最近几天研究了一下运行flask应用的方式,所以就总结一下。
内容包括nginx+uwsgi部署flask应用,但是也包括一下其它的相关内容。
一、使用flask自带的web server
当我们完成一个flask应用的时候,通常会添加下面这段代码。
if __name__ == '__main__':
app.run('127.0.0.1', 8080)
这就是以flask自带的web_server运行了我们所写的flask应用。点进去可以看到这个web_server是通过werkzeug.serving的run_simple实现的。
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
这里也能看到一个web_server的基本要素,监听的ip地址和端口(上面的host和port),以及处理请求的应用部分(上面的self,也就是app对象)。
flask自带的服务器有两种运行方式:多进程和多线程。可以通过threaded和processes参数进行选择。需要注意的点是:1、多进程方式是采用fork()实现的,在windows上选择该模式会报错;2、多进程和多线程不能同时选择;
app.run('127.0.0.1', 8080,threaded=True,processes=1)
二、使用uwsgi部署flask应用
flask自带的服务器通常只是我们自己测试的时候用的,生产环境中常用的WSGI服务器是uwsgi。
通过pip3命令可以直接下载uwsgi,下载完成后通常建立软连接方便操作。
pip3 install uwsgi
ln -s /usr/local/python3/bin/uwsgi /usr/local/bin/uwsgi
uwsgi的配置文件如下:
[uwsgi]
http = 127.0.0.1:8081
# 当用uwsgi直接做服务器时使用http,如果外面还部署一层nginx,只是把uwsgi当作WSGI容器,用socket。
chdir = /practice/helloworld
# 项目的主目录
# virtualenv =
# 虚拟环境路径,这里我没有用虚拟环境
wsgi-file = hello_world.py
# flask应用对象所在的py文件
callable = app
# flask应用对象
#plugin = python
master = True
# 启动主进程
vacuum = True
#设置退出后清理文件
listen = 100
# 等待队列的大小
processes = 4
# work进程的数量
# threads =
# 每个进程可以有几个线程
thunder-lock = True
# 防止惊群
harakiri = 60
# 超过时间
daemonize = /practice/helloworld/uwsgi.log
pidfile = /practice/helloworld/uwsgi.pid
然后我们使用uwsgi --ini uwsgi.ini
就可以启动uwsgi服务啦~
查看uwsgi运行状态,可以看到有1个master进程和4个worker进程。uwsgi会以轮询的方式让4个worker进程轮流处理请求。
uwsgi服务停止指令为uwsgi --stop uwsgi.pid
。
三、uwsgi以协程的方式运行flask应用
uwsgi很好的支持了gevent,可以通过gevent来实现uwsgi以协程的方式运行flask应用。
通过命令uwsgi --gevent 100 --gevent-monkey-patch uwsgi.ini
启动uwsgi。
其中100代表每个进程开启100个协程。运行状态如下。
以协程方式启动uwsgi的时候,配置文件中不能配置线程,需要注释掉。
四、nginx+uwsgi部署flask应用
nginx.conf文件如下
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8081;
uwsgi_param UWSGI_PYTHON python3;
uwsgi_param UWSGI_CHDIR /practice/helloworld;
uwsgi_param UWSGI_SCRIPT hello_world:app;
uwsgi_read_timeout 300;
uwsgi_connect_timeout 300;
uwsgi_send_timeout 300;
以nginx
命令启动nginx服务即可。
五、疑问
以nginx+uwsgi+gevent部署flask应用时,重复访问的情况下,进程id和线程id不变,但是线程的name是在变化的,这应该和gevent的特性有关。
留个坑,看完gevent的代码后回来填坑。
——以上。