System Design 101:实时通信四件套——短轮询、长轮询、SSE 与 WebSocket 原理与实践
System Design 101:实时通信四件套——短轮询、长轮询、SSE 与 WebSocket 原理与实践
HTTP 服务器无法主动向浏览器发起连接,浏览器永远是请求的发起方。要在这种"请求-响应"模型下实现实时数据更新,工程上主要有两条路线:让浏览器承担更多工作(短轮询、长轮询),或者让浏览器与服务器协同配合(SSE、WebSocket)。本文基于 system-design-101 仓库中的 实时更新机制指南 展开,梳理四种方案的原理、优缺点与适用场景,帮助你为聊天、通知、行情推送等场景选型,并在系统设计面试中给出有理有据的回答。
一、问题根源:HTTP 的"无主动推送"限制
HTTP 协议从设计之初就是典型的"请求-响应"模型:客户端(浏览器)发起请求,服务器返回响应,然后连接结束。服务器永远无法主动向浏览器推送数据——它只能在收到请求后应答。
这意味着,当服务器上有新数据(例如一条新消息、一个价格变动)时,浏览器并不会自动收到通知。要获得实时更新,就必须由浏览器主动想办法去"取",或者换一种能让服务器"送"上门的连接机制。仓库中的 8 个常用网络协议图解 也印证了这一点:与始终"拉取"数据的 REST 不同,WebSocket 等机制让数据可以"被推送"。
围绕"谁来干活"这个问题,业界演化出了两类四种方案:
| 责任归属 | 方案 | 数据流向 | 实现难度 |
|---|---|---|---|
| 浏览器单方面承担 | 短轮询(Short Polling) | 单向(拉) | 最低 |
| 浏览器单方面承担 | 长轮询(Long Polling) | 单向(拉,但服务器延迟响应) | 低 |
| 浏览器与服务器协作 | SSE(Server-Sent Events) | 单向(推) | 中 |
| 浏览器与服务器协作 | WebSocket | 双向(全双工) | 较高 |
二、浏览器单方面承担:短轮询(Short Polling)
核心思路:浏览器按固定时间间隔(例如每 5 秒)向服务器发送普通 HTTP 请求,询问"有没有新数据?"。无论有没有新数据,服务器都会立即返回响应,浏览器根据响应内容决定是否更新页面。
工作流程:
- 浏览器设置定时器,周期性地发送 HTTP GET 请求;
- 服务器处理请求,返回当前最新数据(即使数据没有变化,也会正常返回);
- 浏览器解析响应,若发现新数据则更新界面,然后等待下一个周期。
优缺点:
- 优点:实现最简单,就是普通的 HTTP 请求,任何服务器框架、任何网络环境(包括只能发起 HTTP 请求的受限网络)都能跑;
- 缺点:大量请求是无意义的空轮询,服务器资源浪费严重;由于存在固定的轮询间隔,数据到达后最快也要等到下一个周期才能被拿到,实时性有限。
适用场景:对实时性要求不高、请求频率可以接受、基础设施受限的场景。仓库中的 轮询 vs Webhook 对比指南 对轮询有更详细的论述:轮询会反复检查外部服务,哪怕根本没有更新,属于资源密集型且低效的做法,但好处是开发者对"何时、如何获取数据"拥有完全的控制权。
三、浏览器单方面承担:长轮询(Long Polling)
核心思路:长轮询是短轮询的改进版。浏览器发起请求后,服务器不立即返回,而是把请求"挂起",直到有新数据到达时才返回响应;浏览器收到响应后立刻再发起下一个请求,形成一个"挂起 → 数据到达 → 响应 → 再挂起"的循环。
工作流程:
- 浏览器发送一个普通 HTTP 请求;
- 服务器收到请求后不立即响应,保持连接打开,等待新数据;
- 有新数据时,服务器立即返回该数据;
- 浏览器收到数据后,马上发起新的请求,重复上述过程。
优缺点:
- 优点:相比短轮询,请求次数大幅减少(没有数据的空档期不产生请求),数据到达后能几乎即时地返回给浏览器,实时性显著提升;
- 缺点:服务器需要长期维持大量挂起连接,对连接管理、超时处理(如 HTTP 连接超时导致请求被中途断开,需要客户端重连)要求更高;每次请求仍是一次完整的 HTTP 往返,存在额外的头部开销。
适用场景:历史上常用于聊天、通知等需要较高实时性、但又不想引入 WebSocket 的场合。它本质上是"用 HTTP 模拟推送"的过渡方案。
四、浏览器与服务器协作:SSE(Server-Sent Events)
核心思路:SSE 是建立在 HTTP 之上的单向推送机制。浏览器通过 EventSource API 建立一条持久的 HTTP 连接,服务器可以在连接建立后持续不断地把最新数据直接推送给浏览器,浏览器无需反复请求。
关键特性:
- 单向(uni-directional):数据只能从服务器流向浏览器,浏览器不能在连接建立后向服务器发送新的请求;
- 基于普通 HTTP/HTTPS,天然兼容现有的代理、负载均衡、鉴权体系,不需要额外的握手协议;
- 支持自动重连:连接断开后浏览器会自动重新建立连接;
- 支持事件类型(
event字段)、id(断点续传)等机制,便于客户端做增量处理。
优缺点:
- 优点:实现相对简单(服务器端只需保持响应流不关闭),自动重连省去大量客户端状态管理,适合"服务器 → 浏览器"单向更新场景,如行情推送、进度通知、系统状态播报;
- 缺点:单向通信,浏览器无法通过同一条连接向服务器发送数据;单条连接对并发连接数有上限(浏览器通常限制同域连接数),且传统 SSE 基于 HTTP/1.1 时连接数受限明显。
适用场景:新闻推送、股票/币价行情、任务进度、日志流等"只需下行"的实时场景。
五、浏览器与服务器协作:WebSocket
核心思路:WebSocket 是建立在 TCP 之上的全双工(fully-duplex)通信协议。浏览器与服务器通过一次 HTTP 升级握手(Upgrade: websocket)建立持久连接,此后双方可以随时互相发送消息,不再受"请求-响应"约束。
关键特性:
- 双向:浏览器可以继续向服务器发送新请求/消息,服务器也可以主动推送,两端地位对等;
- 一条持久连接承载双向流量,避免了频繁的 HTTP 头部开销;
- 基于 TCP 长连接,适合高频、低延迟的双向交互。
优缺点:
- 优点:真正的实时双向通信,延迟最低,适合聊天、在线游戏、协作编辑、股票交易等高频交互场景;
- 缺点:需要专门的协议支持(服务端、客户端、网关、负载均衡都要能处理 WebSocket 握手与长连接);连接保活、心跳、断线重连、横向扩展(如多实例下的连接路由)都要自己设计,复杂度明显高于前三种方案。
仓库中多处案例印证了 WebSocket 在真实系统中的地位:
- Slack 消息旅程:Slack 的消息接收端通过 Gateway Server 维护 WebSocket 通道订阅,消息接收方使用 WebSocket 这一"双向消息机制"实时接收更新,并由 Envoy 作为云原生代理转发;
- 如何设计 Google Docs:客户端把文档编辑操作发送给 WebSocket 服务器,由它处理实时通信,操作再进入消息队列、经协作算法(OT/CRDT 等)转换后持久化,实现多人实时协作;
- 8 个常用网络协议图解:明确将 WebSocket 定义为"基于 TCP 的全双工通信协议",并指出在线游戏、股票交易、消息应用都靠它实现实时通信。
六、四大方案横向对比与选型建议
| 维度 | 短轮询 | 长轮询 | SSE | WebSocket |
|---|---|---|---|---|
| 数据方向 | 浏览器拉取 | 浏览器拉取(服务器延迟响应) | 服务器单向推送 | 双向全双工 |
| 实时性 | 取决于轮询间隔 | 高(数据到达即返回) | 高(持续推送) | 最高 |
| 请求开销 | 最高(大量空请求) | 中(空闲期无请求) | 低(单条长连接) | 低(单条长连接) |
| 服务器压力 | 低但浪费 | 需维持大量挂起连接 | 需维持长连接 | 需维持长连接,复杂度最高 |
| 实现难度 | 最低 | 低 | 中 | 较高 |
| 典型场景 | 低实时性轮询 | 传统聊天/通知 | 行情、进度、日志流 | 聊天、游戏、协作编辑 |
选型逻辑:
- 实时性要求不高、只想简单实现 → 短轮询;
- 想要更高实时性、但基础设施不允许引入新协议 → 长轮询;
- 只需要"服务器 → 浏览器"单向更新、希望自动重连、想沿用 HTTP 生态 → SSE;
- 需要双向高频交互(消息、协作、交易)→ WebSocket。
此外,如果你的目标是"收到通知"而非"保持连接",还可以参考仓库中的 轮询 vs Webhook 与 API 架构风格对比速查表:Webhook 相当于让外部服务在事件发生时主动回调你的接口,是"推送"思想在 HTTP 之外的另一种落地方式;而 API 协议演进 也把 WebSocket 列为现代六大 API 协议之一。
七、小结
回到最初的问题——HTTP 服务器不能主动连接浏览器,那么实时更新如何实现?答案取决于谁承担更多工作:短轮询与长轮询把主动权完全交给浏览器,其中长轮询通过"挂起请求直到有数据"大幅改善了实时性与资源效率;SSE 与 WebSocket 则让浏览器与服务器协作,连接建立后服务器即可直接推送,区别在于 SSE 是单向的(浏览器无法在连接上发新请求),而 WebSocket 是全双工的(双方随时互发)。实际选型时,把"数据流向、实时性要求、基础设施约束、运维复杂度"四者放在一起权衡,就能找到适合你系统的那一种。