Flask SocketIO 的正确配置
Correct configuration for Flask SocketIO
我一直在按照本教程尝试使用 nginx
和 gunicorn
.
获得 Flask SocketIO
运行
nginx
server {
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
location /socket.io {
proxy_pass http://localhost:8000/socket.io;
proxy_redirect off;
proxy_buffering 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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
gunicorn_config.py
bind = '127.0.0.1:8000'
workers = 2
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
在 Supervisor
我调用我的应用程序:
[program:gunicorn-couponmonk]
directory = ~/couponmonk_project
command =~/venv/py2.7/bin/python ~/venv/py2.7/bin/gunicorn -c ~/venv/py2.7/lib/python2.7/site-packages/gunicorn/gunicorn_config.py __init__.py
stdout_logfile = /var/log/gunicorn/couponmonk-std.log
stderr_logfile = /var/log/gunicorn/couponmonk-err.log
user = mint
使用此配置,我的应用程序(不使用 Flask SocketIO
)工作正常。
我只是对如何使用感到困惑 socketIO
。如果我转到地址 http://localhost:8000/socket.io,我会收到响应 Internal Server Error
。
示例 HTML/Javascript
(https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/example/templates/index.html) 包含此行:
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
我有两个问题:
1) 这个变量应该指向什么地址?
2)我的配置(nginx
、gunicorn
)是否正确?
抱歉,如果这个问题很愚蠢。我只是对这一切应该如何运作感到困惑。
感谢您的帮助。
**更新**
这是我尝试访问 http://localhost/socket.io.
时 nginx
error.log
文件的输出
2015/06/20 14:05:08 [debug] 1917#0: *1 http cleanup add: 00000000009F2170
2015/06/20 14:05:08 [debug] 1917#0: *1 get rr peer, try: 1
2015/06/20 14:05:08 [debug] 1917#0: *1 socket 12
2015/06/20 14:05:08 [debug] 1917#0: *1 epoll add connection: fd:12 ev:80000005
2015/06/20 14:05:08 [debug] 1917#0: *1 connect to 127.0.0.1:8000, fd:12 #2
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream connect: -2
2015/06/20 14:05:08 [debug] 1917#0: *1 posix_memalign: 0000000000A14170:128 @16
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 http finalize request: -4, "/socket.io?" a:1, c:2
2015/06/20 14:05:08 [debug] 1917#0: *1 http request count:2 blk:0
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A295E0
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request handler
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer buf fl:1 s:439
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer in: 00000000009F21A8
2015/06/20 14:05:08 [debug] 1917#0: *1 writev: 439
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer out: 0000000000000000
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer del: 12: 1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A295E0
2015/06/20 14:05:08 [debug] 1917#0: *1 http run request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream check client, write event:1, "/socket.io"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream recv(): -1 (11: Resource temporarily unavailable)
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A15E38
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream dummy handler
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A15E38
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream process header
2015/06/20 14:05:08 [debug] 1917#0: *1 malloc: 00000000009E88A0:4096
2015/06/20 14:05:08 [debug] 1917#0: *1 recv: fd:12 244 of 4096
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy status 500 "500 Internal Server Error"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Connection: close"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Type: text/html"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Length: 141"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header done
2015/06/20 14:05:08 [debug] 1917#0: *1 xslt filter header
2015/06/20 14:05:08 [debug] 1917#0: *1 HTTP/1.1 500 Internal Server Error
Server: nginx/1.4.6 (Ubuntu)
Date: Sat, 20 Jun 2015 04:05:08 GMT
Content-Type: text/html
Content-Length: 141
Connection: keep-alive
不确定这有多大帮助,但我不知道还能在哪里寻找额外的信息。
我也很好奇为什么我可以访问这个:http://localhost/socket.io123abc
并且仍然得到 Internal Server Error
而不是 Not Found
错误?
我还根据下面的 Miguel's
回答更新了我的 supervisord.conf
文件:
supervisord.conf
[program:gunicorn-couponmonk]
directory = /home/giri/couponmonk_project
command = /home/giri/venv/py2.7/bin/python /home/giri/venv/py2.7/bin/gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker __init__:app
stdout_logfile = /var/log/gunicorn/couponmonk-std.log
stderr_logfile = /var/log/gunicorn/couponmonk-err.log
user = mint
/var/log/gunicorn/couponmonk-err.log
2015-06-20 14:30:11 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:11 [3821] [ERROR] Retrying in 1 second.
2015-06-20 14:30:12 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:12 [3821] [ERROR] Retrying in 1 second.
2015-06-20 14:30:13 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:13 [3821] [ERROR] Retrying in 1 second.
此列表会持续一段时间..
首先,我会提到我根本不推荐使用 SocketIO。它在 WebSockets 上增加了一些有用的功能,但它使真正的多个工作负载平衡(水平缩放)变得不可能,除非你让客户端粘在单个工作人员或使用像 Redis 这样的东西在他们之间共享状态信息。我建议看看:
https://github.com/youen/gevent-websocket
本机 WebSockets 更简单、更容易,并且可以跨多个前端工作者进行扩展以实现真正的负载平衡。实现聊天室逻辑所需的代码非常少。
话虽如此,这里是您问题的答案:
1) What address is this variable supposed to point to?
您的命名空间将是“”。 (根据 Flask-SocketIO 的作者 Miguel 的说法,Javascript 客户端会自动插入 "socket.io" 部分。)
所以,你的 io.connect
url 应该是“http://[hostname]/”。
2) Is my configuration (nginx, gunicorn) correct?
Ngnix 配置似乎正确(请参阅下一节)。如果您决定使用 WebSockets,您可以考虑添加 proxy_read_timeout 3600;
。否则,除非你有一个聊天协议,否则 WebSocket 将被 Nginx 每分钟丢弃一次(默认值)。 (此外,根据 Miguel 的说法,SocketIO 具有处理此问题的心跳。)
Gunicorn 配置不正确。使用 SocketIO,您有几个选择:
- 在 gunicorn 中设置
workers = 1
以便每个 SocketIO 客户端都与同一个工作进程对话。
- 更改您的 nginx 配置以使用
ip-hash
命令,这将导致客户端通过客户端 IP 地址分配给工作人员。
- 使用 Redis 或其他一些数据库来允许每个工作人员共享状态信息(尽管尚不清楚是否有人在为 Gevent SocketIO 工作)。
这些选择是强制性的,因为 SocketIO 使用有状态的设置机制,当您尝试水平扩展时该机制会中断。有关详细信息,请参阅此问题:https://github.com/abourget/gevent-socketio/issues/112
这里有一个 link 的 SocketIO 文档也讨论了它:http://socket.io/docs/using-multiple-nodes/
如果您收到 Internal Server Error
,则可能某处记录了异常。尝试找到它并将其添加到您的问题中。
请注意,您不能通过点击浏览器地址栏中的 URL 来测试它 – 默认情况下浏览器不会使用正确的 WebSocket 协议,并且不会为您做任何有用的事情。必须使用 Javascript API.
设置 WebSocket 连接
此外,尝试使用端口号访问 URL 会绕过 nginx - 这可能不是您想要做的。 Nginx 通常以 80/443 侦听并将请求转发到 localhost:8000(这称为 "reverse proxy" 设置)。
我建议您让 Flask-SocketIO 在没有 nginx 和 gunicorn 的情况下工作。一旦你可以让它通过本机 gevent 服务器工作,你就可以移动到你的真实设置。
关于您的问题:
1) What address is this variable supposed to point to?
你的连接语句是正确的。 Socket.IO 将获取主机、端口和命名空间并自行构建连接 URL,包括 /socket.io
组件。您无需在连接中指定。
2) Is my configuration (nginx, gunicorn) correct?
我认为nginx配置是正确的。你好像是直接从我的文档里抄来的,我已经验证过它可以用了。
我不确定 gunicorn 配置,您没有展示足够多的项目来说明。我使用的命令,你应该在你的主管配置中,是这样的:
gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker module:app
其中module
是应用的主模块,app
是Flask应用实例的名称。使用 SocketIO 时绝对应该使用单个 worker,不要使用两个 worker。
对于任何正在阅读这个旧 post 的人来说,gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker module:app
命令已经过时,因为 Miguel 在 github flask-socketio issue.
之一中提到过
我一直在按照本教程尝试使用 nginx
和 gunicorn
.
Flask SocketIO
运行
nginx
server {
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
location /socket.io {
proxy_pass http://localhost:8000/socket.io;
proxy_redirect off;
proxy_buffering 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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
gunicorn_config.py
bind = '127.0.0.1:8000'
workers = 2
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
在 Supervisor
我调用我的应用程序:
[program:gunicorn-couponmonk]
directory = ~/couponmonk_project
command =~/venv/py2.7/bin/python ~/venv/py2.7/bin/gunicorn -c ~/venv/py2.7/lib/python2.7/site-packages/gunicorn/gunicorn_config.py __init__.py
stdout_logfile = /var/log/gunicorn/couponmonk-std.log
stderr_logfile = /var/log/gunicorn/couponmonk-err.log
user = mint
使用此配置,我的应用程序(不使用 Flask SocketIO
)工作正常。
我只是对如何使用感到困惑 socketIO
。如果我转到地址 http://localhost:8000/socket.io,我会收到响应 Internal Server Error
。
示例 HTML/Javascript
(https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/example/templates/index.html) 包含此行:
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
我有两个问题:
1) 这个变量应该指向什么地址?
2)我的配置(nginx
、gunicorn
)是否正确?
抱歉,如果这个问题很愚蠢。我只是对这一切应该如何运作感到困惑。
感谢您的帮助。
**更新**
这是我尝试访问 http://localhost/socket.io.
时nginx
error.log
文件的输出
2015/06/20 14:05:08 [debug] 1917#0: *1 http cleanup add: 00000000009F2170
2015/06/20 14:05:08 [debug] 1917#0: *1 get rr peer, try: 1
2015/06/20 14:05:08 [debug] 1917#0: *1 socket 12
2015/06/20 14:05:08 [debug] 1917#0: *1 epoll add connection: fd:12 ev:80000005
2015/06/20 14:05:08 [debug] 1917#0: *1 connect to 127.0.0.1:8000, fd:12 #2
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream connect: -2
2015/06/20 14:05:08 [debug] 1917#0: *1 posix_memalign: 0000000000A14170:128 @16
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 http finalize request: -4, "/socket.io?" a:1, c:2
2015/06/20 14:05:08 [debug] 1917#0: *1 http request count:2 blk:0
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A295E0
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request handler
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer buf fl:1 s:439
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer in: 00000000009F21A8
2015/06/20 14:05:08 [debug] 1917#0: *1 writev: 439
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer out: 0000000000000000
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer del: 12: 1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A295E0
2015/06/20 14:05:08 [debug] 1917#0: *1 http run request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream check client, write event:1, "/socket.io"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream recv(): -1 (11: Resource temporarily unavailable)
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A15E38
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream dummy handler
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A15E38
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?"
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream process header
2015/06/20 14:05:08 [debug] 1917#0: *1 malloc: 00000000009E88A0:4096
2015/06/20 14:05:08 [debug] 1917#0: *1 recv: fd:12 244 of 4096
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy status 500 "500 Internal Server Error"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Connection: close"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Type: text/html"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Length: 141"
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header done
2015/06/20 14:05:08 [debug] 1917#0: *1 xslt filter header
2015/06/20 14:05:08 [debug] 1917#0: *1 HTTP/1.1 500 Internal Server Error
Server: nginx/1.4.6 (Ubuntu)
Date: Sat, 20 Jun 2015 04:05:08 GMT
Content-Type: text/html
Content-Length: 141
Connection: keep-alive
不确定这有多大帮助,但我不知道还能在哪里寻找额外的信息。
我也很好奇为什么我可以访问这个:http://localhost/socket.io123abc
并且仍然得到 Internal Server Error
而不是 Not Found
错误?
我还根据下面的 Miguel's
回答更新了我的 supervisord.conf
文件:
supervisord.conf
[program:gunicorn-couponmonk]
directory = /home/giri/couponmonk_project
command = /home/giri/venv/py2.7/bin/python /home/giri/venv/py2.7/bin/gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker __init__:app
stdout_logfile = /var/log/gunicorn/couponmonk-std.log
stderr_logfile = /var/log/gunicorn/couponmonk-err.log
user = mint
/var/log/gunicorn/couponmonk-err.log
2015-06-20 14:30:11 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:11 [3821] [ERROR] Retrying in 1 second.
2015-06-20 14:30:12 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:12 [3821] [ERROR] Retrying in 1 second.
2015-06-20 14:30:13 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000)
2015-06-20 14:30:13 [3821] [ERROR] Retrying in 1 second.
此列表会持续一段时间..
首先,我会提到我根本不推荐使用 SocketIO。它在 WebSockets 上增加了一些有用的功能,但它使真正的多个工作负载平衡(水平缩放)变得不可能,除非你让客户端粘在单个工作人员或使用像 Redis 这样的东西在他们之间共享状态信息。我建议看看:
https://github.com/youen/gevent-websocket
本机 WebSockets 更简单、更容易,并且可以跨多个前端工作者进行扩展以实现真正的负载平衡。实现聊天室逻辑所需的代码非常少。
话虽如此,这里是您问题的答案:
1) What address is this variable supposed to point to?
您的命名空间将是“”。 (根据 Flask-SocketIO 的作者 Miguel 的说法,Javascript 客户端会自动插入 "socket.io" 部分。)
所以,你的 io.connect
url 应该是“http://[hostname]/”。
2) Is my configuration (nginx, gunicorn) correct?
Ngnix 配置似乎正确(请参阅下一节)。如果您决定使用 WebSockets,您可以考虑添加 proxy_read_timeout 3600;
。否则,除非你有一个聊天协议,否则 WebSocket 将被 Nginx 每分钟丢弃一次(默认值)。 (此外,根据 Miguel 的说法,SocketIO 具有处理此问题的心跳。)
Gunicorn 配置不正确。使用 SocketIO,您有几个选择:
- 在 gunicorn 中设置
workers = 1
以便每个 SocketIO 客户端都与同一个工作进程对话。 - 更改您的 nginx 配置以使用
ip-hash
命令,这将导致客户端通过客户端 IP 地址分配给工作人员。 - 使用 Redis 或其他一些数据库来允许每个工作人员共享状态信息(尽管尚不清楚是否有人在为 Gevent SocketIO 工作)。
这些选择是强制性的,因为 SocketIO 使用有状态的设置机制,当您尝试水平扩展时该机制会中断。有关详细信息,请参阅此问题:https://github.com/abourget/gevent-socketio/issues/112
这里有一个 link 的 SocketIO 文档也讨论了它:http://socket.io/docs/using-multiple-nodes/
如果您收到 Internal Server Error
,则可能某处记录了异常。尝试找到它并将其添加到您的问题中。
请注意,您不能通过点击浏览器地址栏中的 URL 来测试它 – 默认情况下浏览器不会使用正确的 WebSocket 协议,并且不会为您做任何有用的事情。必须使用 Javascript API.
设置 WebSocket 连接此外,尝试使用端口号访问 URL 会绕过 nginx - 这可能不是您想要做的。 Nginx 通常以 80/443 侦听并将请求转发到 localhost:8000(这称为 "reverse proxy" 设置)。
我建议您让 Flask-SocketIO 在没有 nginx 和 gunicorn 的情况下工作。一旦你可以让它通过本机 gevent 服务器工作,你就可以移动到你的真实设置。
关于您的问题:
1) What address is this variable supposed to point to?
你的连接语句是正确的。 Socket.IO 将获取主机、端口和命名空间并自行构建连接 URL,包括 /socket.io
组件。您无需在连接中指定。
2) Is my configuration (nginx, gunicorn) correct?
我认为nginx配置是正确的。你好像是直接从我的文档里抄来的,我已经验证过它可以用了。
我不确定 gunicorn 配置,您没有展示足够多的项目来说明。我使用的命令,你应该在你的主管配置中,是这样的:
gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker module:app
其中module
是应用的主模块,app
是Flask应用实例的名称。使用 SocketIO 时绝对应该使用单个 worker,不要使用两个 worker。
对于任何正在阅读这个旧 post 的人来说,gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker module:app
命令已经过时,因为 Miguel 在 github flask-socketio issue.