gunicorn 支持如下4种工作模式,Gunicorn“绿色独角兽”

参考:
Gunicorn各种模式的简介:https://www.jianshu.com/p/4c4e1bf22c48
gunicorn 几种 worker class 性能测试比较:http://t.zoukankan.com/morgana-p-10881479.html

WSGI协议

关键词在WSGI(Web Server Gateway Interface)。它不是web server,也不是web app;而正是为了将web和app解耦、再连接起来,这样的一道桥梁。因为它是一种通用接口规范,规定了web server(如Apache、Nginx)和web app(或web app框架)之间的标准。

有了它,web app开发者就能专注于业务逻辑、专注于HTML文档的生成,而不用操心繁琐的网络底层实现(HTTP请求接收、建立连接、返回响应等),并能方便地组合搭配不同的web server + web app/框架了。

在这里插入图片描述

Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求。Web框架和Web服务器之间的通信,需要一套双方都遵守的接口协议。WSGI协议就是用来统一这两者的接口的。

WSGI容器——Gunicorn
常用的WSGI容器有Gunicorn和uWSGI,但Gunicorn直接用命令启动,不需要编写配置文件,相对uWSGI要容易很多,所以这里我也选择用Gunicorn作为容器。

gunicorn是目前使用最广泛的高性能的Python WSGI(WEB Server Gateway interface)服务器,移植自Ruby的Unicorn项目,使用pre-fork worker模式,具有简单、易用、轻量级、低资源消耗和高性能等特点。

什么是pre-fork worker model?

“worker model”意味着:这个模型有一个master进程,来管理一组worker进程;“fork”意味着:worker进程是由master进程fork(复刻)出来的;“pre-”意味着:在任何客户端请求到来之前,就已从master进程fork出了多个worker进程,坐等请求到来。

在worker进程创建时,就被实例化了Python web app;并由worker进程监听端口、处理请求。那么,当请求到来时,worker进程就能解析HTTP请求、调用Python web app处理、得到处理结果后,再整理成HTTP Response,通过TCP返回给客户端。

而master进程是不管处理请求的,只负责管理worker进程,比如对worker进程的创建、销毁、以及根据负载情况增减。(启动时设置的–workers参数只是worker数,而Gunicorn还会创建个master进程。所以,即使配置workers为1,你的app也至少有俩进程:master负责管理,worker负责处理请求。)

当然了,Gunicorn是WSGI的实现,但同时也自带web server,能直接对外提供web服务。包括大部分的web app框架比如Flask和Django也都带有web server。不过,在真正的生产环境的部署中,它们还是各司其职,Flask/Django只用于写app、Gunicorn只用于运行和管理Python web app,而在它们前面有专门的web server,比如Nginx。
在这里插入图片描述

通信逻辑

在这里插入图片描述

(nginx收到客户端发来的请求,根据nginx中配置的路由,将其转发给WSGI) nginx:”WSGI,找你的来了!” (WSGI服务器根据WSGI协议解析请求,配置好环境变量,调用start_response方法呼叫flask框架) WSGI服务器:”flask,快来接客,客户资料我都给你准备好了!” (flask根据env环境变量,请求参数和路径找到对应处理函数,生成html) flask:”!@# %^……WSGI,html文档弄好了,拿去吧。” (WSGI拿到html,再组装根据env变量组装成一个http响应,发送给nginx) WSGI服务器:”nginx,刚才谁找我来着?回他个话,!@# %^……” (nginx再将响应发送给客户端)

gunicorn 支持如下4种工作模式

Sync Workers
Async Workers
Tornado Workers
AsyncIO workers
工作模式是通过worker_class参数配置的。可以是如下任一值:

sync
gevent
eventlet
tornado
gaiohttp
gthread
缺省值: sync

Sync Worders (sync)

最简单的同步工作模式
在这里插入图片描述

Async Worders (gevent, eventlet)

gevent和eventlet都是基于Greenlet库,利用python协程实现的
在这里插入图片描述

Tornado Worders (tornado)

利用python Tornado框架实现
在这里插入图片描述

AsyncIO Workers (gthread, gaiohttp)

gaiohttp利用aiohttp库实现异步I/O,支持web socket

gthread采用的是线程工作模式,利用线程池管理连接

在这里插入图片描述

通过调整Gunicorn设置,我们希望优化应用程序性能。

1、如果这个应用是 I/O 受限,通常可以通过使用“伪线程”(gevent 或 asyncio)来得到最佳性能。正如我们了解到的,Gunicorn 通过设置合适的 worker 类 并将 workers数量调整到 (2*CPU)+1 来支持这种编程范式。

2、如果这个应用是 CPU 受限,那么应用程序处理多少并发请求就并不重要。唯一重要的是并行请求的数量。因为 Python’s GIL,线程和“伪线程”并不能以并行模式执行。实现并行性的唯一方法是增加workers 的数量到建议的 (2*CPU)+1,理解到最大的并行请求数量其实就是核心数。

3、如果不确定应用程序的内存占用,使用 多线程 以及相应的 gthread worker 类 会产生更好的性能,因为应用程序会在每个 worker 上都加载一次,并且在同一个 worker 上运行的每个线程都会共享一些内存,但这需要一些额外的 CPU 消耗。

4、如果你不知道你自己应该选择什么就从最简单的配置开始,就只是 workers 数量设置为 (2*CPU)+1 并且不用考虑 多线程。从这个点开始,就是所有测试和错误的基准环境。如果瓶颈在内存上,就开始引入多线程。如果瓶颈在 I/O 上,就考虑使用不同的 Python 编程范式。如果瓶颈在 CPU 上,就考虑添加更多内核并且调整 workers 数量。

工作模式的补充说明

当worker指定为gevent或者evenlet类型时,线程变成基于Greentlet的task(伪线程),这时候线程数量threads参数是无效的。

使用gevent模式会出现一些兼容性问题。
使用gevent时,系统会使用monkey patch。系统的部分函数会被修改, 有些库会兼容gevent的类型, 例如,任务调度的库apscheduler,web socket需要socketio的库等,需要专门选择gevent的函数。 而有些库则直接无法使用,例如多进程multiprocess。 例如,在一个api请求中,如果需要使用多核cpu资源,采用multiprocess进行多进程计算。则会出现卡死的问题。gevent中,不能使用multiprocess库。

并发计算

多线程

gunicorn --workers=5 --threads=2 --worker-class=gthread main:app
复制代码

在我们的例子里面最大的并发请求数就是 worker * 线程,也就是10。

协程

gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 main:app
复制代码

(2*CPU)+1 仍然是建议的workers 数量。因为我们仅有一核,我们将会使用 3 个worker。

在这种情况下,最大的并发请求数量是 3000。(3 个 worker * 1000 个连接/worker)

猜你喜欢

转载自blog.csdn.net/qq_15821487/article/details/126518215