gunicorn syncworker 源码解析

来源:互联网 发布:邮箱数据购买 编辑:程序博客网 时间:2024/04/30 05:59
  gunicorn支持不同的worker类型,同步或者异步,异步的话包括基于gevent、基于eventlet、基于Aiohttp(python版本需要大于3.3),也有多线程的版本。下面是gunicorn当前版本(19.6.0)支持的Worker类型:
  • sync
  • eventlet - Requires eventlet >= 0.9.7
  • gevent - Requires gevent >= 0.13
  • tornado - Requires tornado >= 0.2
  • gthread - Python 2 requires the futures package to be installed
  • gaiohttp - Requires Python 3.4 and aiohttp >= 0.21.5
本文主要对同步模型进行分析。同步模型实现(gunicorn.workers.sync.SyncWorker)继承自gunicorn.workers.base.Worker,绝大多数方法都是定义在基类,包括
init_signal
    注册信号处理函数
handle_xxx:
    各个信号具体的处理函数
notify:
    通知父进程自己还活着
run:
    需要子类实现的接口,用于处理具体的请求。
init_process:
    提供给Arbiter的接口,调用inti_signal和run方法
SyncWorker实现了run方法,对HTTP请求进程处理
def run(self):           if len(self.sockets) > 1:            self.run_for_multiple(timeout) # 使用select       else:            self.run_for_one(timeout)        # 如果只有一个监听socket,那么阻塞accept就行了
  run方法根据监听的端口数量进行区分,如果只在一个端口监听,那么调用accept; 如果是多个端口,那么用select轮训再accept。不管哪种方式,新的连接请求到达后 都调用handle_request函数处理,源代码如下:
  
复制代码
    def handle_request(self, listener, req, client, addr):        environ = {}        resp = None        try:            self.cfg.pre_request(self, req)            request_start = datetime.now()            resp, environ = wsgi.create(req, client, addr,                    listener.getsockname(), self.cfg)            # Force the connection closed until someone shows            # a buffering proxy that supports Keep-Alive to            # the backend.            resp.force_close()            self.nr += 1            if self.nr >= self.max_requests:                self.log.info("Autorestarting worker after current request.")                self.alive = False            respiter = self.wsgi(environ, resp.start_response)            try:                if isinstance(respiter, environ['wsgi.file_wrapper']):                    resp.write_file(respiter)                else:                    for item in respiter:                        resp.write(item)                resp.close()                request_time = datetime.now() - request_start                self.log.access(resp, req, environ, request_time)
复制代码

  其中,调用到App的是下面这行代码

   respiter = self.wsgi(environ, resp.start_response)
  前面提到worker通过notify来向master进程做心跳,具体的代码在WorkerTmp.py。原理很简单:
    (1)首先通过tempfile.mkstemp创建一个临时文件
    (2)worker进程在每次轮训的时候修改该临时文件的属性
    
复制代码
    def notify(self):        try:            self.spinner = (self.spinner + 1) % 2            os.fchmod(self._tmp.fileno(), self.spinner)        except AttributeError:            # python < 2.6            self._tmp.truncate(0)            os.write(self._tmp.fileno(), b"X")
复制代码

 

    (3)master进程检查临时文件最新一次修改时间是否超过阈值
    
    def last_update(self):        return os.fstat(self._tmp.fileno()).st_ctime

 

references:
http://docs.gunicorn.org/en/stable/
http://docs.gunicorn.org/en/stable/signals.html
https://github.com/benoitc/gunicorn
0 0