最简单的Flask Web应用:
新建文件夹myproject,里面就一个文件:myapp.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hi! It works!'
if __name__=='__main__':
app.run(host='0.0.0.0')
想启动该应用,只要运行python myapp.py就可以在浏览器http://localhost:5000看到运行结果了。开心!
然鹅,这里的问题是:这个应用是单进程单线程的,如果在多个用户(高并发)的场景,这个就要跪了
Flask 作为一个 Web 框架,内置了一个 webserver, 但这自带的 Server 到底能不能用?
官网的介绍:
While lightweight and easy to use, Flask’s built-in server is not suitable for production as it doesn’t scale well. Some of the options available for properly running Flask in production are documented here.
很显然,内置的 webserver 是能用的。但不适合放在生产环境。这个 server 本来就是给开发者用的。框架本身并不提供生产环境的 web 服务器,SpringBoot 这种内置 Tomcat 生产级服务器 是例外。
假设我们使用的是 Nginx+Flask Run 来当作生产环境,全部部署在一台机器上。劣势如下:
Gunicorn(绿色独角兽)是一个Python WSGI的HTTP服务器。从Ruby的独角兽(Unicorn )项目移植。该Gunicorn服务器与各种Web框架兼容,实现非常简单,轻量级的资源消耗。Gunicorn直接用命令启动,不需要编写配置文件,相对uWSGI要容易很多。
Gunicorn 作为 Server 相对而言可以有什么提升?
架构:
nginx(反向代理)-> gunicorn(with gevent)-> flask server -> supervisor
nginx 只使用反向代理功能,不再作负载均衡。负载均衡在 gunicorn 侧实现,采用轮询方式。
这时候Gunicorn登场了,它就是来解决这个高并发的问题的。它全名叫Green Unicorn,是一个被广泛使用的高性能的Python WSGI Unix HTTP服务器。
Gunicorn 是python中的WSGI容器,pre-fork worker模式,优点就是配置简单,轻量级的资源消耗,以及高性能。
安装
$ pip install gunicorn
相关配置:
bind = '0.0.0.0:17123' # 监听地址和端口
backlog = 2048 # 最大挂起连接数
timeout = 30 # 超时时间
worker_class = 'gevent' # worker 进程的工作方式。目前选用 gevent 异步协程方式
worker_connections = 65535 # 客户端最大同时连接数
workers = 1 # 处理请求的 worker 进程数量,多进程
threads = 1 # 每个 worker 进程的线程数。采用 gevent 协程方式时,配置 1 即可
使用
在命令行下,键入:
$ gunicorn -w 4 myapp:app
可以看到输出:
[2018-10-25 20:21:12 +0800] [28597] [INFO] Starting gunicorn 19.9.0
[2018-10-25 20:21:12 +0800] [28597] [INFO] Listening at: http://127.0.0.1:8000 (28597)
[2018-10-25 20:21:12 +0800] [28597] [INFO] Using worker: sync
[2018-10-25 20:21:12 +0800] [28600] [INFO] Booting worker with pid: 28600
[2018-10-25 20:21:12 +0800] [28601] [INFO] Booting worker with pid: 28601
[2018-10-25 20:21:12 +0800] [28602] [INFO] Booting worker with pid: 28602
[2018-10-25 20:21:12 +0800] [28603] [INFO] Booting worker with pid: 28603
在浏览器键入http://localhost:8000
就可以访问。
其中-w表示启动的进程数,myapp是Python文件名,app是文件中的变量名或者函数名。可以看到,默认是绑定8000端口的,也就是说Python文件里那个main函数可以忽略了。
多进程高并发的问题解决了,开心!
然鹅,使用这个命令时,当我们退出终端时,这个应用就跪了,不能继续在后台运行,当然我们可以用nohup gunicorn -w 4 myapp:app &这
个命令让它在后台运行,但是后续的状态监控呀什么的,可能就要用什么ps、kill这种原生态命令了,这真是太TM烦了。
实际环境:
启动命令:
gunicorn_conf_MEO.py -> gunicorn 配置文件
MEO : app -> MEO.py文件名 : flask 中的app = Flask(name)
gunicorn -c gunicorn_conf_MEO.py MEO:app
这时候Supervisor闪亮登场!
Supervisor是一个进程管理系统,它通过fork/exec的方式将这些被管理的进程当作它的子进程来启动,若该子进程异常中断,则父进程可以准确地获取子进程异常中断的信息。
supervisor是一个制作守护进程的工具,用户可以在UNIX系统中监控、管理进程。
常用于管理与某个用户或项目相关的进程。
去帮我们维护各种服务器的进程,即使有软件崩了也能帮我们自动重启。
用于在生产环境中,控制项目涉及的软件的进程。
如果不使用supervisor,重启gunicorn的步骤是:
指定进程和端口号: -w
: 表示进程(worker
)。 -b
:表示绑定ip地址和端口号(bind)。
$gunicorn -w 4 -b 127.0.0.1:5001 运行文件名称:Flask程序实例名
pstree -ap|grep gunicorn
kill -9(gunicorn pid)
gunicorn -w6 -b 127.0.0.1:80 demo:app
主要功能:
安装
sudo apt install supervisor
使用
在项目文件夹下新建supervisor_app.conf文件:
[include]
files=/etc/supervisord.conf
[program:awesome_app]
directory=/home/gld/myproject
command=gunicorn -w 4 myapp:app
生成配置文件:echo_supervisord_conf > /etc/supervisord.conf(默认是没有配置文件的)
例如在配置文件/etc/supervisord.conf中添加:
[program:gunicorn]
command=gunicorn manage:app ;supervisor启动命令
directory=/home/hanquan/testPython/xxx ;项目的文件夹路径
startsecs=0 ;启动时间
stopwaitsecs=0 ;终止等待时间
autostart=true ;是否自动启动
autorestart=true ;是否自动重启
stdout_logfile=/home/hanquan/testPython/xxx/log/gunicorn.log ;log日志
stderr_logfile=/home/hanquan/testPython/xxx/log/gunicorn.err ;error日志
[program:nginx]
command=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf -g 'daemon off;' ;前台运行
directory=/home/hanquan/testPython/xxx ;项目的文件夹路径
startsecs=0 ;启动时间
stopwaitsecs=0 ;终止等待时间
autostart=true ;是否自动启动
autorestart=true ;是否自动重启
stdout_logfile=/home/hanquan/testPython/xxx/log/nginx.log ;log日志
stderr_logfile=/home/hanquan/testPython/xxx/log/nginx.err ;error日志
实际环境:
[program:meo_zwj] z'w ; 被管理的进程配置参数,后面是进程的名称
directory=/home/vnfm/zwj/meo/MEO/MEO ; 脚本目录
command=gunicorn -c configure/gunicorn_conf_MEO.py MEO:app ; 脚本执行命令
priority=999 ; 进程启动优先级,默认999,值小的优先启动
autostart=true ; 在supervisord启动的时候也自动启动
startsecs=10 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
startretries=3 ; 启动失败自动重试次数,默认是3
autorestart=true ; 程序退出后自动重启,可选值:[unexpected,true,false]
user=vnfm ; 用哪个用户启动进程,默认是root
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile=/tmp/meo_zwj_stdout.out
stderr_logfile=/tmp/meo_zwj_stderr.out
启动supervisord:
sudo supervisord -c myproject/supervisor_app.conf
启动我们的应用:
$ sudo supervisorctl start awesome_app
常用管理命令:
$sudo supervisorctl start [program_name]
$sudo supervisorctl stop [program_name]
$sudo supervisorctl restart [program_name] # 重启服务,注意这里不会重新加载配置文件
更新项目文件后,重启supervisor命令:
supervisorctl restart all
重新加载配置文件,重新启动正在运行的服务:
$sudo supervisorctl reload
重新加载修改过的配置并重启该服务:
$sudo supervisorctl reread
$sudo supervisorctl update
supervisor 相关操作:
systemctl start supervisord.service //启动 supervisor 并加载默认配置文件
systemctl stop supervisord.service //停止 supervisor
管理各服务进程:
supervisorctl status //查看所有进程的状态
supervisorctl stop meo_vimproxy //停止 meo_vimproxy 进程
supervisorctl start meo_vimproxy //启动 meo_vimproxy 进程
supervisorctl restart meo_vimproxy //重启 meo_vimproxy 进程
supervisorctl restart all //重启所有进程
supervisorctl update //配置文件修改后使用该命令加载新的配置
supervisorctl reload //重新启动配置中的所有程序
------------------------------------------------------------------------------------------
supervisor的服务器端部分启动命令:
sudo unlink /var/run/supervisor.sock(执行第二行产生文件后执行)
supervisord -c /etc/supervisord.conf
此时默认开启了所有服务
supervisor的客户端部分命令:
supervisorctl status 查看进程运行状态
supervisorctl start 进程名 启动进程
supervisorctl stop 进程名 关闭进程
supervisorctl restart 进程名 重启进程
supervisorctl update 重新载入配置文件
supervisorctl shutdown 关闭supervisord
supervisorctl clear 进程名 清空进程日志
supervisorctl 进入到交互模式下。使用help查看所有命令。
例如: supervisorctl start all 启动所有进程
supervisorctl restart all 重启所有进程
supervisorctl stop all 停止所有进程
常用参数:
-w:进程数,如-w 4
-b:绑定地址和端口,如-b 0.0.0.0:5000
Supervisor只能监控前台程序, 如果你的程序是通过fork方式实现的daemon服务,则不能用它监控,否则会提示:BACKOFF Exited too quickly (process log may have details)。 因此像Apache、Tomcat服务默认启动都是按daemon方式启动的,则不能通过Supervisor直接运行启动脚本(service httpd start),相反要通过一个包装过的启停脚本来完成。(参考博客)
日志
Logging, Flask, and Gunicorn … the Manageable Way
常见问题
CentOS 7.4默认的日志打印在/var/log/supervisor/supervisord.log文件下。
Permission权限问题
有时候提示往/tmp文件夹写入文件提示PermissionErr,检查supervisor配置文件,可以设置为user=root。
exit status 127; not expected
127表示命令没找到,首先可能是directory写错,用cd命令看一下,然后可能是command命令写错,复制命令在控制台试试是否gunicorn无法使用。
supervisor: couldn’t exec celery: EACCES
CentOS
CentOS Linux release 7.6.1810
安装Python3:
yum install python36u
安装pip3:
yum install python36u-pip
安装gunicorn:
pip3 install gunicorn
安装supervisor:
yum install supervisor
运行echo_supervisord_conf
命令输出默认的配置项,可以如下操作将默认配置保存到文件中
echo_supervisord_conf > supervisord.conf
vim 打开编辑supervisord.conf文件,修改
[include]
files = relative/directory/*.ini
为
[include]
files = /etc/supervisor/*.conf
include
选项指明包含的其他配置文件。
将编辑后的supervisord.conf文件复制到/etc/目录下
sudo cp supervisord.conf /etc/
然后我们在/etc目录下新建子目录supervisor(与配置文件里的选项相同),并在/etc/supervisor/中新建tuotiao管理的配置文件toutiao.conf
。
[group:toutiao]
programs=toutiao-app
[program:toutiao-app]
command=/home/python/scripts/toutiao_app.sh
directory=/home/python/toutiao-backend
user=python
autorestart=true
redirect_stderr=false
loglevel=info
stopsignal=KILL
stopasgroup=true
killasgroup=true
[program:im]
command=/home/python/scripts/im.sh
directory=/home/python/toutiao-backend
user=python
autorestart=true
redirect_stderr=false
loglevel=info
stopsignal=KILL
stopasgroup=true
killasgroup=true
启动
supervisord -c /etc/supervisord.conf
查看 supervisord 是否在运行:
ps aux | grep supervisord
我们可以利用supervisorctl
来管理supervisor。
supervisorctl // 执行supervisorctl,进去命令行编辑器
> status # 查看程序状态
> start apscheduler # 启动 apscheduler 单一程序
> stop toutiao:* # 关闭 toutiao组 程序
> start toutiao:* # 启动 toutiao组 程序
> restart toutiao:* # 重启 toutiao组 程序
> update # 重启配置文件修改过的程序
执行status命令时,显示如下信息说明程序运行正常:
supervisor> status
toutiao:toutiao-app RUNNING pid 32091, uptime 00:00:02