4

我正在开发一个使用 websocket 处理程序的 Tornado 应用程序。我正在使用 Supervisord 运行该应用程序的多个实例,但在负载平衡 websocket 连接时遇到了问题。

我知道 nginx 不支持开箱即用的 websockets 处理,但我按照http://www.letseehere.com/reverse-proxy-web-sockets此处的说明使用 nginx tcp_proxy 模块来反向代理 websocket 连接。但是,这不起作用,因为模块无法路由 websocket url(例如:ws://localhost:80/something)。所以它不适用于我在 Tornado 应用程序中定义的 URL 路由。

从我对网络的研究来看,HAProxy 似乎是对我的 websocket 连接进行负载平衡的方法。但是,我无法找到任何体面的指导来设置 HAProxy 以负载平衡 websocket 连接并且还能够处理 websocket URL 路由。

我真的很感激一些关于如何做到这一点的详细指导。我也对其他解决方案完全开放。

4

4 回答 4

5

在 haproxy 中实现 WebSocket 并不难,尽管我承认在这方面找到文档并不容易(希望这个响应会成为一个例子)。如果您使用的是 haproxy 1.4(我想您是),那么它就像任何其他 HTTP 请求一样工作,无需执行任何操作,因为 HTTP 升级已被 haproxy 识别。

如果您想将 WebSocket 流量定向到与 HTTP 的其余部分不同的场,那么您应该使用内容切换规则,简而言之:

前端 pub-srv
    绑定:80
    use_backend websocket if { hdr(Upgrade) -i WebSocket }
    default_backend http

 后端网络套接字
    服务器超时 600s
    服务器节点1 1.1.1.1:8080 检查
    服务器节点2 2.2.2.2:8080 检查

 后端http
    服务器超时 30s
    服务器 www1 1.1.1.1:80 检查
    服务器 www2 2.2.2.2:80 检查

如果您使用的是 1.5-dev,您甚至可以指定“超时隧道”以使 WS 连接的超时时间大于普通 HTTP 连接的超时时间,从而避免在客户端使用过长的超时时间。

您还可以结合 Upgrade: WebSocket + 一个特定的 URL :

前端 pub-srv
    绑定:80
    acl is_websocket hdr(升级) -i WebSocket
    acl is_ws_url 路径 /something1 /something2 /something3
    use_backend websocket if is_websocket is_ws_url
    default_backend http

最后,请不要使用我们有时看到的愚蠢的 24 小时空闲超时,现在等待客户端 24 小时建立会话绝对没有意义。与 80 年代相比,网络移动性更强,连接也非常短暂。你最终会得到许多 FIN_WAIT 套接字。10 分钟对于当前的互联网来说已经相当长了。

希望这会有所帮助!

于 2012-06-05T21:49:11.820 回答
0

WebSockets 不能很好地遍历代理,因为握手之后它们没有遵循正常的 HTTP 行为。

尝试使用 WebSocket (wss://) 协议(安全 WS)。这将使用 Proxy CONNECT API,它将隐藏 WebSocket 协议。

于 2012-06-05T14:30:45.163 回答
0

我使用https://launchpad.net/txloadbalancer使用 Tornado websocket 处理程序进行负载平衡。这很简单而且效果很好(我认为)。

于 2012-10-10T15:53:12.247 回答
0

http nginx(仅 nginx v1.3+)

upstream chatservice {
    #multi thread by tornado
    server 127.0.0.1:6661;
    server 127.0.0.1:6662;
    server 127.0.0.1:6663;
    server 127.0.0.1:6664;
}
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

虚拟主机

server {
    listen 80;
    server_name chat.domain.com;
    root /home/duchat/www;
    index index.html index.htm;

    location / {
            try_files $uri $uri/ @backend;
    }
    location @backend {
            proxy_pass_header Server;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_pass http://chatservice;
            internal;
}
于 2014-12-07T10:21:18.850 回答