System Design 101:实时通信四件套——短轮询、长轮询、SSE 与 WebSocket 原理与实践

原创2026-10-01 09:42:381,704 阅读
文章标签:后端文档教程

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 请求,询问"有没有新数据?"。无论有没有新数据,服务器都会立即返回响应,浏览器根据响应内容决定是否更新页面。

工作流程:

  1. 浏览器设置定时器,周期性地发送 HTTP GET 请求;
  2. 服务器处理请求,返回当前最新数据(即使数据没有变化,也会正常返回);
  3. 浏览器解析响应,若发现新数据则更新界面,然后等待下一个周期。

优缺点:

  • 优点:实现最简单,就是普通的 HTTP 请求,任何服务器框架、任何网络环境(包括只能发起 HTTP 请求的受限网络)都能跑;
  • 缺点:大量请求是无意义的空轮询,服务器资源浪费严重;由于存在固定的轮询间隔,数据到达后最快也要等到下一个周期才能被拿到,实时性有限。

适用场景:对实时性要求不高、请求频率可以接受、基础设施受限的场景。仓库中的 轮询 vs Webhook 对比指南 对轮询有更详细的论述:轮询会反复检查外部服务,哪怕根本没有更新,属于资源密集型且低效的做法,但好处是开发者对"何时、如何获取数据"拥有完全的控制权。

三、浏览器单方面承担:长轮询(Long Polling)

核心思路:长轮询是短轮询的改进版。浏览器发起请求后,服务器不立即返回,而是把请求"挂起",直到有新数据到达时才返回响应;浏览器收到响应后立刻再发起下一个请求,形成一个"挂起 → 数据到达 → 响应 → 再挂起"的循环。

工作流程:

  1. 浏览器发送一个普通 HTTP 请求;
  2. 服务器收到请求后不立即响应,保持连接打开,等待新数据;
  3. 有新数据时,服务器立即返回该数据;
  4. 浏览器收到数据后,马上发起新的请求,重复上述过程。

优缺点:

  • 优点:相比短轮询,请求次数大幅减少(没有数据的空档期不产生请求),数据到达后能几乎即时地返回给浏览器,实时性显著提升;
  • 缺点:服务器需要长期维持大量挂起连接,对连接管理、超时处理(如 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 是全双工的(双方随时互发)。实际选型时,把"数据流向、实时性要求、基础设施约束、运维复杂度"四者放在一起权衡,就能找到适合你系统的那一种。

登录后查看全文
system-design-101