Gunicorn 采用 arbiter/manager + worker 管理进程。
arbiter 作为管理者,不断循环,在每轮循环检测 worker 状态,比如杀死超时 worker ,创建新 worker 。
而 worker 负责处理请求,多个 worker 监听在同一个 socket 上接受新请求。worker 模式多样,最简单的就是进程模式和线程模式。
max request 被设计用来限制一个 worker 所能处理的做法请求数量。其初衷是担心代码中内存泄漏,worker 运行一段时间后能被杀死,回收掉内存。
worker 里边也是循环处理新请求。在每次处理请求前,worker touch 一个 WorkerTmp 对象(好像是一个文件来着),更新其时间戳。而 arbiter 每轮循环检测到 worker.tmp ,就明白 worker 空闲有一定时间了,会干掉它。
Arbiter.run() 是循环代码,Arbiter.murder_worker() 尝试清理 worker 。
Arbiter 管理 worker 方式基于信号。Arbiter 和 Worker 实例化时都会初始化自己的信号管理函数。总之 arbiter 发送 abrt 或者 kill 信号给 worker ,空转 worker 接受到信号后自杀。( worker 空转是因为其达到最大请求数后不再处理新请求)根据 base worker 中 abrt 信号处理函数,worker 执行了 sys.exit(1) 直接退出。
max requests jitter 是在最大请求数目上加点抖动值,避免所有 worker 同一时间停止接受新请求,服务摊了。不过我觉得请求耗时不大可能完全一样,加不加差不大多。
Gunicorn vs Uvicorn vs Supervisor
Gunicorn 很独特的一点是,它既是一个 wsgi 服务器(对标 Uvicorn ),也是一个进程管理器(对标 supervisor )。所以你看到过 Gunicorn+ Uvicorn 部署 asgi 应用,Uvicorn 作为一个 gunicorn 运行。和 supervisor 相比,Gunicorn 进程管理方式相对较弱,完全基于信号,好像 supervisor 基于 RPC 调用啥的,交互式 shell 管理进程、web page 管理进程一应俱全。
主要相关代码参考
arbiter.py 和 workers/
base.py 。