gunicorn

gunicorn

在了解 gunicorn 之前, 我们先来看一下 WSGI 的定义

WSGI 的定义如下

Web服务器网关接口Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器Web应用程序框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。

并且

gunicorn 的定义如下

Gunicorn "Green Unicorn" (pronounced jee-unicorn or gun-i-corn)[2] 是一个 Python Web Server Gateway Interface (WSGI) HTTP 服务. 它是一个预先 fork 出工作 worker 的模型, 从 Ruby's Unicorn 项目移植过来. Gunicorn 服务适配许多 web 框架, 实现简单, 资源占用小并且运行速度快

当你启动一个 gunicorn 程序时, 主进程会调用 listen 方法对指定的地址和端口进行绑定, 并获取到文件描述符

在这之后 fork 出 N 个进程(N 就是配置文件里的 worker 整数值), 在 fork 之前把对应的文件描述符传递给了每个子进程(worker)

每个 worker 会创建一个临时文件 (文件名称类似 /var/folders/62/nzw4jhq14yzbd5722996v7s00000gn/T/wgunicorn-3ygziaw_), 并且持续地调用 fchmod() 更新这个文件, 主进程可以通过持续的检查这个临时文件的更新时间来知晓对应的 worker 是否还存活着(通过 fstat().st_ctime 获取更新时间)

worker(子进程) 可以通过持续的检查传入的主进程id和 os.getppid() (self.ppid != os.getppid()) 的值, 来判断主进程是否还存活着

主进程绑定了服务地址后, 初始化worker(创建并获取临时文件描述符, 传入当前的进程id作为子进程的ppid, 传入当前绑定了地址的文件描述符等操作), 之后进行 fork 系统调用, 在 fork之后, 操作系统会保证主进程创建的文件描述符在子进程中依旧可以使用, 这样主进程就可以通过上述机制对子进程进行管理

每个 worker 会调用自身 run 方法并进入一个无限循环中

e

默认的 worker 是 SyncWorker, 在每一次循环中, SyncWorker 会调用 accept 方法获取一个客户端发送过来的请求, 并且处理对应的请求

# gunicorn/workers/sync.py
while self.alive:
    # 持续地对临时文件进行更新
    self.notify()

    # 获取一个客户端连接, 如果这里抛出了异常表明当前没有等待进行连接的请求
    # 则进入下面的 select 中, select 会阻塞直到有能建立连接的请求进来为止再进行返回
    try:
        # 获取一个连接并处理
        self.accept(listener)
        # 持续的处理客户端请求, 直到没有等待建立连接的客户端请求为止
        # 这样可以防止针对每个客户端请求都进行一次 select() 调用
        continue

    except EnvironmentError as e:
        if e.errno not in (errno.EAGAIN, errno.ECONNABORTED,
                           errno.EWOULDBLOCK):
            raise

    if not self.is_parent_alive():
        return
        
    try:
        # 调用 select.select
        self.wait(timeout)
    except StopWaiting:
        return

workers

并且 SyncWorker accept 方法会调用 self.wsgi(environ, resp.start_response) , 这个方法会最终调用到WSGIHandler.__call__(self, environ, start_response)(文件位置 django/core/handlers/wsgi.py )

到这里就是 django 的部分了, django 会处理对应的请求, 并把返回内容传递给 SyncWorker 实例, 这里每个worker只有一个线程在处理请求

SyncWorkeraccept 方法定义如下

# gunicorn/workers/sync.py
def accept(self, listener):
    client, addr = listener.accept()
    client.setblocking(1)
    util.close_on_exec(client)
    # 这里会最后调用到 WSGIHandler.__call__(self, environ, start_response)
    self.handle(listener, client, addr)

我们来看一个示例, 当你输入如下命令时

gunicorn --workers 2 mysite.wsgi

主进程调用 listen 方法绑定了默认的地址和端口 127.0.0.1:8000 , 之后通过系统调用 fork 生成两个 worker(子进程)

每一个 worker 都会加载 mysite/wsgi.py 并寻找名为 application 的实例, django 默认创建好的实例是从这个位置进行导入生成的 from django.core.wsgi import get_wsgi_application, 它实现了 WSGI 接口, 所以 gunicorn 可以对它进行加载并调用对应的方法处理每一个请求

django_example

posted @ 2022-11-10 12:37  G先生  阅读(179)  评论(0编辑  收藏  举报

:guocheng