HTTP 长轮询(Long Polling)是一种在客户端与服务器之间维持实时通信的技术,它弥补了传统 HTTP 短轮询效率低下的缺陷,当我们将长轮询应用于负载均衡架构时,需要特别关注会话保持(Session Affinity/Sticky Sessions)以及连接状态的同步问题,以下是对 HTTP 长轮询负载均衡的详细解析。
核心机制回顾:什么是长轮询?
在理解负载均衡之前,必须明确长轮询的工作流程,这与传统的 HTTP 请求有本质区别:
- 客户端发起请求:客户端向服务器发送一个 HTTP 请求。
- 服务器挂起连接:服务器接收到请求后,如果当前没有新数据,不会立即返回响应,而是保持连接打开(挂起),直到有新数据产生或超时。
- 服务器返回响应:一旦有新数据或超时,服务器立即返回 HTTP 响应,包含数据或空响应。
- 客户端立即重连:客户端收到响应后,几乎立即再次发起新的长轮询请求。
这种机制使得服务器能够以“推送”的方式将数据发送给客户端,同时保持 HTTP 协议的无状态特性。
负载均衡中的关键挑战
在负载均衡(LB)环境下,长轮询面临两个主要挑战:
- 连接状态分散:由于 HTTP 是无状态的,如果负载均衡器将后续的轮询请求分发到不同的后端服务器,而数据只存在于某一台服务器上,客户端将无法收到预期的数据。
- 资源占用不均:长轮询会长时间占用服务器线程或连接资源,如果负载均衡器无法正确识别“活跃”连接,可能导致某些后端服务器过载,而其他服务器空闲。
解决方案:会话保持(Sticky Sessions)
为了解决上述问题,最常见的策略是启用基于 Cookie 或 IP 的会话保持。
1 工作原理
负载均衡器在第一次响应中设置一个特殊的 Cookie(如 SERVER_ID),或者记录客户端的源 IP 地址,后续来自同一客户端的请求,负载均衡器会将其转发到同一台后端服务器。

2 会话保持策略对比
| 策略类型 | 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Cookie 绑定 | LB 在响应中写入 Cookie,后续请求携带该 Cookie 被定向到特定后端。 | 精确控制,支持客户端 IP 变化(如 NAT 环境)。 | 需要客户端支持 Cookie;Cookie 可能被篡改或清除。 | 大多数 Web 应用,尤其是需要精细会话管理的场景。 |
| 源 IP 哈希 | LB 根据客户端源 IP 计算哈希值,固定映射到某台后端。 | 配置简单,无需客户端配合。 | 客户端 IP 变化(如移动网络切换)会导致连接中断;NAT 环境下多个用户可能映射到同一后端。 | 内部微服务通信,或 IP 相对固定的场景。 |
| 无会话保持 | 每次请求随机或轮询分发到不同后端。 | 负载均衡最均匀,无状态依赖。 | 长轮询场景下不可用,除非后端有共享存储(如 Redis)同步消息。 | 短轮询或非实时通信场景。 |
高级架构:共享消息队列模式
对于高并发、高可用的长轮询系统,单纯依赖会话保持可能带来单点故障风险(某台后端服务器宕机,所有长轮询连接丢失),更优雅的架构是引入中间件层:
- 客户端:发起长轮询请求到负载均衡器。
- 负载均衡器:将请求分发到任意可用的后端服务器(无需会话保持)。
-

后端服务器:
- 如果没有数据,将连接挂起,并将连接句柄注册到共享消息队列(如 Redis Pub/Sub、Kafka、RabbitMQ 或专门的 WebSocket 网关)。
- 如果有数据,直接返回。
- 消息发布者:业务逻辑产生数据时,将消息发布到共享消息队列。
- 后端服务器:监听消息队列,一旦收到针对该客户端的消息,立即唤醒挂起的 HTTP 连接并返回响应。
这种架构下,负载均衡器可以是完全无状态的,任意后端服务器宕机只会影响其当前挂起的连接,其他连接不受影响,且客户端重连后可被分发到任何存活的后端。
配置示例(Nginx)
以下是 Nginx 配置长轮询负载均衡的示例,重点展示了会话保持的配置:
upstream long_polling_backend {
# 使用 ip_hash 实现基于源 IP 的会话保持
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
server {
listen 80;
server_name example.com;
location /api/poll {
proxy_pass http://long_polling_backend;
# 增加超时时间,因为长轮询连接可能持续较久
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# 确保代理头正确传递
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_buffering off;
}
}
最佳实践与注意事项
- 超时机制:必须设置合理的超时时间(如 30-60 秒),如果服务器长时间无数据,应返回空响应或特定状态码,客户端收到后重新发起请求,这可以防止连接无限期挂起导致资源耗尽。
- 连接数限制:长轮询会占用大量并发连接,确保后端服务器和负载均衡器有足够的文件描述符(file descriptors)和内存资源。
- 客户端重试逻辑:客户端应实现指数退避重试机制,避免在网络波动时产生请求风暴。
- 监控与告警:监控挂起连接的数量、平均响应时间以及后端服务器的负载情况。

相关问题与解答
问题 1:在长轮询负载均衡中,如果启用了会话保持,某台后端服务器宕机,正在该服务器上挂起的长轮询连接会发生什么?客户端如何恢复?
解答:
当启用了会话保持(如 IP Hash 或 Cookie 绑定)时,如果某台后端服务器宕机,负载均衡器通常会将该服务器的健康状态标记为“不可用”。已经建立但尚未完成响应的长轮询连接会立即中断,因为服务器进程已停止。
客户端会收到连接错误(如 Connection Reset 或 Timeout),客户端的 JavaScript 代码应捕获该错误,并立即重新发起一个新的长轮询请求,由于负载均衡器检测到原服务器不可用,新的请求会被分发到其他健康的后端服务器,如果系统采用了“共享消息队列”架构,新服务器可以从队列中获取该客户端之前未收到的数据;如果仅依赖会话保持且无共享存储,客户端可能会短暂丢失部分实时数据,直到下一次轮询成功。
问题 2:为什么在长轮询场景中,Nginx 等反向代理需要配置 proxy_buffering off;?
解答:proxy_buffering off; 的作用是禁用 Nginx 对后端服务器响应的缓冲。
在长轮询中,服务器可能在连接挂起数秒甚至数十秒后才返回数据,如果启用了缓冲(默认开启),Nginx 会等待后端服务器发送完整的 HTTP 响应头和内容,将其存储在内存缓冲区中,然后再发送给客户端,这会导致两个问题:
- 增加延迟:Nginx 必须等待后端完全处理完并返回数据,才能开始向客户端传输,无法实现“即时推送”。
- 资源浪费:对于长连接,缓冲机制可能无法有效工作,反而增加内存开销。
禁用缓冲后,Nginx 会采用流式传输(Streaming),一旦后端服务器发送数据,Nginx 立即将其转发给客户端,从而保证实时性。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/487932.html