Flask,Django自带的web server目的就是用于开发,而不是生产环境,自带的server应该只能开单进程,而gunicorn和wsgi是专门为生产环境开发的,能配置更多从而处理更加复杂的请求状态,性能和稳定性都更好。
使用gunicorn启动flask应用:
pip install gunicorn
gunicorn app:app -b localhost:8000 &
第一个app是模块文件的名字,即在这个文件中创建了flask app,第二个app是文件中创建的flask实例的名字,所以如果文件wsgi.py像下面这样:
from app import create_app
app = create_app()
启动应用的命令就应该是:
gunicorn wsgi:app -b localhost:8000 &
gunicorn -w 3 wsgi:app -b localhost:8000 & # 启动了三个进程
退出,关闭,重启gunicorn进程:
获取gunicorn进程树:pstree -ap|grep gunicorn
重启gunicorn任务:kill -HUP 14226
(第二层pid)
退出gunicorn任务:kill -9 28097
(第一层pid)
使用systemd来管理gunicorn服务
- 假设我们在
/opt/sampleapp
下面有一个文件执行文件,使用gunicorn的启动方式就是gunicorn sample:app -b 0.0.0.0:8000
- 需要在
/etc/systemd/system/
下面创建一个名字为sampleapp.service
的文件,文件内容:[Unit] Description = SampleApp # 描述 After = network.target [Service] PermissionsStartOnly = true PIDFile = /run/sampleapp/sampleapp.pid User = sampleapp Group = sampleapp WorkingDirectory = /opt/sampleapp # 执行文件的路径 ExecStartPre = /bin/mkdir /run/sampleapp ExecStartPre = /bin/chown -R sampleapp:sampleapp /run/sampleapp ExecStart = /usr/bin/env gunicorn sample:app -b 0.0.0.0:8000 --pid /run/sampleapp/sampleapp.pid ExecReload = /bin/kill -s HUP $MAINPID ExecStop = /bin/kill -s TERM $MAINPID ExecStopPost = /bin/rm -rf /run/sampleapp PrivateTmp = true [Install] WantedBy = multi-user.target
- 然后我们需要设置权限并且使改变生效:
chmod 755 /etc/systemd/system/sampleapp.service systemctl daemon-reload
- 然后用下面命令来操作:
# 启动 systemctl start sampleapp.service # 查看状态 systemctl status sampleapp.service # 停止服务 systemctl stop sampleapp.service # 重启服务 systemctl restart sampleapp.service
这里使用一个例子:
比如我们的环境其实是在虚拟环境当中,然后使用systemd来启动gunicorn
[Unit]
Description = project
After = network.target
[Service]
WorkingDirectory = /home/user/project/project_C
ExecStart = /home/user/.local/share/virtualenvs/CUS-C-EiCxwBq2/bin/gunicorn wsgi:wsgi -b 0.0.0.0:8080
Type = simple
[Install]
WantedBy = multi-user.target
这里的WorkingDirectory其实就是指定了执行命令的路径
然后我们使用gunicorn的配置文件来配置gunicorn
# -*- coding: utf-8 -*-
# gunicorn.py
import multiprocessing
bind = '0.0.0.0:8080'
timeout = 120
worker_class = 'gevent'
workers = multiprocessing.cpu_count() + 1 # 进程数
threads = 2 # 每个进程开启的线程数量
accesslog = "/home/wangyf/CUS/CUS-C/gunicorn_access.log"
errorlog = "/home/wangyf/CUS/CUS-C/gunicorn_error.log"
在service文件里面就应该修改成
ExecStart = /home/user/.local/share/virtualenvs/CUS-C-EiCxwBq2/bin/gunicorn
-c gunicorn.py wsgi:wsgi
web服务器,web应用,WSGI 之间的联系:
-
WSGI翻译为python web服务器网关接口–>python的应用(Flask)和web服务器(比如Nginx)之间的通信协议,所以如果想让应用在web服务器上运行就必须遵守这个WSGI协议
-
实现WSGI协议的web服务器有uWSGI和Gunicorn,所以很多地方都是使用Nginx+Gunicorn的部署方式,但是实际上直接使用Gunicorn直接部署也是可以外网访问的,那么为何要使用Nginx?
-
Nginx是一个高性能web服务器,有负载均衡,拦截静态请求,高并发等功能:
- 它可以仅通过前端的唯一URL访问分发到后台的多个服务器上,通常会监听80端口
- 它可以拦截静态请求,比如静态文件或者图片,并交给Nginx本身来处理。动态的请求内容则通过WSGI容器(Gunicorn)交给web应用处理
- 所以这样的话,有两种架构方式:
- web应用+WSGI容器+Nginx:WSGI容器比如Gunicorn是一个中间件
- web应用+WSGI容器:WSGI容器就是web服务器
- 实际部署方案:
让Nginx绑定80端口,接受客户端的请求,静态资源请求自己处理,但是将动态内容请求反向代理给运行在本地端口的WSGI容器。