Flask 高并发部署方案

在Python开发中,部署有各种各样的方案,同时作为服务端语言也是比较吃力的,没有Java那样有很成熟的方案。在这里介绍一个高并发部署方案:Nginx+Gunicorn+Gevent+Supervisor+Flask。

众所周知 Flask 是一个同步的框架,处理请求的时候是以单进程的方式,当同时访问的人数过多时,Flask 服务就会出现阻塞的情况。

就像我们买火车票一样,当买火车票的人多的时候,排队的人就会很多,队伍就会很长,相应的等待的时间会变得很长!

方案

  • Nginx:高性能 Web 服务器+负载均衡
  • Gunicorn:高性能 WSGI 服务器;
  • Gevent:把 Python 同步代码变成异步协程的库;
  • Supervisor:监控服务进程的工具;
  • Flask:一个使用Python编写的轻量级 Web 应用框架

Gunicorn来实现webserver,会启动多个进程,通过Gevent模式来运行,会达到协程的效果,每来一个请求会自动分配给不同的进程来执行

部署

1. 创建Flask项目

创建项目、安装依赖库 mkdir flask-proj & pip3 install flask
构建简单服务 cd flask-project & vi app.py

# app.py
from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

启动 flask python3 app.py 此时,用浏览器访问 http://127.0.0.1:5000 就能看到网页显示Hello World!

2. Gunicorn 部署服务

现在我们使用 flask 自带的服务器,完成了 web 服务的启动。生产环境下,flask 自带的 服务器,无法满足性能要求。我们这里采用 gunicorn 做 wsgi容器,用来部署 python。

  1. 安装 gunicorn pip3 install gunicorn
  2. 创建 gunicorn 配置文件
    在项目根目录创建一个 gunicorn.py 文件。

     # gunicorn.py
     import gevent.monkey
        
     gevent.monkey.patch_all()
        
     import multiprocessing
     import os
    
     if not os.path.exists('log'):
         os.mkdir('log')
    
     debug = True
     loglevel = 'debug'
     bind = '0.0.0.0:5000'
     pidfile = 'log/gunicorn.pid'
     logfile = 'log/debug.log'
     errorlog = 'log/error.log'
     accesslog = 'log/access.log'
    
     # 启动的进程数
     workers = multiprocessing.cpu_count() * 2 + 1
     worker_class = 'gunicorn.workers.ggevent.GeventWorker'
    
     x_forwarded_for_header = 'X-FORWARDED-FOR'
    

    这里使用gevent模式来支持并发

  3. 创建文件入口
    在使用Pycharm创建Flask项目的时候,会生成一个app.py的入口文件,里面是创建启动App实例,在这里我们创建一个新的程序入口,用来使用Gunicorn服务,在生产环境中使用。
    在项目根目录创建一个wsgi.py的文件,内容如下:

     from app import app
     import logging
    
     gunicorn_logger = logging.getLogger('gunicorn.error')
     app.logger.handlers = gunicorn_logger.handlers
     app.logger.setLevel(gunicorn_logger.level)
    
     if __name__ == '__main__':
         app.run(host='0.0.0.0')
    
  4. 测试配置
    上面配置好了,下面进行测试运行服务。
    执行命令:gunicorn -c gunicorn.py wsgi:app
    如果没有出现报错,那么服务就可以启动了,访问接口可以有数据了。

Supervisor 监控服务

Supervisor是一个用Python编写的进程管理工具,我们这里通过他来管理我们的项目进程。

  1. 安装 Supervisor pip install supervisor

     # 设置 Supervisor 配置文件位置
     echo_supervisor_conf > /opt/supervisor/supervisor.conf
    
     # 编辑 supervisor.conf ,修改内容,去掉注释
     # vi /opt/supervisor/supervisor.conf
     [include]
     files = /opt/supervisor/*.conf
    

    通常这两行是注释的,这里我们取消注释,这个配置的作用是导入这个路径下面所有的conf配置文件,后面如果有很多项目,可以每个项目都写一个配置文件。

  2. 创建 Flask 项目的配置文件
    这里我们创建一个项目需要的配置文件,用于启动我们上面创建的flask项目。
    首先创建一个 flask-proj.conf,名字可以随意起
    内容如下:

     # /opt/supervisor/flask-proj.conf
     # flaskproj是项目启动的服务标识,可以根据自己需求去修改
     # command后内容,为使用gunicorn的启动命令
     # directory是项目根目录
    
     [program:flaskproj]
     command=gunicorn -c gunicorn.py wsgi:app
     directory=/root/project/flask-proj/
     startsecs=0
     stopwaitsecs=0
     autostart=true
     autorestart=true
    

    supervisor的基本使用命令

     supervisord -c supervisor.conf                             通过配置文件启动supervisor
     supervisorctl -c supervisor.conf status                    查看supervisor的状态
     supervisorctl -c supervisor.conf reload                    重新载入 配置文件
     supervisorctl -c supervisor.conf start [all]|[appname]     启动指定/所有 supervisor管理的程序进程
     supervisorctl -c supervisor.conf stop [all]|[appname]      关闭指定/所有 supervisor管理的程序进程
    

    supervisor 还有一个web的管理界面,可以激活。更改 supervisor.conf 配置文件

     [inet_http_server]         ; inet (TCP) server disabled by default
     port=127.0.0.1:9000        ; (ip_address:port specifier, *:port for all iface)
     username=user              ; (default is no username (open server))
     password=123               ; (default is no password (open server))
    
     [supervisorctl]
     serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
     serverurl=http://127.0.0.1:9000 ; use an http:// url to specify an inet socket
     username=user              ; should be same as http_username if set
     password=123                ; should be same as http_password if set
     ;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
     ;history_file=~/.sc_history  ; use readline history if available
    
  3. 启动 Supervisord 服务
    上面配置好了Supervisord所需要的配置,下面开始启动服务
    启动命令 supervisord -c /opt/supervisord/supervisord.conf
    现在已经完成 supervsior 启动 gunicorn。访问 http://127.0.0.1:9000 可以得到 supervisor的web管理界面。访问 http://localhost:5000 可以看见 gunciron 启动的返回的Hello World!

配置 Nginx

pass…

参考