之前用Haproxy 来转发Shadowsocks 的流量时遇到一个问题,现象是在使用Slack 的时候(聊天使用了Websocket),频繁重连。凭直觉是由于Haproxy 的某一项timeout 设置的不合理导致的。
Websocket 协议可以分为2个阶段,先用HTTP 握手,然后建立长连接,通过ws 协议进行通信。将Haproxy 作为中继时,在建立长连接之后,Haproxy 就转入tunnel 模式:
TUN:tunnel(option http-tunnel):这是 1.0 ~ 1.5-dev21 的默认模式,类似于隧道,HAProxy 仅处理第一个请求和响应,剩余的报文将直接转发而不进行处理。尽量不要使用这个模式,因为它在日志记录和 HTTP 处理上有很多问题。 --来源:liaoph.com
涉及到的timeout 见下图:
图片来源:www.yuangguo.info
我们遇到的需要频繁重连的情况,其实是由于timeout tunnel 设置不合理导致的。官方给的关于timeout tunnel 的解释:
Set the maximum inactivity time on the client and server side for tunnels.
The tunnel timeout applies when a bidirectional connection is established between a client and a server, and the connection remains inactive in both directions. This timeout supersedes both the client and server timeouts once the connection becomes a tunnel. In TCP, this timeout is used as soon as no analyser remains attached to either connection (eg: tcp content rules are accepted). In HTTP, this timeout is used when a connection is upgraded (eg: when switching to the WebSocket protocol, or forwarding a CONNECT request to a proxy), or after the first response when no keepalive/close option is specified......
另外官方给出了一个配置示例:
defaults http
option http-server-close
timeout connect 5s
timeout client 30s
timeout client-fin 30s
timeout server 30s
timeout tunnel 1h # timeout to use with WebSocket and CONNECT
把中继的Haproxy 的这项值设为1h,解决了Slack 会频繁重连的问题。
参考: - Setup a Shadowsocks relay - Haproxy之websocket的负载均衡方案 - HAProxy 反向代理的使用