实时通信 — WebSocket、gRPC 流式调用与 WebRTC
SSE、WebSocket、gRPC 流式调用还是 WebRTC
一句话总结
如果只有服务器在说话,就用 SSE;如果双方随时都要说话,就用 WebSocket;如果服务之间的契约很重要,就用 gRPC 流式调用;如果要在几十 ms 之内传送人的声音,就用 WebRTC。
为什么需要它
构建实时功能时,最先做出的决定就是传输通道,而且一旦选定就很难更改。因为客户端代码、认证方式、代理配置和观测工具,全都与这个选择绑在一起。可是这个决定往往是出于“现在大家都用 WebSocket”这样的理由做出的。把每种传输通道免费提供什么、又要你自己构建什么并排放在一起,选择就有了依据。
工作原理
HTML 标准中的 Server-Sent Events 是不结束一个普通的 HTTP 响应,而以 text/event-stream 持续写下去的方式。它是从服务器到客户端的单向通信,只传送文本。作为补偿,当浏览器的 EventSource 断开时会自动重新连接,并且标准中包含续传规则:通过 Last-Event-ID 头告知最后收到的事件编号。由于是普通的 HTTP,可以原样穿过代理和认证。LLM 的令牌流式 API 大多采用这种方式。不过 EventSource 无法附加自定义请求头,而且在 HTTP/1.1 中会受到浏览器每个域名的连接数限制(通常为 6 个)。在 HTTP/2 中,它们以流的形式叠加承载,这个限制就消失了。
WebSocket 是双向的,可以传送二进制,并且保持消息边界。作为代价,重新连接、续传、背压以及请求与响应的配对,全都要由应用程序自己构建。前面模块中亲手构建的序号、环形缓冲区和带抖动的退避就是这些。它以 HTTP/1.1 的 Upgrade 开始,所以中间设备必须放行 Upgrade。
gRPC 流式调用提供由 proto 确定的契约、截止时间、状态码、流量控制和重试策略。在服务之间的通信中,它免费提供的东西最多。但是浏览器没有处理 HTTP/2 trailer 的 API,所以无法直接使用 gRPC,而在中间设置转换层的 gRPC-Web 并不支持客户端流式和双向流式。
WebRTC 与前面三种不在同一个层次。它建立在 UDP 之上,可以丢弃迟到的数据,浏览器内置了 Opus 编解码器、抖动缓冲和回声消除,能以最短的延迟传送人的声音。作为代价,需要自己运维信令、ICE 和 TURN 服务器。
| 对比项 | SSE | WebSocket | gRPC 流式 | WebRTC |
|---|---|---|---|---|
| 方向 | 服务器 → 客户端 | 双向 | 四种形态 | 双向(对等端之间) |
| 浏览器 | 原生支持 | 原生支持 | 仅通过 gRPC-Web 部分支持 | 原生支持 |
| 重连与续传 | 标准中有 | 自行实现 | 自行实现(重试仅限于确定之前) | ICE 重启 |
| 丢弃迟到数据 | 不可 | 不可(TCP) | 不可(TCP) | 可以 |
| 运维负担 | 最小 | 中等 | 中等(代理需支持 HTTP/2) | 最大(TURN) |
再指出一个表中没有的。HTTP/3 之上的 WebTransport 是一个新的 API,让浏览器能同时使用 QUIC 流和不可靠数据报,它同时瞄准 WebSocket 简单的服务器结构和 WebRTC 丢弃迟到数据的能力。它还不能在所有浏览器和服务器配置中使用,所以要引入的话,需要先在目标环境中确认。即使出现新技术,选择时要问的问题也是一样的——方向、浏览器支持、能否丢弃迟到的数据,以及负责运维的人能否承受。
在现场相遇的样子
语音 AI 服务通常会混合使用两种以上。浏览器、手机与服务器之间的语音用 WebRTC,与服务器内部的识别、合成引擎之间用 gRPC 双向流式或 WebSocket,显示在屏幕上的字幕和令牌则用 SSE 或 WebSocket 传送。与其把传输通道统一成一种,不如为每一段选择所需要的特性——丢弃迟到数据、契约与截止时间、浏览器支持——效果更好。
认证和观测也会随传输通道而不同。SSE 和 gRPC 每个请求都有头部,所以可以原样使用现有的认证中间件和访问日志。WebSocket 在一次握手之后就没有头部了,对于令牌会过期的长连接,必须通过消息重新认证,或者断开连接后重新连接,并且需要自己构建以消息为单位的指标。
还有一些常见原因会迫使人推翻选择。公司内部的代理阻止了 WebSocket Upgrade,只好退回到 SSE;或者因为 UDP 被封的网络,要给 WebRTC 加上 TURN over TCP/TLS 443。从一开始就确认“这个网络里能不能用”,是选择传输通道的第一步。
下一项测验要做什么
针对每种情形选出合适的传输通道,并区分每种传输通道免费提供什么、需要自己构建什么。