gunicorn + flask 处理高并发请求介绍

一,独角兽
Gunicorn 服务器作为wsgi app的容器, 采用 pre-fork 模型中有一个管理进程以及几个的工作进程。master 管理多个 slave 进程
创建slave进程,监听事件:
1, 根据定义的 work数量 创建多个 work 进程
2, 在worker.init_process()函数中,每个woker子进程都会单独去实例化我们的wsgi app对象。针对多进程,一个进程实例化一个 app 对象,多线程,一个线程处理实例化app对象,协程根据server对象
3, 然后,worker和master各自进入自己的消息循环。 master的事件循环就是收收信号,管理管理worker进程,
而worker进程的事件循环就是监听网络事件并处理(如新建连接,断开连接,处理请求发送响应等等),真正的连接最终是连到了worker进程上的
# 创建 固定数量的 worker(由 manager 进行维护)
    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)

    # 创建 work 进程
    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 = 0 表示子进程
        pid = os.fork()
        #父进程,返回后继续创建其他worker,没worker后进入到自己的消息循环
        if pid != 0:
            # 父进程记录子进程
            self.WORKERS[pid] = worker
            return pid

        # 子进程继续运行
        # Process Child
        worker_pid = os.getpid()
        try:
            ..........
            worker.init_process() #子进程,初始化woker,进入worker的消息循环,
            sys.exit(0)
        except SystemExit:
            raise
        ............
View Code
二,  Gunicorn 几种启动方式 sync (默认值) eventlet gevent tornado
IO 受限 -建议使用gevent或者asyncio
CPU受限 -建议增加workers数量
不确定内存占用? -建议使用gthread
       # gunicorn 启动4个进程(默认启动方式),每个 work 单线程 并发量 4*1
        gunicorn -w 4 -b 0.0.0.0:8000 demo:app
         # gunicorn 允许每个worker拥有多个线程  并发量 = 4*2
        gunicorn -w 4 --thread=2 --worker-class=gthread main:app
         # gunicorn  伪线程 gevent (协程) 并发量 3*1000
        gunicorn --worker-class=gevent --worker-connections=1000 -w 3 main:app
三, web 异步任务实现方式:
1, web 的多并发 并不是有 flask 来实现的, flask 只是负责根据Request产生Response(一个python程序),
多并发是由 WSGI server是通过进程(pre-fork)来并发的。这样并发就取决与进程数,如果WSGI server用了gevent,
eventlet等 green thread技术,就可以支持更多并发
2, 针对 work 启动方式 gevent
每个ggevent worker启动的时候会启动多个server对象,worker首先为每个listener创建一个server对象,
每个server对象都有运行在一个单独的gevent pool对象中。真正等待链接和处理链接的操作是在server对象中进行的
3,WSGIServer 实际上是创建一个协程去处理该套接字,也就是说在WSGIServer 中,一个协程单独负责一个HTTP链接。
协程中运行的self._handle函数实际上是调用了WSGIHandler的handle函数来不断处理http 请求
4,gunicorn 会启动一组 worker进程,所有worker进程公用一组listener,在每个worker中为每个listener建立一个wsgi server。
每当有HTTP链接到来时,wsgi server创建一个协程来处理该链接,协程处理该链接的时候,先初始化WSGI环境,
然后调用用户提供的app对象去处理HTTP请求(处理http请求可以理解为一个程序)。
#为每个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)
        .........
View Code
  在handle函数的循环内部,handle_one_request函数首先读取HTTP 请求,初始化WSGI环境,然后最终调用run_application函数来处理请求
    def run_application(self):
        self.result = self.application(self.environ, self.start_response)
        self.process_result()

 



posted @ 2021-01-09 12:32  十七楼的羊  阅读(3596)  评论(0编辑  收藏  举报