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] = workerreturn pid# Process Childworker_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 poolif 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._spawnspawn(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:breakif result is True:continueself.status, response_body = resultself.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工作原理相关推荐

  1. 2021年大数据ELK(十八):Beats 简单介绍和FileBeat工作原理

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Beats 简单介绍和FileBeat工作原理 一.Beats 二.FileB ...

  2. 深入理解Nginx工作原理

    1 反向代理 1.1 概念 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给intern ...

  3. 高频开关电源原理_程控开关电源的工作原理

    本文介绍了开关电源的工作原理以及它的特点. 程控开关电源要要比线性电源复杂得多. 下图是典型的开关电源工作原理图. 首先对 220 V/50Hz 的 AC 输入,通过桥式整流器进行整流 储能电容对整流 ...

  4. Servlet生命周期与工作原理

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...

  5. java的工作原理你知道吗_每天用Mybatis,但是Mybatis的工作原理你真的知道吗?

    近来想写一个mybatis的分页插件,但是在写插件之前肯定要了解一下mybatis具体的工作原理吧,于是边参考别人的博客,边看源码就开干了. 核心部件:SqlSession Executor Stat ...

  6. linux网络管理原理,Linux__网络管理(物理层 数据链路层 网络层工作原理)

    千锋云计算逆战班11点后打卡 今天学习后,进行复习下,物理层 数据链路层  网络层 的工作原理 物理层关心的两件事情:1.信号 2.介质 先说信号:信号分为模拟信号和数字信号 模拟信号: 模拟信号,不 ...

  7. HDD工作原理 导图

    以上导图介绍了我们使用的 (HDD)机械硬盘的基本构造以及核心工作原理,对于大家扫盲有所帮助 参考文档: https://blog.csdn.net/yizhaoxin/article/details ...

  8. 路由和交换机工作原理

    路由器与交换机的工作原理 计算机网络往往由许多种不同类型的网络互连连接而成.如果几个计算机网络只是在物理上连接在一起,它们之间并不能进行通信,那么这种"互连"并没有什么实际意义.因 ...

  9. Google工作原理

    今天在晚上看到一个图,讲解google的工作原理,感觉写的不错.贴过来方便以后深入的研究. 转载于:https://www.cnblogs.com/muyuge/archive/2010/07/06/ ...

最新文章

  1. 2017年50道Java线程面试题
  2. Java过滤器与SpringMVC拦截器之间的关系与区别
  3. 在WebView中如何让JS与Java安全地互相调用
  4. 使用graphite和grafana进行应用程序监控
  5. python 堆栈溢出_内存 - 如何发生“堆栈溢出”,如何防止它?
  6. 小米净水器更换php教程,这种方法更换滤芯寿命更长:小米净水器
  7. 【转】通过CountDownLatch提升请求处理速度
  8. 进程/线程同步的方式和机制,进程间通信
  9. 我是如何将博客转成PDF的
  10. phoenix hbase java_spark通过phoenix读写hbase(Java版)
  11. 跳转页面 bscroll 无法无法从顶部滚动
  12. MeasureSpec介绍
  13. PHP接收云之家审批结果,首页云之家开放平台文档
  14. 东芝u盘写保护无法格式化解决方案
  15. LODOP打印分页出现空白页
  16. 【技术贴】Realtek HD声卡下QQ语音话筒没声音解决办法
  17. 51单片机学习笔记【五】——1602液晶屏
  18. Vue.js实战——内置指令(一)
  19. 让每块火腿都留下“数字痕迹”西媒:区块链将用于保护食品安全
  20. 再现“换桥奇迹”|人大金仓助力大型运营商完成营销系统国产化升级

热门文章

  1. 为Repository添加自定义方法
  2. rewrite break
  3. linux usleep函数,linux下,测试usleep函数对CPU占用率的影响
  4. Python中利用moviepy对视频进行剪辑以及拼接
  5. 大毕业什么都没学到 就是收藏了超级实用的130个网站!!!
  6. 基于python下django框架 实现外卖点餐系统详细设计
  7. 40、查询选修“张三”老师所授课程的学生中成绩最高的学生姓名及其成绩(重要top)
  8. ENVI: 如何添加控制点并基于控制点进行几何校正?
  9. NGUI 制作字体集和图集
  10. JAVA与C、C++比较