Flask SocketIO的正确配置

6 python nginx gunicorn flask-socketio

我一直在关注本教程,尝试Flask SocketIO使用nginx和运行gunicorn.

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";

    }

}
Run Code Online (Sandbox Code Playgroud)

gunicorn_config.py

bind = '127.0.0.1:8000'
workers = 2
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

使用此配置,我的应用程序(不使用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);
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

1)这个变量应该指向什么地址?

2)我的配置(nginx,gunicorn)是否正确?

对不起,如果这个问题很愚蠢.我只是对这一切应该如何工作感到困惑.

谢谢你的帮助.

**更新**

nginx error.log当我尝试访问http://localhost/socket.io时,这是文件的输出.

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
Run Code Online (Sandbox Code Playgroud)

不知道这有多大帮助,但我不知道在哪里寻找额外的信息.

我也很好奇为什么我可以访问它:http://localhost/socket.io123abc

仍然得到一个Internal Server Error而不是Not Found错误?

我还supervisord.conf根据以下Miguel's答案更新了我的文件:

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
Run Code Online (Sandbox Code Playgroud)

/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.
Run Code Online (Sandbox Code Playgroud)

这个清单会持续一段时间..

Dav*_*ess 1

首先,我要提到的是,我根本不推荐使用 SocketIO。它在 WebSockets 上添加了一些有用的功能,但它使得多个工作线程之间的真正负载平衡(水平扩展)变得不可能,除非你让客户端粘在单个工作线程上或者使用 Redis 之类的东西在它们之间共享状态信息。我建议看一下:

\n\n

https://github.com/youen/gevent-websocket

\n\n

本机 WebSocket 更简单、更容易,并且可以跨多个前端工作人员进行扩展,以实现真正的负载平衡。实现聊天室逻辑所需的代码非常少。

\n\n

话虽如此,这是您问题的答案:

\n\n
\n

1)这个变量应该指向什么地址?

\n
\n\n

你的命名空间将是“”。(根据 Flask-SocketIO 的作者 Miguel 的说法,Javascript 客户端会自动插入“socket.io”部分。)

\n\n

因此,您的io.connect网址应该是“ http://[hostname]/ ”。

\n\n
\n

2)我的配置(nginx、gunicorn)是否正确?

\n
\n\n

Ngnix 配置似乎是正确的(尽管请参阅下一节)。如果您决定使用 WebSockets,您可以考虑添加proxy_read_timeout 3600;. 否则,除非你有一个闲聊协议,否则 Nginx 将每分钟丢弃一次 WebSocket(默认值)。(此外,根据 Miguel 的说法,SocketIO 有处理此问题的心跳。)

\n\n

Gunicorn 配置不正确。使用 SocketIO,您有几种选择:

\n\n
    \n
  1. 在gunicorn中设置,workers = 1以便每个SocketIO客户端都与同一个工作进程通信。
  2. \n
  3. 更改您的 nginx 配置以使用ip-hash命令,这将导致客户端通过客户端 IP 地址分配给工作人员。
  4. \n
  5. 使用 Redis 或其他一些数据库来允许每个工作人员共享状态信息(尽管尚不清楚是否有人可以为 Gevent SocketIO 提供该功能)。
  6. \n
\n\n

这些选择是被迫的,因为 SocketIO 使用有状态设置机制,当您尝试水平扩展时该机制会中断。有关更多信息,请参阅此问题:https ://github.com/abourget/gevent-socketio/issues/112

\n\n

这里有一个 SocketIO 文档的链接,也讨论了它:http ://socket.io/docs/using-multiple-nodes/

\n\n

如果您收到Internal Server Error则可能是某个地方记录了异常。尝试找到它并将其添加到您的问题中。

\n\n

请注意,您无法通过点击浏览器地址栏中的 URL \xe2\x80\x93 来测试这一点,浏览器默认情况下不会使用正确的 WebSocket 协议,并且不会为您做任何有用的事情。必须使用 Javascript API 设置 WebSocket 连接。

\n\n

另外,尝试使用端口号访问该 URL 会绕过 nginx - 这可能不是您想要做的。Nginx 通常侦听 80/443 并将请求转发到 localhost:8000(这称为“反向代理”设置)。

\n

  • 您的回答有很多不准确之处。*它在 WebSocket 上添加了一些有用的功能* Socket.IO 在常规 HTTP 和 WebSocket 上工作,它为每个客户端选择最佳传输。它还跟踪连接的用户,并允许服务器向所有用户或进入房间的用户组进行广播。对于 WebSocket,这些都不存在。*本机 WebSocket 更简单、更容易,并且可以跨多个前端工作人员扩展,而无需部署 Redis 之类的东西*当然,但这不是因为 WebSocket,而是因为没有广播/房间。 (2认同)