gunicorn
https://blog.csdn.net/jailman/article/details/78496522
gunicorn工作原理
Gunicorn“绿色独角兽”是一个被广泛使用的高性能的Python WSGI UNIX HTTP服务器,移植自Ruby的独角兽(Unicorn )项目,使用pre-fork worker模式,具有使用非常简单,轻量级的资源消耗,以及高性能等特点。
Gunicorn 服务器作为wsgi app的容器,能够与各种Web框架兼容(flask,django等),得益于gevent等技术,使用Gunicorn能够在基本不改变wsgi app代码的前提下,大幅度提高wsgi app的性能。
总体结构
gunicorn pre-fork worker模型中有一个管理进程以及几个的工作进程。管理进程:master,工作进程:worker。(以下代码中为了方面理解,均去除了一些干扰代码)
master通过pre-fork的方式创建多个worker:
def spawn_worker(self):
self.worker_age += 1
#创建worker。请注意这里的app 对象并不是真正的wsgi app对象,而是gunicorn的app
#对象。gunicorn的app对象负责import我们自己写的wsgi app对象。
worker = self.worker_class(self.worker_age, self.pid, self.LISTENERS,
self.app, self.timeout / 2.0,
self.cfg, self.log)
pid = os.fork()
if pid != 0: #父进程,返回后继续创建其他worker,没worker后进入到自己的消息循环
self.WORKERS[pid] = worker
return pid # Process Child
worker_pid = os.getpid()
try:
..........
worker.init_process() #子进程,初始化woker,进入worker的消息循环,
sys.exit(0)
except SystemExit:
raise
............
在worker.init_process()函数中,worker中gunicorn的app对象会去import 我们的wsgi app。也就是说,每个woker子进程都会单独去实例化我们的wsgi app对象。每个worker中的swgi app对象是相互独立、互不干扰的。
manager维护数量固定的worker:
def manage_workers(self):
if len(self.WORKERS.keys()) < self.num_workers:
self.spawn_workers()
while len(workers) > self.num_workers:
(pid, _) = workers.pop(0)
self.kill_worker(pid, signal.SIGQUIT)
创建完所有的worker后,worker和master各自进入自己的消息循环。
master的事件循环就是收收信号,管理管理worker进程,而worker进程的事件循环就是监听网络事件并处理(如新建连接,断开连接,处理请求发送响应等等),所以真正的连接最终是连到了worker进程上的。(注:有关这种多进程模型的详细介绍,可以参考http://blog.csdn.net/largetalk/article/details/7939080)
worker
woker有很多种,包括:ggevent、geventlet、gtornado等等。这里主要分析ggevent。
每个ggevent
worker启动的时候会启动多个server对象:worker首先为每个listener创建一个server对象(注:为什么是一组listener,因为gunicorn可以绑定一组地址,每个地址对于一个listener),每个server对象都有运行在一个单独的gevent
pool对象中。真正等待链接和处理链接的操作是在server对象中进行的。
#为每个listener创建server对象。
for s in self.sockets:
pool = Pool(self.worker_connections) #创建gevent pool
if self.server_class is not None:
#创建server对象
server = self.server_class(
s, application=self.wsgi, spawn=pool, log=self.log,
handler_class=self.wsgi_handler, **ssl_args)
.............
server.start() #启动server,开始等待链接,服务链接
servers.append(server)
.........
上面代码中的server_class实际上是一个gevent的WSGI SERVER的子类:
class PyWSGIServer(pywsgi.WSGIServer):
base_env = BASE_WSGI_ENV
需要注意的是构造PyWSGIServer的参数:
self.server_class(
s, application=self.wsgi, spawn=pool, log=self.log,
handler_class=self.wsgi_handler, **ssl_args)
这些参数中s是server用来监听链接的套接字。spawn是gevent的协程池。application即是我们的wsgi app(通俗点讲就是你用 flask 或者 django写成的app),我们的app就是通过这种方式交给gunicorn的woker去跑的。 handler_class是gevent的pywsgi.WSGIHandler子类。
当所有server对象创建完毕后,worker需要定时通知manager,否则会被认为是挂掉了。
while self.alive:
self.notify()
.......
这个地方的notify机制设计的比较有趣,每个worker有个与之对应的tmp file,每次notify的时候去操作一下这个tmp file(比如通过os.fchmod),这个tmp file的last update的时间戳就会更新。而manager则通过检查每个worker对应的temp file的last update的时间戳,来判断这个进程是否是挂掉的。
WSGI SERVER
真正等待链接和处理链接的操作是在gevent的WSGIServer 和 WSGIHandler中进行的。
最后再来看一下gevent的WSGIServer 和 WSGIHandler的主要实现:
WSGIServer 的start函数里面调用start_accepting来处理到来的链接。在start_accepting里面得到接收到的套接字后调用do_handle来处理套接字:
def do_handle(self, *args):
spawn = self._spawn
spawn(self._handle, *args)
可以看出,WSGIServer 实际上是创建一个协程去处理该套接字,也就是说在WSGIServer 中,一个协程单独负责一个HTTP链接。协程中运行的self._handle函数实际上是调用了WSGIHandler的handle函数来不断处理http 请求:
def handle(self):
try:
while self.socket is not None:
result = self.handle_one_request()#处理HTTP请求
if result is None:
break
if result is True:
continue
self.status, response_body = result
self.socket.sendall(response_body)#发送回应报文
..............
在handle函数的循环内部,handle_one_request函数首先读取HTTP 请求,初始化WSGI环境,然后最终调用run_application函数来处理请求:
def run_application(self):
self.result = self.application(self.environ, self.start_response)
self.process_result()
在这个地方才真正的调用了我们的 app。
总结:gunicorn 会启动一组 worker进程,所有worker进程公用一组listener,在每个worker中为每个listener建立一个wsgi server。每当有HTTP链接到来时,wsgi server创建一个协程来处理该链接,协程处理该链接的时候,先初始化WSGI环境,然后调用用户提供的app对象去处理HTTP请求。
gunicorn的更多相关文章
- python Gunicorn
1. 简介 Gunicorn(Green Unicorn)是给Unix用的WSGI HTTP 服务器,它与不同的web框架是非常兼容的.易安装.轻.速度快. 2. 示例代码1 def app(envi ...
- Debian7下lnmp+gunicorn部署Django运行环境
首先安装lnmp,安装方法见lnmp.org wget -c http://soft.vpser.net/lnmp/lnmp1.3-full.tar.gz && tar zxf lnm ...
- apache(nginx)+django+virutalenv(virtualenvwrapper)+gunicorn+supervisor配置高效web环境
前言 django的调试模式配置简单,用于测试十分方便,但众所周知,这个只适合于调试,生产上运行效率十分低下. 后来考虑用nginx+uwsgi的模式进行,但之前配置过apache+wsgi的方式,感 ...
- Gunicorn 和 Nginx
Web Application Deployment Using Nginx Nginx is a very high performant web server / (reverse)-proxy. ...
- Gunicorn 问题
Does Gunicorn suffer from the thundering herd problem? The thundering herd problem occurs when many ...
- Gunicorn 文档翻译
服务器模式 Gunicorn 基于 pre-fork 模式,这意味着有一个主进程管理工作的子进程.主进程对客户端的工作业务有了解.所有的请求和响应都是工作子进程处理. 主进程 主进程是一个简单的循环, ...
- nginx+gunicorn+supervisor+flask @ centos
/etc/nginx/conf.d/default.conf server { listen 80 default_server; server_name 127.0.0.1; #charset ko ...
- Gunicorn + Django 部署
1. 下载gunicorn pip install gunicorn 2. 运行 gunicorn AutoSa.wsgi:application ## AutoSa为我project的名字,后面的不 ...
- Flask + Gunicorn + Nginx 部署
最近很多朋友都在问我关于 Flask 部署的问题,说实在的我很乐意看到和回答这样的问题,至少证明了越来越多人开始用 Flask 了. 之前我曾发表过一篇在 Ubuntu 上用 uwsgi + ngin ...
- virtualenv 环境下 Nginx + Flask + Gunicorn+ Supervisor 搭建 Python Web
在这篇文章里,我们将搭建一个简单的 Web 应用,在虚拟环境中基于 Flask 框架,用 Gunicorn 做 wsgi 容器,用 Supervisor 管理进程,然后使用 Python 探针来监测应 ...
随机推荐
- atitit。全局变量的设计与实现 java php的异同
atitit.全局变量的设计与实现 java php的异同 1. 超级全局(Superglobals)"变量 1 2. 全局变量和"global"关键字 1 3. 更加好 ...
- [svc][bg]phabricator-zh_CN汉化包
汉化phabricator审计系统 主要是用来审计一些开发bug的,客服会提交一些bug,测试也会提交一些bug给开发. https://github.com/wanthings/phabricato ...
- 新型I/O架构引领存储之变(二)
新型I/O架构引领存储之变(二) 作者:廖恒 众所周知,支持存储及网络I/O服务的接口协议有很多种.比方,以太网及Infiniband接口都支持採用iSCSI协议来实现存储业务,它们也因而成为了ser ...
- [python小记]使用lxml修改xml文件,并遍历目录
这次的目的是遍历目录,把目标文件及相应的目录信息更新到xml文件中.在经过痛苦的摸索之后,从python自带的ElementTree投奔向了lxml.而弃用自带的ElementTree的原因就是,na ...
- IE的layout布局
我们那知道浏览器有bug,而且Windows上的lE的bug 似乎比太多数浏览器都多.IE/Win的表现与其他浏览器不同的原因之一是,显示引擎使用一个称为布局(layout)的内部概念.因为布均是一个 ...
- jquery几个按钮同时调用一个方法
- 怎么来爬取代理服务器ip地址?
一年前突然有个灵感,想搞个强大的网盘搜索引擎,但由于大学本科学习软件工程偏嵌入式方向,web方面的能力有点弱,不会jsp,不懂html,好久没有玩过sql,但就是趁着年轻人的这股不妥协的劲儿,硬是把以 ...
- 虚拟机Ubuntu系统下kaldi安装与编译简介
kaldi官网:http://www.kaldi-asr.org/doc/index.html 在http://github.com/kaldi-asr/kaldi中直接下载kaldi的zip包,没有 ...
- greenplum全量恢复gprecoverseg -F出现Unable to connect to database时的相关分析及解决方法
之前有两位朋友碰到过在对greenplum的系统构架更改后,出现全量恢复gprecoverseg -F也无法正常执行的情况. 报错信息为Unable to connect to database. R ...
- html5 webwork
在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出“脚本运行时间过长“的提示框,如果出现这种情况说明你的脚本已经失控了. 一个浏览器至少存在三个线程:js引擎线程(处理js).GUI渲 ...