← [ BACK_TO_NOTES ]

实时通信:SSE vs WebSocket vs Polling

把 SSE/WebSocket/轮询放在一起对比:通信方向、可靠性、基础设施约束与典型场景。

#synthesis #growing #network #browser #http #javascript

[!info] related notes

实时通信:SSE vs WebSocket vs Polling

范围

这篇是“选型关系笔记”,不重复解释每个概念的所有细节,只把关键差异、恢复边界与面试表达讲清楚。

心智模型:先选通信形状,再谈协议

不要先问“WebSocket 是否更高级”,先问业务的数据流是什么形状:

低频查询 / 对实时性要求不高
→ Polling

持续 server → client 文本/事件流
→ SSE / HTTP streaming

client ↔ server 双向高频通信
→ WebSocket

最关键的一句话:

SSE 和 WebSocket 的首要差别不是“谁性能更强”,而是通信方向和抽象是否匹配业务。

AI 文本生成通常是服务器持续向浏览器推送 token/event,浏览器并不需要在同一条长连接上持续高频上行,因此 SSE 往往已经足够。

抓住 4 个问题

  • 你需要双向吗?客户端是否也要持续、高频发消息?
  • 数据主要是文本事件还是需要二进制帧?
  • 实时性要求有多高,能不能接受周期性请求延迟?
  • 网络、代理、CDN、负载均衡是否会干扰长连接,断线后怎么恢复?

对比要点

SSE

  • 单向:server -> client
  • 基于 HTTP,典型媒体类型是 text/event-stream
  • 浏览器原生 EventSource 提供自动重连,并支持 Last-Event-ID 语义
  • 很适合模型流式输出、通知、日志、进度等持续服务端推送
  • 原生 EventSource 只支持 GET;如果业务必须 POST body 后再返回 SSE,可以使用 fetch() + ReadableStream 手动消费,此时重连/恢复逻辑通常要由应用自己实现

WebSocket

  • 双向全双工:client <-> server
  • 在 HTTP/1.1 场景通常先通过 HTTP handshake/Upgrade 建立 WebSocket 连接,之后传输 WebSocket frames
  • 浏览器 WebSocket API 本身不替应用提供完整自动重连、恢复和业务 replay 语义
  • 适合双方都持续高频交互的场景,例如 IM、协作编辑、实时游戏、语音控制等

[!note] 性能不要绝对化 不能简单说“WebSocket 一定比 SSE 更耗性能”。WebSocket 在高频双向、二进制、小帧通信时反而可能更合适;SSE 的优势主要是单向 HTTP 语义简单、和现有 HTTP 基础设施更自然。选型应看通信形状、恢复复杂度与基础设施,而不是只看协议名字。

Polling

  • 客户端周期性主动请求服务器
  • 不需要维持特殊长连接,基础设施兼容性好
  • 代价是额外请求开销,以及实时性受 polling interval 限制
  • 低频变化、恢复兜底、长连接环境不稳定时依然非常实用

AI 流式回答为什么常选 SSE

典型 Agent/LLM 回答:

user command
→ server starts Agent run
→ server continuously emits events/token deltas
→ browser renders progressively

主要方向是:

server → browser

因此 SSE/HTTP streaming 的抽象很贴合。WebSocket 当然也能实现,但如果客户端没有持续高频上行需求,就会承担额外的双向连接管理复杂度,却没有获得明显业务收益。

选 SSE 不等于“只要连接不断就行”

Production streaming 的关键问题不是永远不断线,而是:

连接可以断
但业务执行不能因此丢失
客户端还能恢复到服务器事实

如果架构只是:

LLM delta
→ SSE
→ Browser

连接在事件 5 后断开,而服务器继续产生 6..10,那么浏览器永久缺少 6..10。

因此可靠 Agent streaming 更适合:

Agent Event
   ↓
Durable Runtime Event Log
   ├──→ Live SSE(低延迟)
   └──→ Replay API(恢复)

见 Durable SSE Recovery with after_seq。

Seq / Cursor / Replay 的恢复模型

假设客户端已经成功应用:

seq 1, 2, 3, 4, 5

本地 high-water mark:

maxSeq = 5

断线后可以请求:

GET events?after_seq=5

服务端从 durable event log 返回:

6, 7, 8, 9, 10

然后客户端继续投影。

如果恢复结果因为 race/重试带回:

4, 5, 6, 7, 8, 9, 10

客户端必须根据稳定事件身份 / (run_id, seq) 去重,跳过已经应用的 4,5,否则 text delta、tool card、citation 或 side effect 都可能重复。

这和 TCP 序号“像”,但不是在重新实现 TCP

seq + after_seq 的直觉确实像 TCP sequence/cursor:双方需要知道“我已经可靠消费到哪里”。但应用层事件恢复解决的是不同问题:

TCP
→ 字节可靠、有序地从一条连接传输

Application Event Replay
→ 连接已经断过/进程可能重启后,恢复业务事件历史和 UI projection

TCP 不能替应用回答:

Agent run 是否仍在继续?
哪些事件已经 durable commit?
刷新页面后应该恢复到哪个业务状态?
重复 replay 是否应触发 side effect?

所以更准确的说法是:借用了“有序编号 + 已确认位置 + 从位置之后追赶”的思想,但恢复的是应用层事件,不是网络字节。

BodySense 当前实践

BodySense 当前不是使用原生 EventSource,而是 POST 请求返回 SSE,并由 fetch/ReadableStream 手动解析。因此它自己维护恢复协议:

Live SSE
→ StreamEvent.seq
→ maxSeq

transport disconnect / terminal not confirmed
→ GET /conversations/:conversationId/runs/:runId/events?after_seq=maxSeq
→ durable Runtime Event Log
→ ordered replay
→ skip seq <= maxSeq
→ same handlers / reducer

服务端查询语义是:

WHERE conversation_id = ?
  AND run_id = ?
  AND seq > after_seq
ORDER BY seq ASC

这体现了一个非常重要的分层:

SSE connection = low-latency transport
Runtime Event Log = durable recovery authority
Reducer/read model = client-visible projection

典型建议

  • 模型/Agent 回复逐字输出:优先 SSE 或 HTTP streaming
  • 双向高频协作、游戏、IM、实时控制:优先 WebSocket
  • 低频刷新、受限环境或恢复兜底:Polling 依然合理
  • 需要 Production-grade streaming:无论 SSE 还是 WebSocket,都要另外设计 durable identity、replay、dedup、terminal authority

面试 / 交流表述

“我不会简单用 WebSocket 替代所有实时通信。选型先看通信方向:如果是 LLM/Agent 这种主要 server-to-client 的持续文本事件流,SSE 更贴合 HTTP 语义;如果双方都需要持续高频通信,再考虑 WebSocket。真正的生产问题也不只是保持长连接,而是断线恢复,所以我会把 live transport 和 durable state 分开:事件先有稳定的 run identity/sequence,并落到可恢复的 event log;客户端记录已消费 cursor,断线后用 after_seq catch up,再对 replay 做去重。这样连接可以失败,但最终 projection 仍能收敛到服务器事实。”

最短记忆方式

Polling:我定期问“变了吗?”
SSE:服务器持续告诉我“发生了什么”
WebSocket:双方都可以持续说话

Production recovery:
transport 可以断,durable event 不应该丢;
seq 定位位置,after_seq 追赶,dedup 防重复。

下一步阅读

创建于 2026/3/16 更新于 2026/10/16
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本