程序员专享绿色独角兽Gunicorn,了解下
作者:互联网
楔子
承接上文,今天讲讲python后端流量处理过程中第一个步骤:接收数据包。接收数据包一般需要web服务器来处理,常用的python web服务器可以是nginx,httpd, WSGI容器本身也可以做web服务,考虑到扩展,高可用,生产上一般常用nginx+gunicorn(uwsgi),通讯方式一般 unix socket.
今天的重点是WSGI容器 Gunicorn。
知识准备
pre-forking
pre意思是在requests 到来之前,先fork出多个worker子进程;
worker负责处理请求,master负责管理worker的运行周期。
WSGI
全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。
从定义上讲,如下几点:
WSGI是一套接口标准协议/规范;
通信(作用)区间是Web服务器和Python Web应用程序之间;
目的是制定标准,以保证不同Web服务器可以和不同的Python程序之间相互通信,比如nginx+gunicorn+flask,或者nginx+uwsgi+django等等。但凡实现wsgi协议均可替换。
socket
传统意义上是类似于文件描述符的存在形式,是一种抽象的资源定位,即进程端口资源。
1,一个程序启动后,有pid文件标识锁定该运行的程序。
2,一个文件打开后,在进程中有一个fd标识着它。
3,一个进程占用了一个端口,并建立相关协议的通信,由socket标识着它。
所以socket就是一个资源标识,是一个三元组(协议,端口号,IP地址)。
基于socket的编程,指的是在该资源(三元组)的基础上,封装对数据的处理。就好比打开一个文件后,对文件的编程,如函数f.Close()。
socket编程必备的函数如下:
· Socket():创建一个socket。
· Bind():绑定地址,即该socket负责哪个资源。
· Listen():开始监听。
· Accept():接收请求。
· Connect():建立连接
· Recv()/Send():数据发送和接收
客户端->建立socket->Connect()建立连接->Close()。
服务端->建立socket->Bind()->Listen()->Accept()接收请求->Close()。
Gunicorn是什么
Gunicorn Green Unicorn是一个UNIX的Python WSGI HTTP服务器。它是一个从Ruby的Unicorn项目移植过来的预分叉工作器模型。Gunicorn服务器广泛兼容各种web框架,实现简单,服务器资源少。
Gunicorn实现了WSGI协议,所以它可以作为web服务器和程序框架之间的纽带,将http报文转换为WSGI规定的格式。
项目中如何使用
命令行模式
gunicorn -h 有很多参数,读者有兴趣可以细究下,本文主要讲原理实现。
- 文件配置形式
[program:gunicorn_demo] process_name=%(program_name)s numprocs=1 priority=901 directory = /opt/gunicorn_demo/ command = /opt/virtualenv/bin/python /opt/virtualenv/bin/gunicorn -c gunicorn_demo.py gunicorn_demo:app autostart = true startsecs = 20 autorestart = true startretries = 3 user = root redirect_stderr = true stdout_logfile_maxbytes = 20MB stdout_logfile_backups = 10 stdout_logfile = /dev/null
工作原理
如下图:
gunicorn运行逻辑图,从图中我们可以看到,gunicorn主要做了如下几件事情:
启动框架程序;
接收数据包并转换wsgi格式,传递给框架;
提供并发模型,管理进程.
gunicorn代码调用,最重要的逻辑在Arbiter类中,arbitor在计算机专业术语中叫 总线控制器,顾名思义,这个类很重要,gunicorn主要功能都围绕它展开。
gunicorn提供的并发模型(文件路径gunicorn/workers)
同步模型Sync Workers(sync.py)
如下图是 同步worker的流程图,accept时,设置为阻塞模式。
并发模型如下:
同步worker一个进程里一个线程,线程按照顺序处理请求,后面的请求需要等待。
同步worker适合在访问量不大、CPU密集而非I/O密集的情形。
好处是一个worker进程crash了,也只会影响一个请求。
异步模型Async Workers(异步workers)
(ggevent.py,geventlet.py)
异步并发模型如下,异步worker也只有一个线程,但能同时处理不同请求,不会阻塞后面的请求
异步worker是怎样实现并发,使得一个worker就能同时处理很多请求的呢?
以Gevent为例,每个请求的连接是一个Greenlet协程。Gevent虽然只有一个线程、同时只能处理一个请求,但是在这个请求的异步事件没准备好、进入IO等待时,能主动yield让出控制权、而不是阻塞其他请求的协程,而是先让其他协程执行,当自己的IO准备好时,事件循环会将它从yield让出控制权的地方,继续恢复执行。
这样,Gevent就能在不同请求间不断切换,从而实现并发,以充分利用CPU、减少IO等待。并且,因为切换的Greenlet是“微线程”,它操作的维度是函数,而不是线程/进程,所以来回切换的开销,就没有那么大。一般来说,我们的web app多半属于外部IO密集型(总要访问db、访问第三方服务等等),所以用Gunicorn的Gevent异步worker(比如Gevent),就非常合理。而如果你的web app是CPU密集型,或者你希望请求之间不要互相影响,那么可以选择Gunicorn的同步worker。
这里有三个概念:greenlet,eventlet,gevent。
greenlet是Python的协程实现,可以理解为微线程。
Gevent是一个Python网络函数库,它通过Greenlet协程+libev快速事件循环,实现了异步模型。gevent的猴子补丁读者有兴趣可以了解下。
Tornado Workers
用来配合Tornado使用。Tornado是一个Python框架和网络库,可以提供异步IO非阻塞型模型,来处理长延时请求。
Tornado也是一个很有名框架,笔者也计划写Tornado源码系列文章。
多线程Workers
一个请求由一个线程处理,使用线程池技术。这里不展开,后续有线程池和进程池系列文章。
标签:web,Gunicorn,worker,专享,socket,线程,请求,独角兽,gunicorn 来源: https://blog.51cto.com/13176208/2677775