首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Gunicorn 的设计与实现

gunicorn源码解析

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

关于gunicorn的设计

Server Model

Gunicorn is based on the pre-fork worker model. This means that there is a central master process that manages a set of worker processes. The master never knows anything about individual clients. All requests and responses are handled completely by worker processes.

的实现是由一个 进程来管理多个 进程,所有的请求都是由 进程处理的。

源码解读

官方网站的例子如下:

阅读源码第一步要先定位到入口,我们知道gunicorn的调用方式

写过python包的同学就知道怎么去定位入口,那就是在 这个文件

也就是说入口在 ,我们直接定位到 这个函数上

可以看得出来其实是实例化 对象之后调用 方法。

gunicorn配置

我们可以先看看实例化 对象会做什么操作由于 和其父类 都没有实现 方法,我们直接看 的父类 的 方法。

实例化过程的调用链看起来应该是这样的: -> -> & 也就是实例化 对象会加载配置 我们再来看看 对象是如何加载配置的

从上面的代码片段我们可以看出来其实实例化 对象的时候会去访问 这个列表的元素,但是从代码上看 是个空列表,这边就有疑问了,什么时候会往 这个列表上添加元素呢?在这个文件全局搜了下 ,发现了一个有趣的技巧

这边的代码片段上使用了python的元类, 是由 这个元类创建出来的类,继承 的子类都会被 这个元类创建。而创建类的时候,会把这些类放在 列表中。所以 这个函数返回了除ignore之外的所有继承 的类的实例。而对 对象实例的操作会被代理到对应的 实例上。

下面回到 方法的实现上, 没有实现 方法,重点还是看基类 的 实现。

这个类在gunicorn是相当重要,可以说 只是用来管理gunicorn的配置,而 是gunicorn中用来管理worker的。

Master 进程

The master process is a simple loop that listens for various process signals and reacts accordingly. It manages the list of running workers by listening for signals like TTIN, TTOU, and CHLD. TTIN and TTOU tell the master to increase or decrease the number of running workers. CHLD indicates that a child process has terminated, in this case the master process automatically restarts the failed worker.

进程用循环来监听信号事件并处理,通过监听信号事件来管理运行中 的数目。

方法是 进程的 所在。

我们来看看 都做了什么事

调用 注册消息事件

创建

注册消息事件

会先关闭已存在的管道对 ,然后创建一个新的管道对,初始化管道并注册信号事件,除了 信号外,其他信号都会被 方法处理,处理方式就是把信号加到信号事件队列,然后唤醒自身,当然前提是信号事件队列没有满的情况。一旦队列满了,就不对信号做任何处理。

创建

函数会通过配置的地址或文件描述符去创建 ,如果配置的地址是元组,则创建一个 ,如果是字符串,则创建一个 。这些 最终将被 消费,每次创建 的时候都会把 当参数传递过去。

再回到 的 方法, 之后调用了 方法。

方法维护了大小为 的worker数,worker进程是在 方法中被创建的

master进程会先实例化 ,默认的 是 。可以在fork子进程之前预处理一些操作,具体可以在 的 类实现。fork之后会产生子进程,而父进程 把实例化的 对象放到 中,这边的 是子进程的进程ID。结下来父进程结束了 ,直接

而fork出来的子进程会继续执行 的逻辑。主要的逻辑就是:

这边会产生疑问, 不是会退出子程序么?即使 异常被捕获但是也没有处理?其实这个 进程正常情况不会退出,原因就是在 中的实现。

可以看得出来子类worker实现的 和 都会在循环中度过。

再次回到 的 方法,现在 方法进入了 过程。

loop过程,每次从消息事件队列取一个消息处理,具体的消息处理会转交给 方法处理,如果没有信号要处理,就进入休眠状态直到被唤醒。这里就是 进程基本的工作。

进程进入休眠之后什么时候会被唤醒,怎么唤醒的?我们来看看 进程休眠和唤醒的过程。

可以看得出来 的 方法会监视之前创建的管道读端 ,一直等待到这一端有数据才结束。 方法会在信号被加到信号事件队列之后调用,往管道写端 写数据。

Worker 进程

这边我们重点来看看 中 的实现:

创建管道

注册消息事件

加载wsgi应用

执行

注册消息事件

注册消息事件的时候,worker进程会通过设置文件描述符( ),当接收到信号的时候,一个'\0'字节被写入到指定的fd上(这里是管道的写端 ),从而来唤醒一个 或 调用,允许信号被处理。

执行

方法由各个子类实现,我们来看看 的 方法

方法中调用 方法

的调用会通过 来阻塞监听 列表, 列表包括socket列表 和worker管道读端 ,如果有可读的文件描述符,会返回这些可读的文件描述符,也就是说, 进程会在有 请求和信号事件( )触发唤醒。

可以看出了, 或者 方法从 列表取一个或多个socket,调用 方法建立连接,调用 方法处理请求。这边的请求处理是阻塞式的,每次只能处理一个请求。

方法会解析请求的内容并调用 方法来创建一个 请求并被 应用处理。最后如果处理的请求总数大于最大请求数,这个 进程就结束。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180619G0M0YX00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券