美文网首页
Gunicorn 0.2 源码阅读

Gunicorn 0.2 源码阅读

作者: 霡霂976447044 | 来源:发表于2021-11-16 08:46 被阅读0次

    安装相关包

    Flask==0.1
    gunicorn==0.2
    Jinja2==2.11.3
    MarkupSafe==1.1.1
    Werkzeug==0.6.1
    

    测试代码

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route("/")
    def hello():
        return "Hello World!"
    
    
    if __name__ == "__main__":
        app.run()
    

    注:以下所说子进程一般代指worker工作进程

    gunicorn采用了pre-fork模式的设计, 主进程+多个子进程,主进程负责管理子进程,子进程负责HTTP请求的处理. 子进程的处理HTTP对父进程是不可见的.

    在程序运行, 主进程会一直循环运行, 在循环之前就已经创建好了子进程, 循环期间检测外部信号和检查子进程健康情况, 从而作出对应处理. 主进程会监听信号,例如, 当收到终止信号, 会将一个个子进程杀死. 杀死子进程分为优雅停止和直接杀死. 优雅停止子进程能够让当前请求处理完再结束, 新的在等待(sock.accept)的请求将不会开始.

    子进程会不断从监听的sock连接中,获取client客户端, 当得到一个client, 就会一直读取http数据流数据,直到一个完整的http request报文数据获取到,就会构造出wsgi协议需要的数据, 调用wsgi application(Flask等), 然后就得到了http response, 再通过client sock将response数据send出去.
    gunicorn中的同步worker是只能每个请求过来,处理完成就关闭(关闭的是client而不是listen),所以不管http keep-alive是否是1.1, 都无法生效(使用异步worker支持).

    子进程是否共用一个tcp监听连接?

    是的(子进程从主进程复制了一份), 主进程创建了TCP连接, 并且在子进程创建的时候传递给了子进程

    worker = Worker(i, self.pid, self.LISTENER, self.modname,
                            self.timeout)
    

    杀死主进程的流程

    通常主进程会阻塞在sleep中, gunicorn通过管道实现了休眠等待信号的逻辑, 当按下ctrl+c
    会走到except select.error, e:的逻辑, EINTR: 终止信号影响了select.select

        def sleep(self):
            try:
                ready = select.select([self.PIPE[0]], [], [], 100.0)
                if not ready[0]:
                    return
                while os.read(self.PIPE[0], 1):
                    pass
            except select.error, e:
                if e[0] not in [errno.EAGAIN, errno.EINTR]:
                    raise
            except OSError, e:
                if e.errno not in [errno.EAGAIN, errno.EINTR]:
                    raise
            except KeyboardInterrupt:
                print 3
                sys.exit()
    

    当跳出sleep, 就会执行对应信号的处理逻辑, 如果是停止服务, 就会去遍历当前所有子进程, 通过子进程的id去kill掉

        def kill_workers(self, sig):
            for pid in self.WORKERS.keys():
                self.kill_worker(pid, sig)
            
        def kill_worker(self, pid, sig):
            worker = self.WORKERS.pop(pid)
            try:
                os.kill(pid, sig)
                kpid, stat = os.waitpid(pid, os.WNOHANG)
                if kpid:
                    self.log.warning("Problem killing process: %s" % pid)
            except OSError, e:
                if e.errno == errno.ESRCH:
                    try:
                        worker.tmp.close()
                    except:
                        pass
    
    

    主进程如何检查子进程的健康情况

    子进程通过不断一个修改一个自己的临时文件的inode信息, 主进程在循环中不断检查这个inode信息的stat.st_ctime(i节点最后更改时间)来判断子进程是否正常.

    解析HTTP报文是gunicorn做还是Flask做?

    HTTP报文详细的由Flask解析, 通过wsgi的wsgi_input流数据解析. gunicorn解析了一些基础信息

    environ = {
                "wsgi.url_scheme": 'http',
                "wsgi.input": wsgi_input,
                "wsgi.errors": sys.stderr,
                "wsgi.version": (1, 0),
                "wsgi.multithread": False,
                "wsgi.multiprocess": True,
                "wsgi.run_once": False,
                "SCRIPT_NAME": "",
                "SERVER_SOFTWARE": self.SERVER_VERSION,
                "REQUEST_METHOD": self.parser.method,
                "PATH_INFO": unquote(self.parser.path),
                "QUERY_STRING": self.parser.query_string,
                "RAW_URI": self.parser.raw_path,
                "CONTENT_TYPE": self.parser.headers_dict.get('Content-Type', ''),
                "CONTENT_LENGTH": str(wsgi_input.len),
                "REMOTE_ADDR": self.client_address[0],
                "REMOTE_PORT": self.client_address[1],
                "SERVER_NAME": self.server_address[0],
                "SERVER_PORT": self.server_address[1],
                "SERVER_PROTOCOL": self.parser.raw_version
            }
    

    多个子进程一起去accept客户端client会怎样?

    在旧的内核中会产生多个子进程同时唤醒(惊群问题), 新的内核只有一个能得到client.
    假设A B C三子进程同时在select.select, 那么只会有其中一个返回, 例如是B, 现在的等待队列之后A C(因为B在处理报文了)

    相关文章

      网友评论

          本文标题:Gunicorn 0.2 源码阅读

          本文链接:https://www.haomeiwen.com/subject/fuactrtx.html