Haproxy socket.io websocket代理总是回退到长轮询

时间:2012-05-17 16:44:26

标签: python websocket socket.io tornado haproxy

嘿,我一直试图从socket.io

获取Haproxy代理websocket连接

我已经阅读了几乎所有我可以在谷歌上找到的东西,并尝试了haproxy.cfg的无数变种,但无论我尝试socket.io总是回到长轮询。

值得一提的是,如果我将连接直接路由到使用的套接字服务器,那么ws连接可以正常工作。

所以我使用socket.io客户端和tornado tornadio2 websocket服务器。我目前的haproxy.cfg取自haproxy example conf

defaults
mode    http

frontend all
bind 0.0.0.0:80
mode tcp

maxconn 200000
timeout client 86400000
default_backend www_backend

# Any URL beginning with socket.io will be flagged as 'is_websocket'
acl is_websocket path_beg /socket.io
acl is_websocket hdr(Upgrade) -i WebSocket
acl is_websocket hdr_beg(Host) -i ws

# The connection to use if 'is_websocket' is flagged
use_backend socket_backend_http if is_websocket

tcp-request inspect-delay 500ms
tcp-request content accept if HTTP   

backend www_backend
option httplog
option httpclose
balance roundrobin
option forwardfor
timeout server 30000
timeout connect 4000
server nginx localhost:81 weight 1 maxconn 1024 check

backend socket_backend_http
mode http
option httplog
option http-server-close
option forceclose
no option httpclose
balance roundrobin
option forwardfor 
timeout queue 5000
timeout server 86400000
timeout connect 86400000
timeout check 1s
server socket1 localhost:3012 weight 1 maxconn 1024 check

websocket请求正确路由到socket_backend_http,但浏览器控制台始终显示以下错误

Unexpected response code: 400

然后在短时间内按预期显示消息后,socket.io将回退到长轮询。 我已经使用最新版本的chrome,safari和firefox进行了测试,结果相同

我见过很多人说他们有这个让我感到绝望!我会永远感激能够解决这个问题的任何人。

再次只是为了澄清haproxy绑定到80,nginx在端口81上运行,套接字服务器在端口3012上运行。如果有人觉得查看套接字服务器会很有用请发表评论并且不应该修改发布代码

提前致谢

修改 当前的haproxy.cfg实际上是在龙卷风服务器中引发此错误

Traceback (most recent call last):
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-     packages/tornado/ioloop.py", line 399, in _run_callback
callback()
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/iostream.py", line 304, in wrapper
callback(*args)
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/httpserver.py", line 250, in _on_headers
self.request_callback(self._request)
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/web.py", line 1362, in __call__
handler._execute(transforms, *args, **kwargs)
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/web.py", line 992, in _execute
self._handle_request_exception(e)
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/web.py", line 1032, in _handle_request_exception
self.send_error(500, exc_info=sys.exc_info())
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/web.py", line 688, in send_error
self.finish()
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/web.py", line 669, in finish
self.request.finish()
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/httpserver.py", line 422, in finish
self.connection.finish()
File "/home/mike/.virtual-envs/watchdog-app/local/lib/python2.7/site-packages/tornado/httpserver.py", line 183, in finish
assert self._request, "Request closed"

更新

好的一些进一步的发展。我已经设法使用stunnel进行稍微不同的设置。所以nginx现在重新将http请求路由到https,其中它被拾取并且ssl连接被stunnel终止,然后stunnel将请求转发到haproxy选择它的端口8443上。套接字握手已经完成,一切都按预期工作,这很棒,但是我喜欢有人能够启发我为什么这可以用ssl工作而不用http !!!

4 个答案:

答案 0 :(得分:3)

我不能谈论Socket.io,但是SockJS经过测试并且在最近的haproxy(例如1.4.16)之后运行良好。请参阅示例配置:

我还没有找到一种在Nginx后面运行SockJS的方法。

答案 1 :(得分:2)

做了一些快速的研究 - 不是个人熟悉的,但我一直在使用SockJS并注意到了同样的行为。我至少发现Nginx与websockets不兼容,HAProxy需要工作才能找到工作。 haproxy and socket.io not fully working

示例配置与以下来源http://book.mixu.net/ch13.html的配置非常相似,看起来与您的配置相似99%。

https://github.com/mixu/sioconfig/blob/master/single.haproxy.cfg

我发现的另外两个花絮 - 来自HAProxy + WebSocket Disconnection

  • 确保您的HAProxy为1.4或更高
  • 确保您的socket.io版本为0.6.8或更高版本

答案 2 :(得分:1)

为了说清楚,WebSocket中没有HTTP内容,因此不需要任何内容​​长度标题。

此外,您的配置中存在错误。前端处于TCP模式,因此ACL仅在请求足够快时才匹配。事实上,有时它可能部分由纯粹的运气起作用。请将您的前端设置为“模式http”以解决此问题, 并删除无用的“tcp-inspect”规则。顺便说一下,你的“http-backend”也没有HTTP模式。

我猜你没有检查过日志,否则你可能会注意到它们在TCP中无法真正被利用: - /

答案 3 :(得分:0)

我知道这是一个老问题,但是:

Haproxy无法代理websockets(截至2013年6月)。 错误的原因我非常肯定是因为它看到它是一个正常的http连接并且连接时间。你可以让超时持续很长时间,但感觉很脏。

您的选择是:

  • Nginx版本1.4支持代理websockets,请参阅http://nginx.org/
  • 使用Nodejitsu的websocket代理http://blog.nodejitsu.com/http-proxy-intro(发现它泄漏了内存并在我们放置> 5k并发连接时失败了。)
  • 客户端平衡,例如使用server<n>.x.com
  • 使用亚马逊的route53做DNS roundrobin(我说亚马逊因为它支持健康检查,但如果你不需要HA就可以正常使用DNS)
  • 恐慌...

要记住的一点是,您还需要执行粘性会话或使用集中式会话存储。 SockJS比socket.io更容易,因为它会在每个会话的url中放置一个随机字符串,因此您可以根据url简单地进行平衡。您可以使用redis等集中存储来与Socket.io进行会话,我发现这些会议很笨拙。

Nginx和nodejitsu选项都可以为您终止SSL。

相关问题