之前一直在用nginx + uwsgi + django 架构,之前也在博客里分享过相关故障解决:
nginx+uwsgi完美配置文件,解决“upstream prematurely closed connection”报错
nginx + uwsgi + django出现的问题
那么在用了一段时间后发现一个很严重的问题:无论代码层如何优化,都会出现内存泄漏(内存占用无限增长)的问题,
尝试过增加uwsgi.ini配置文件中添加参数:max-requests = 50,来对抗内存泄露(该参数用来控制每个进程处理50个请求后重启该进程)。
但发现并没有什么用,当然网上还有其他折中方案,比如控制达到占用多少内存后自动重启uwsgi,但这些都是治标不治本的,果断弃用nginx + uwsgi + django架构。
Nginx + gunicorn + Flask
在考虑很多架构后,还是选择了一个主流轻量级架构:Nginx + gunicorn + Flask
网上相关的资料也不少,在参考了网上很多demo与教程,加上零碎的实用配置与自己的理解,终于实现了生产环境稳定上线,那么在这里想把自己的最简,最优,最实用配置分享出来,同时也是作为一个备忘。
这里我们应用了flask 的一个扩展:flask_restful
安装:
pip3 install flask && pip3 install flask_restful
以下的demo代码为实现一个接口的最简代码,基本满足接口使用:
接口demo代码
文件名:vuln.py
from flask import Flask,request,jsonify
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
# 这是第一个接口
class task_1(Resource):
def get(self): #这里的get函数,指定处理get请求
parser = reqparse.RequestParser()
parser.add_argument("url", type=str, location="args", required=False)
parser.add_argument("type", type=int, location="args", required=False)
parser.add_argument("id", type=str, location="args", required=False)
params = parser.parse_args(strict=False)
if params['action'] == 'fresh':
#run something
return 'vuln.cn demo 1'
else:
#run something
return 'hello vuln.cn'
# 这是第二个接口
class task_2(Resource):
def get(self):
parser = reqparse.RequestParser()
parser.add_argument("id", type=str, location="args", required=False)
params = parser.parse_args(strict=False)
#run something
return 'vuln.cn demo 2'
#路由地址分别对应处理的类
api.add_resource(task_1, '/demo1/') #实现接口:http://www.vuln.cn:8002/demo1/?url=xxx&type=xxx&id=xxx
api.add_resource(task_2, '/demo2/') #实现接口:http://www.vuln.cn:8002/demo2/?id=xxx
if __name__ == '__main__':
app.run(debug=True)
flask web启动(仅限测试使用,不可作为生产接口)
flask run -h 0.0.0.0 -p 8002
这里0.0.0.0 可以接收外网访问
那么,以上就完成了一个基本的web接口,访问8002端口,加上对应的参数即可看到响应,这里就不截图了。
但是,从代码功能角度是已经没有问题的,接口已经写好,但从系统稳定性与web性能角度是远远不够的,因为你测试的时候会发现,flask 启动的接口同时只能处理一个请求。
gunicorn 配置
这时候就需要引入部署容器gunicorn,安装与配置都非常简单。
安装:
pip3 install gunicorn
启动:
gunicorn -w 50 -b 0.0.0.0:8080 vuln:app --reload -t 500 -D --access-logfile log/gunicorn.log
以上启动命令的含义为:
- -w 50 开启50个进程
- 0.0.0.0:8080 定义8080端口
- vuln:app vuln为项目的文件名,如上面的vuln.py文件名,app为vuln.py代码中 app = Flask(__name__)
- –realod 监听到项目文件变动自动重启gunicorn 使之生效
- -t 500 配置每个请求的超时时间为500秒
- -D 让命令后台执行
- –access-logfile log/gunicorn.log 将请求日志保存到该文件中
以上我们就可以使用8080端口来访问我们的接口,到这里已经差不多了,但是我们还需要在web最外层用nginx 做下代理提升静态文件的web性能。
nginx最外层代理
nginx相关的配置博客里已经有很多了,在这里再贴一个我的最简配置吧:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
server {
listen 80;
server_name www.vuln.cn;
location / {
proxy_pass http://127.0.0.1:8080;
access_log /home/web/log/api_access.log;
proxy_read_timeout 300;
}
}
关于第一行的配置解释可以参考:Nginx反向代理 + Flask + gunicorn 架构解决获取用户真实ip问题
至此,已经实现nginx 80端口代理本地后端gunicorn服务(8080)启动的flask web项目。
以上demo 与部署方案仅为个人经验,仅供参考,本文会持续更新优化