Python Web

Flask应用示例3 - 通过nginx+gunicorn+fl

2017-11-23  本文已影响63人  红薯爱帅

1,目的

在生产环境下,可以通过Nginx+gunicorn+Flask部署Web服务,从而达到高并发高稳定性的要求。
如果要部署多个APP,可以采用单个Nginx,多个gunicorn+Flask的方式来实现,如下图所示。

gunicorn.png

此外,还可以参考本人的上篇文章,通过nginx+uwsgi+flask搭建web服务

通过两个模式的搭建,个人感觉gunicorn与nginx只是通过端口做反向代理,不像uwsgi通过pid进行通信,效率可能受到影响,没有uwsgi高(并没有大数据量的测试)。
但是,gunicorn用着更顺手,本身就是通过python开发的,可以通过配置文件执行钩子代码(支持python),例如请求前后的处理等等。

2,安装过程

2.1,升级软件包

sudo apt-get update 

2.2,安装virtualenv和python环境

sudo apt-get install build-essential python-dev python-pip 
sudo pip install virtualenv

2.3,在virtualenv中部署flask app,并测试

mkdir mysite

进入mysite目录,然后创建虚拟环境.my_env,激活虚拟环境,然后安装flask

cd mysite 
virtualenv .my_env           # 创建Python虚拟环境
source .my_env/bin/activate  # 进入Python虚拟环境,退出命令是deactivate
pip install flask            # 在虚拟环境下安装flask
# 通过pip freeze保存Python第三方包到requirement文件里面,既能知道自己安装了什么库,也方便别人部署时,安装相应的库。
pip freeze > requirements.txt
from flask import Flask
app = Flask(__name__)

@app.route("/app1/")
def hello():
    return "Hello World!"

@app.route("/app1/flask/")
def hello_flask():
    return "Hello World! Hello Flask!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)

需要注意的是,app.run()只是开发时测试使用,故需要放置在if __name__ == "__main__"下,这样gunicorn才不会执行app.run()方法。而host需要设置为0.0.0.0,表示让flask监听机器的所有ip地址的8080端口。

python hello.py

2.4,在virtualenv中部署gunicorn,并测试

source .env/bin/activate  # 进入Python虚拟环境,退出命令是deactivate
pip install gunicorn      # 在虚拟环境中安装gunicorn
# -w 表示开启多少个worker,根据系统核心数确定,-b表示gunicorn开放的访问地址
(.my_env) kevin@black:~/test$ gunicorn -w 8 -b 0.0.0.0:30000 hello:app
[2017-11-23 19:50:37 +0000] [3725] [INFO] Starting gunicorn 19.7.1
[2017-11-23 19:50:37 +0000] [3725] [INFO] Listening at: http://0.0.0.0:30000 (3725)
[2017-11-23 19:50:37 +0000] [3725] [INFO] Using worker: sync
[2017-11-23 19:50:37 +0000] [3731] [INFO] Booting worker with pid: 3731
[2017-11-23 19:50:37 +0000] [3732] [INFO] Booting worker with pid: 3732
[2017-11-23 19:50:37 +0000] [3737] [INFO] Booting worker with pid: 3737
[2017-11-23 19:50:37 +0000] [3740] [INFO] Booting worker with pid: 3740
[2017-11-23 19:50:37 +0000] [3743] [INFO] Booting worker with pid: 3743
[2017-11-23 19:50:37 +0000] [3744] [INFO] Booting worker with pid: 3744
[2017-11-23 19:50:38 +0000] [3749] [INFO] Booting worker with pid: 3749
[2017-11-23 19:50:38 +0000] [3750] [INFO] Booting worker with pid: 3750

# -k gevent,worker_class进程的工作方式,默认是sync,gevent需要提前安装,可选值eventlet、gevent、tornado、gthread、giohttp

# 查看进程,可以看到用到了虚拟环境的包,否则用的是全局的包
kevin@black:~$ ps -ef | grep gunicorn
kevin  3725 21793  1 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3731  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3732  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3737  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3740  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3743  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3744  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3749  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3750  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3839   937  0 19:50 pts/12   00:00:00 grep --color=auto gunicorn

# 关闭进程
pkill gunicorn

2.5,安装nginx,并配置测试

sudo apt-get install nginx
server {
    listen 8000;
    server_name example.org; # 这是HOST机器的外部域名,用地址也行

    location / {
        proxy_pass http://192.168.1.30:30000; # 这里是指向 gunicorn host 的服务地址
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
kevin@orange:~/web/flask/mysite$ sudo service nginx start
kevin@orange:~/web/flask/mysite$ ps -ef | grep nginx
root      2324     1  0 16:19 ?        00:00:00 nginx: master process /usr/sbin/nginx
www-data  2325  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2326  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2327  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2328  2324  0 16:19 ?        00:00:00 nginx: worker process
zhangsh+  2330  2171  0 16:20 pts/1    00:00:00 grep --color=auto nginx

2.6,服务测试

kevin@Blue:~$ curl http://192.168.1.32:81/app1/flask/
Hello World! Hello Flask!
kevin@Blue:~$ curl http://192.168.1.32:81/app1/
Hello World!
test 1.png test 2.png

3,gunicorn高级用法

pip install gevent
#coding=utf-8
import os
bind = '127.0.0.1:8422'  #绑定的ip已经端口号
workers = 8              #进程数
threads = 2              #指定每个进程开启的线程数,官方推荐设置为核心数的两至四倍
backlog = 2048           #允许挂起的连接数的最大值,官方推荐这个值设在64-2048
timeout = 30             #超时时间,单位秒
worker_class = "gevent"  #工作方式,使用gevent模式,默认的是sync模式(并发只有1个),可选值eventlet、gevent、tornado、gthread、giohttp
worker_connections=1000  #进程链接数,默认值1000,同时链接客户端的阀值,这个设置只对进程工作方式为Eventlet和Gevent的产生影响
daemon=True              #守护进程,默认值是False,守护进程形式来运行Gunicorn进程
pidfile='gunicorn.pid'      #设置pid文件的文件名,如果不设置的话,不会创建pid文件,默认值是None
proc_name="myflask"      #默认值default_proc_name,即gunicorn(需要额外安装setproctitle),但是测试没有生效,需要深入看看??
pythonpath='/home/kevin/test/.my_env/bin'  # 将这些路径加到python path去

loglevel='info'         #日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置,可以是debug,info,warning,error,critical
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'     #设置gunicorn访问日志格式,错误日志无法设置
accesslog = "/home/kevin/test/log/access.log"   #访问日志文件的路径
errorlog = "/home/kevin/test/log/error.log"    #错误日志文件的路径
# accesslog = "log/access.log"   #访问日志文件的路径
# errorlog = "log/error.log"     #错误日志文件的路径

# debug = False
# chdir = '/home/lijiajia/Ip_Asnproject/AsnProc'   #gunicorn要切换到的目的工作目录,测试后,没搞懂具体含义???

# 可以通过以下包完成对gunicorn日志的按天分割,具体用的时候可以尝试
# import logging
# import logging.handlers
# from logging.handlers import WatchedFileHandler

4,参考资料

上一篇 下一篇

猜你喜欢

热点阅读