flask 程序使用 websocket,部署使用 gunicorn, gunicorn 导致 websocket 运行有问题

2018-10-11 12:07:09 +08:00
 hanssx

#1 本地开发 flask 应用程序,里面使用了 websocket,异步模式使用得是 gevent,并在程序刚开始打了 gevent 猴子补丁,s 端主要监听 connect disconnect 两个事件用来做一些前端页面的初始化和离开动作。 启动代码:

socketio.run(app=app, host='0.0.0.0', port=5000, debug=True)

#2 正常在本地 debug 或 run 都没问题,部署到测试环境遇到问题,测试环境采用得是 Nginx+supervisor+gunicorn+flask, nginx 配置:

    server {
        listen       8000;
        listen       [::]:8000;
        server_name  x.x.x.x;
        root /root/python/asset;
        location / {
            	proxy_pass http://127.0.0.1:5000;
	    	proxy_redirect off;
	    	proxy_set_header Host $host;
	    	proxy_set_header X-Real-IP $remote_addr;
	    	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	    	access_log /var/log/asset/access.log;
	    	error_log /var/log/asset/error.log;
	    	proxy_set_header Upgrade $http_upgrade;
            	proxy_set_header Connection "Upgrade";
        }
    }

supervisor 配置:

[program:xx]
directory = /root/python/xx
command = /root/.local/xxx/bin/gunicorn -b 127.0.0.1:5000 -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 module:app
user = root
autostart = true
autorestart = true
stopasgroup = true
killasgroup = true
startsecs = 5
startretries = 3
redirect_stderr = true
stdout_logfile_maxbytes = 20MB
stdout_logfile_backups = 20
stdout_logfile = /var/log/xx/stdout.log
stderr_logfile = /var/log/xx/stderr.log

其中启动 gunicorn 的命令参考自
https://stackoverflow.com/questions/38624447/websockets-proxied-by-nginx-to-gunicorn-over-https-giving-400-bad-request
https://segmentfault.com/q/1010000007495163
https://flask-socketio.readthedocs.io/en/latest/#gunicorn-web-server
gunicorn 也在 pipenv 环境下安装

#3 不使用 gunicorn 的情况下没任何问题,如图: 使用了 gunicorn 的情况,
首先会导致 402 错误,
402 详情,
其次,会一直 pending,一直在发请求,
最后是 402 详情在控制台的信息,
请各位帮帮忙,尝试了好长时间没办法解决,感谢各位。

8466 次点击
所在节点    Python
30 条回复
hanssx
2018-10-11 16:44:18 +08:00
清理了 gunicorn 进程,抛弃了 websocket-gevent,使用了 gevent,gunicorn -b 127.0.0.1:5000 -k gevent -w 1 module:app,不再报 402 错误了,但是程序还是会一直 pending,一直发请求。。。
hanssx
2018-10-11 16:47:12 +08:00
@itertools 是的,不支持 py3,真是我的锅,第一次部署花了很多时间,使用了 gevent 之后没有 402 错误了,但是会一直 pending,gunicorn 日志显示好像是心跳包,正在找办法关了它。。。
[2018-10-11 16:40:27 +0800] [12128] [INFO] Shutting down: Master
[2018-10-11 16:41:47 +0800] [13014] [INFO] Starting gunicorn 19.9.0
[2018-10-11 16:41:47 +0800] [13014] [INFO] Listening at: http://127.0.0.1:5000 (13014)
[2018-10-11 16:41:47 +0800] [13014] [INFO] Using worker: gevent
[2018-10-11 16:41:47 +0800] [13017] [INFO] Booting worker with pid: 13017
Server initialized for gevent.
94207eaf37114c118b05480ba12679ef: Sending packet OPEN data {'sid': '94207eaf37114c118b05480ba12679ef', 'upgrades': [], 'pingTimeout': 60000, 'pingInterval': 25000}
94207eaf37114c118b05480ba12679ef: Sending packet MESSAGE data 0
94207eaf37114c118b05480ba12679ef: Received packet MESSAGE data 0/process_upload_csv
94207eaf37114c118b05480ba12679ef: Sending packet MESSAGE data 0/process_upload_csv
94207eaf37114c118b05480ba12679ef: Received packet PING data None
94207eaf37114c118b05480ba12679ef: Sending packet PONG data None
94207eaf37114c118b05480ba12679ef: Received packet PING data None
94207eaf37114c118b05480ba12679ef: Sending packet PONG data None
94207eaf37114c118b05480ba12679ef: Received packet PING data None
hanssx
2018-10-11 16:50:01 +08:00
hanssx
2018-10-11 16:53:37 +08:00
@itertools 我 flask 应用程序的启动代码:socketio.run(app=app, host='0.0.0.0', port=5000, debug=True)
其中 socketio 初始化时,指定了 async_mode='gevent',是这个原因吗?然后 gunicorn 也使用了 gevent。
hanssx
2018-10-11 17:26:37 +08:00
@itertools 我晕,我本地不加 gunicorn,socketio.run(app=app, host='0.0.0.0', port=5000, debug=True),指定 async_mode='gevent',也会一直 pending,一直请求。。。
itertools
2018-10-11 17:43:29 +08:00
@hanssx 目前最解决问题的办法是使用 gunicorn + eventlet 组合跑,卸载 gevent 安装 eventlet 然后把 async_mode="gevent"改成 async_mode="eventlet " 启动命令为 gunicorn --worker-class eventlet -w 1 module:app。
如果一定要用 gevent 请尝试使用 uWSGI + gevent
hanssx
2018-10-11 17:46:27 +08:00
@itertools 确实,老哥,能加您个 QQ 吗?想感谢您一下,gevent+flask-socketio 就会一直发请求并且 pending,eventlet 则不会,怎么会这样我也不明白,我的扣扣 9614 六 2392,期待老哥,哈哈。
hanssx
2018-10-11 17:48:46 +08:00
已解决,感谢各位的帮助,特别是 itertools。
daya
2018-10-11 17:53:42 +08:00
怎么解决的?
hanssx
2018-10-11 17:56:05 +08:00
@daya 首先清除 gunicorn 多余进程,使用 netstat -antlp | grep port 或者 ps -ef | grep guni,然后 sudo kill -9 pid
然后再把 gevent-websocket 换成 gevetn,因为前者不支持 py3
最后把 flask-socketio 的 async_mode 换成 eventlet 而不是 gevent,gevent 会一直发送类似心跳包的东西,不知道有没有选项可以清除。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/496645

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX