要让Apache负载均衡集群稳定支持WebSocket并保持粘滞会话,必须协同启用mod_proxy、mod_proxy_balancer、mod_proxy_wstunnel模块,配置带route的后端集群与stickysession绑定,透传Connection和Upgrade头,并延长Timeout与ProxyTimeout至3600秒,同时后端需配合生成含路由后缀的会话Cookie。

要让 Apache 负载均衡集群稳定支持 WebSocket 并保持粘滞会话,关键不是简单开启代理,而是模块协同、协议识别、路由绑定、超时控制四者齐备。WebSocket 是长连接、单会话生命周期的协议,一旦请求被轮询分发到不同后端,就会因上下文丢失而断连。下面分四步讲清实操要点。
启用必要模块并验证加载
Apache 必须同时加载以下模块,缺一不可: - mod_proxy:反向代理基础 - mod_proxy_balancer:负载均衡集群管理 - mod_proxy_wstunnel:唯一能正确处理 WebSocket 升级(Upgrade: websocket)的隧道模块 - mod_proxy_http(可选,但推荐保留,便于健康检查等 HTTP 交互)检查方式(Ubuntu/Debian):
a2enmod proxy proxy_balancer proxy_wstunnel proxy_http systemctl reload apache2
验证是否生效:
httpd -M | grep -E "(proxy|wstunnel)"
输出中应含 proxy_module, proxy_balancer_module, proxy_wstunnel_module, proxy_http_module。若缺失 proxy_wstunnel,WebSocket 握手虽可能成功,但后续帧传输必然异常。
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
定义带 route 的后端集群 + stickysession 绑定
WebSocket 粘滞不能靠 IP(易受 NAT/CDN 干扰),必须基于应用层路由标识。配置需满足三点: - 每个 BalancerMember 显式声明 `route=xxx` - ProxyPass 中启用 `stickysession`,值与后端生成的 Cookie 名严格匹配(如 `JSESSIONID` 或自定义 `ROUTEID`) - 后端服务(如 Tomcat、Spring Boot)必须在 Set-Cookie 响应头中附带 `.node1` 这类路由后缀示例配置:
<Proxy balancer://wscluster>
BalancerMember ws://192.168.1.10:8080 route=node1
BalancerMember ws://192.168.1.11:8080 route=node2
</Proxy>
ProxyPass /ws/ balancer://wscluster/ws/ stickysession=JSESSIONID|jsessionid nofailover=Off
ProxyPassReverse /ws/ balancer://wscluster/ws/注意:
-
ws://协议前缀不可替换为http://,否则走错模块,连接静默中断 -
stickysession=JSESSIONID|jsessionid支持大小写变体,防客户端篡改 -
nofailover=Off允许故障时自动切到其他节点,避免用户卡死
透传协议头并延长超时时间
WebSocket 握手依赖两个 hop-by-hop 头:`Connection: upgrade` 和 `Upgrade: websocket`。默认情况下,mod_proxy 会过滤它们。需显式放行: ```apache RequestHeader set Connection "upgrade" RequestHeader set Upgrade "websocket" ProxyPreserveHost On ``` 同时,Apache 默认 `Timeout 60` 和 `ProxyTimeout 60` 会主动关闭空闲连接。WebSocket 长连接需大幅延长: ```apache Timeout 3600 ProxyTimeout 3600 ``` 建议仅在 WebSocket 专用 `后端配合与验证要点
粘滞会话是前后端协作结果,仅 Apache 配置无法闭环: - Tomcat:在 `server.xml` 的 `验证方法:
- 浏览器开发者工具 → Network → 查看登录后响应头中的
Set-Cookie是否含.node1 - 连接 WebSocket 后,持续发送 ping,观察后端日志是否始终来自同一实例
- 故意停掉 node1,确认新连接落到 node2,且已有连接不受影响(
nofailover=Off生效)
不复杂但容易忽略。

















