实时通信协议选型速查:WebSocket、SSE、MQTT、WebRTC对比与落地实践
在做技术选型的时候,实时通信协议应该是被问得最多、也是最容易吵起来的话题之一。不管是做客服系统、直播弹幕、在线协作白板、设备状态上报,还是 AI 对话的流式输出,第一步碰到的都是同一个问题:我这个场景到底该用 WebSocket,还是 SSE,或者直接上 MQTT,再或者是 WebRTC?实时通信协议从来不是越高级越好,也不是性能越强越好,它是跟业务场景强绑定的。这篇内容不是教科书,是我这几年在多个项目里做协议选型和落地时整理的一份对比速查,适合正在做方案调研、准备动手写第一版原型的后端工程师、全栈开发以及架构师参考,能帮你省掉不少调研时间,也避开一些只有实战才能踩到的坑。
1. 实时通信协议为什么会让人纠结
1.1 选型背后的核心矛盾
很多项目一开始并不是技术问题,而是需求问题。你问业务方要什么,他只会说“数据要实时”,但“实时”这个词在不同场景下的含义差着十万八千里。股票行情里的实时可能是毫秒级,IM 聊天里的实时可能是 1 秒内能送达,物联网传感器上传温度可能延迟十几秒都能接受,而在线视频通话里超过 400 毫秒就会觉得卡顿。所以选型的第一步不是查文档,而是先量化和业务方对齐:可接受的端到端延迟到底是多少,是双向通信还是单向推送,客户端和服务端谁发起数据,数据量多大,网络环境是内网还是公网。这些约束直接决定了候选协议的范围。
另一个容易忽略的点是传输方向。很多刚接触实时通信的开发者会默认“实时 = WebSocket”,但实际上有一大类场景只是服务器想把新数据主动推给浏览器,比如新闻订阅、订单状态变化、日志实时滚动、AI Token 流式返回。这些场景用 SSE 就够了,根本不需要 WebSocket 的双向能力,更不需要自己去维护心跳和重连。反向来看,如果你要做的是游戏位置同步、多人协作编辑,那 SSE 的单向推送就无法满足,必须选一个客户端也能随时发消息的协议。把方向搞清楚,选择范围立刻缩小一大半。
1.2 协议不是越底层越高级
我的习惯是先看标准,再看生态,最后才看性能参数。HTTP、TCP、UDP 这些是传输层和协议层的基础,WebSocket、MQTT、WebRTC、gRPC 这些则是在基础之上为特定应用场景定做的协议。它们之间并不是简单的替代关系,更多时候是互补。比如 MQTT 底层走 TCP,但它在物联网场景里的价值不在传输本身,而在发布订阅模型、QoS 保障和遗嘱消息这些机制;WebRTC 底层主要走 UDP,但它提供的音视频编解码、抖动缓冲、NAC 和带宽预估能力,是直接在 UDP 上裸写逻辑很难替代的。
所以我建议在做对比速查的时候,不要只盯着“谁更快”,而是要看“谁为我的场景提供了更多现成能力”。WebSocket 在浏览器里原生支持、全双工、数据帧类型灵活,这是它的优势;但它不会帮你处理断线重连,也不会自动做消息幂等,这些都得上层自己写。选型之所以难,就是因为没有任何一个协议能同时把手握效率、实时性、可靠性、兼容性和开发成本全都做到最优,必须接受取舍。这个认知一旦建立,后面看对比表就会轻松很多。
2. 主流实时通信协议逐个拆解
2.1 WebSocket:实时应用的基本盘
WebSocket 是目前实时通信领域最通用的选择。它基于 TCP,通过一次 HTTP Upgrade 握手建立长连接,之后客户端和服务端可以随时向对方发送数据,而且是真正的全双工。我最早接触它是在做在线客服系统,当时的第一个版本用的是轮询,每 5 秒让前端拉一次最新消息,人一多服务器压力立刻上来,消息延迟也看运气。换成 WebSocket 之后,连接建立后服务器有新消息直接推给客服端,不仅延迟降到了百毫秒级,服务器压力反而变小了。
一个典型的 WebSocket 连接用 Node.js 搭起来非常简单,但生产环境远没有这么愉快。浏览器和服务端之间如果隔着 Nginx,就需要额外配置 Upgrade 头,不然连接会在代理层被截断。协议本身不提供心跳机制,如果网络中间设备静默断开了 TCP 连接,服务端可能长时间察觉不到客户端已经掉线,就会留下大量僵尸连接,导致内存和文件描述符泄漏。所以实际项目中我一般都会做三层保障:应用层心跳、空闲连接回收、断线重连与消息补偿。
WebSocket 最合适的是浏览器和 App 里中等数据量、高频率的双向消息场景,比如 IM、弹幕、在线文档协同、实时行情推送,以及对延迟敏感但不要求音视频级别的游戏对战消息。它的优势是浏览器原生支持、调试工具丰富、协议开销小;劣势是需要自己处理连接状态、重连、心跳、消息顺序和负载均衡下的连接粘连问题。说它是基本盘,是因为大多数实时项目确实是从它开始的。
2.2 SSE:服务器单向推送的低成本方案
很多开发者会低估 SSE,也就是 Server-Sent Events。它不需要独立的协议和端口,直接复用 HTTP,服务端按 text/event-stream 格式持续把数据推到客户端。浏览器里有现成的 EventSource 接口,最重要的是——它自带断线重连机制。这两个特点让 SSE 在“服务器单向推送”这个细分场景里几乎是成本最低的选择。
我在做日志实时查看功能的时候,对比过 WebSocket 和 SSE 两种方案。我们的需求很简单:用户在网页上触发一个任务,后端跑完之后把日志流水推给前端展示,用户基本不需要往服务器回传业务数据。用 WebSocket 也能做,但意味着前端要自己管理连接状态、心跳、重连和错误处理,工作量并不小。换成 SSE 之后,前端只需要几行代码:
SSE 有几个需要注意的坑。第一个是连接数量限制,HTTP/1.1 下浏览器对同一域名有 6 个连接上限,如果页面同时开了多个 SSE 连接,很容易撞上限导致后面的连接一直 pending。解决思路是用 HTTP/2 来多路复用,或者把多个推送流合并成一个连接,在消息里带业务标识做分发。第二个坑是反向代理缓冲,Nginx 默认会缓冲后端响应,导致前端收到的不是实时流而是一大块积累的数据,必须关掉该连接的缓冲参数。第三个坑是 SSE 不能跨域直连,需要后端配合 CORS 配置,或者用代理转发。
SSE 适合订单状态推送、优惠券到期提醒、AI 对话 Token 流式返回、日志面板、监控大屏这类服务端主动往客户端单向推送的场景。如果你的业务不需要客户端频繁回传数据,选 SSE 会比 WebSocket 省心很多,也更容易维护。
2.3 MQTT:物联网与弱网环境的头号选手
MQTT 是我在物联网项目里落地最多的协议,它跟 WebSocket、SSE 不是同一个赛道的东西。MQTT 的核心是发布订阅模型,客户端不直接互连,所有消息都通过 Broker 中转。客户端可以订阅主题,也可以向主题发布消息,Broker 负责路由。这个模型天然支持一对多推送、设备状态管理和消息过滤,非常适合传感器数据上报、远程控制指令下发、设备间通信这类场景。
MQTT 的 QoS 机制是选型时必须理解的。QoS 0 最多发一次,消息可能丢失,适合高频、可容忍丢数据的传感器数据;QoS 1 保证至少到达一次,但可能重复;QoS 2 保证只到达一次,开销最大、处理最慢。我在实际项目里经常看到有人无脑把 QoS 设成 2,结果设备一多 Broker 负载剧增,其实大多数遥测数据用 QoS 0 就够了,控制指令才需要 QoS 1 或 2。除了 QoS,还有两个容易被忽略但很好用的机制:保留消息和遗嘱消息。保留消息让新上线的设备立刻拿到 Broker 上最新一次的状态值,遗嘱消息则让设备异常掉线后自动广播一条离线通知。
MQTT 默认走 1883 端口,生产环境要改成 TLS 加密的 8883 端口。浏览器不能直接实现 MQTT 原生协议,但可以通过 WebSocket 端口做桥接,把 MQTT 数据包封装在 WebSocket 帧里传输。这种组合在物联网管理后台里很常见:设备用 MQTT 上报,浏览器用 MQTT over WebSocket 实时看数据。如果你在做的项目是硬件设备、车联网、智能家居、工业监控这类对带宽和功耗敏感的实时通信,MQTT 几乎是绕不开的标准答案。
2.4 WebRTC:音视频与 P2P 场景的硬核心
WebRTC 解决的是另一类问题:实时音视频通话、视频会议、屏幕共享、P2P 文件传输。它不需要中间服务器转发媒体流,浏览器之间可以直接建立连接传输数据。WebRTC 的底层主要走 UDP,配合 SRTP 做加密,内部实现了音视频编解码、抖动缓冲、丢包重传、拥塞控制等一系列能力。你直接用 WebSocket 也能传音视频数据,但延迟、卡顿和弱网表现会很难看,因为 WebSocket 基于 TCP,TCP 的拥塞控制和重传机制在弱网下会导致明显的延迟堆积,而音视频对延迟比对丢包更敏感。
WebRTC 上手成本是这几个协议里最高的。一个最简单的通话也需要完成几件事:信令服务交换 SDP 和 ICE 候选,获取本地媒体流,创建 RTCPeerConnection,处理 ICE 连接状态变化。信令本身协议没规定,通常用 WebSocket 或者 HTTP 传输。STUN/TURN 服务器也不可少,STUN 用于 NAT 穿透探测,TURN 则在穿透失败时中继流量。如果用户网络环境复杂,TURN 中继带宽会成为成本大头,这个必须提前在预算里算清楚。
除了音视频,WebRTC 的 DataChannel 也值得关注。它走的是和媒体流一样的传输通道,但传输的是任意数据,延迟比 WebSocket 低,而且天然 P2P。适合做多人实时对战、白板协同、远程遥控这类对延迟敏感的数据传输。不过它依然需要信令服务来建立连接,连接建立后如果传输的数据规模不大,可以考虑优先用 DataChannel,再退而求其次选 WebSocket。我的建议是:非音视频业务不要轻易碰 WebRTC,开发成本和排障成本都不低;一旦确实需要做音视频,它又是目前综合体验最好的选择。
2.5 gRPC 与 HTTP/3:服务端实时通信的新变量
gRPC 是基于 HTTP/2 的 RPC 框架,支持四种通信模式:普通一元调用、服务器流式、客户端流式、双向流式。因为底层是 HTTP/2,gRPC 天然支持多路复用,多个请求可以在同一个 TCP 连接上并发传输,配合 Protobuf 的高效二进制序列化,性能表现非常出色。它更适合服务端内部、服务端之间的实时通信,比如微服务架构里把日志、监控、事件流从 A 服务实时推到 B 服务。
gRPC 在浏览器里的支持一直是短板,虽然可以用 gRPC-Web 或者 Envoy 代理做适配,但使用体验和调试便利度都比不上原生 WebSocket。所以在对外的前端实时场景里我一般不用 gRPC,只有纯后端链路、数据量大、接口契约要求严格的场景才值得引入。gRPC 的双向流通信一旦建立,能保持长时间连接,服务端可以主动向客户端推送数据,这比轮询或者消息队列中转要直观得多。但要注意,HTTP/2 的长连接也意味着服务端需要管理连接生命周期,而且调试工具不如 HTTP 接口成熟,出了问题排障路径会变长。
HTTP/3 和 QUIC 是最近几年开始进入生产环境的新变量。QUIC 基于 UDP,头部和数据都加密,握手延迟比 TCP+TLS 低很多,还支持连接迁移,比如手机从 Wi-Fi 切到 4G 时连接不会断。CDN 厂商和部分头部互联网产品已经在大规模使用 HTTP/3 提升弱网场景的体验,但普通业务团队短期内可能还用不上,因为需要客户端和服务端同时对 QUIC 有完整支持。现阶段比较务实的态度是把它列为观察项,等基础设施成熟了再逐步灰度。
3. 横向对比速查:选型前先看这张表
3.1 核心场景对比速查表
收藏级内容往往不是长篇原理,而是一张能解决问题的表。我把上面几个主流协议放进同一个框架里,用真实项目里最关心的维度做了一次横向对比。这张表不追求面面俱到,而是在选型决策时更直观地看出候选协议的位置。
| 维度 | WebSocket | SSE | MQTT | WebRTC | gRPC |
|---|---|---|---|---|---|
| 通信方向 | 双向全双工 | 服务器到客户端单向 | 发布订阅双向 | P2P 双向 | 支持多种流式模型 |
| 传输层基础 | TCP | HTTP | TCP | UDP(SRTP/ICE) | HTTP/2 over TCP |
| 典型端到端延迟 | 百毫秒级 | 百毫秒到秒级 | 取决于 Broker,通常百毫秒级 | 毫秒到百毫秒级 | 毫秒到百毫秒级 |
| 浏览器原生支持 | 支持 | 支持 | 需 WebSocket 桥接 | 支持,需信令服务器 | 不支持,需 gRPC-Web |
| 流量与开销 | 中等 | 低 | 极低 | 较高,音视频流量大 | 较低,二进制序列化 |
| 服务端复杂度 | 中 | 低 | 中 | 高(信令/TURN) | 中高 |
| 断线重连 | 自建 | 原生支持 | 需客户端实现 | 需要应用层处理 | 需要应用层处理 |
| 弱网表现 | 一般 | 一般 | 较好 | 专门优化 | 一般 |
| 适合场景 | IM、弹幕、行情 | 状态推送、AI 流式输出 | 物联网、车联网 | 音视频、P2P | 服务端流式通信 |
3.2 决策逻辑:从业务约束倒推协议
拿到需求时,我会按一套固定的决策顺序来缩小范围。先把需要满足的硬约束列出来,比如延迟必须在 1 秒内、必须是双向通信、客户端是浏览器还是硬件设备、公网还是内网环境、团队对协议的熟悉程度、是否有多人同时在线等。然后按照下面的顺序过滤:
- 是不是音视频或 P2P 文件传输?是,优先 WebRTC。
- 客户端是不是硬件设备且需要低功耗低带宽?是,优先 MQTT。
- 是不是服务端之间的流式通信?是,考虑 gRPC。
- 还需要实时双向通信?是,考虑 WebSocket。
- 只需要服务器单向推送?是,考虑 SSE。
这套逻辑看起来很机械,但配合业务场景基本不会跑偏。最容易犯的错误是一开始就带入个人偏好,比如团队熟悉 WebSocket,于是所有数据都用 WebSocket 推,该用 SSE 的推送场景也硬上了 WebSocket,最后不只是开发成本高,线上维护也麻烦。反过来也一样,知道 MQTT 在物联网里好用,就把业务系统里的普通消息推送也搬过去,引入一个 Broker 结果反而复杂化了。
3.3 几个常见场景的标准答案
结合我自己的项目经验,整理几个出现频率最高的场景和对应的协议组合,给大家做参考。
IM 聊天系统:首选 WebSocket,并且用 Socket.IO 或类似库封装重连、心跳和事件分发,避免从零造轮子。客户端量级非常大时,可以前端连 WebSocket 网关,网关背后再接 Redis Pub/Sub 或消息队列做水平扩展。消息可靠顺序问题不能只靠协议,要设计消息序号和 ACK 机制。
股票行情推送:核心是低延迟,双向需求弱,WebSocket 仍然是主流,因为客户需要客户端发送查询请求、订阅指定标的。某些只做展示的行情面板用 SSE 也够,但涉及到订阅指令下发,SSE 就满足不了。
物联网传感器数据上报:设备数量多、数据频率高、带宽受限,用 MQTT 做上行,Broker 收到后写入时序数据库。如果同时要做浏览器端实时监控,前面加一层 MQTT over WebSocket 桥接即可。
AI 流式输出:大模型的中间结果要逐 token 推给前端,典型场景是 ChatGPT 对话流、AI 写作、语音识别结果实时显示。SSE 是最稳妥的选择,自带重连、实现简单,也能极大降低服务端连接管理的复杂度。如果要让客户端在流式过程中发送交互指令,比如停止生成、改变生成参数,那就得上 WebSocket。
4. 协议落地的坑与排查笔记
4.1 我踩过的五个真实问题
第一,WebSocket 连接数在 Nginx 后面一旦多了就频繁断开。排查下来是 Nginx 默认的 60 秒连接超时配置导致的,WebSocket 长连接空闲时会被服务端主动切断。解决方式是在代理配置里把 proxy_read_timeout 调大,同时让客户端主动发心跳,保持连接一直有流量。心跳设计要避开一个陷阱:心跳间隔不能大于代理层的超时时间,否则心跳也保不住连接。
第二,SSE 明明设置了定时推送,但前端接收到的却是一段一段的,不是逐条即时到达。这是 Nginx 的 proxy_buffering 在作怪,关掉响应缓冲之后数据就顺畅了。还有一个常见误配是后端框架的响应压缩,gzip 压缩也会导致数据攒到一定量才发出,要注意把流式接口的压缩策略单独处理。
第三,MQTT 设备频繁上下线,Broker 上看到的 session 一直堆积。这通常是客户端没有设置 clean_session 或者 session_expiry_interval,导致断线后的会话被保留。设备量大的时候,需要按设备类型区分会话策略:传感器类短连接设备适合短会话,控制类设备追求低延迟恢复才考虑持久会话。
第四,WebRTC 打洞成功率不高。公网环境下穿透失败率在 10%-20% 是正常的,网络环境越复杂越需要 TURN 兜底。遇到连接不上的问题,先通过 chrome://webrtc-internals 看 ICE 候选,确认是 Lhost 还是 Rhost 缺失,再决定是补 STUN 配置还是直接升级 TURN 带宽。别把 TURN 当成可有可无的选项,在不能保证网络环境的情况下,它是保证通话质量的最后防线。
第五,gRPC 双向流在生产环境出现“假死”现象,连接没有断开但数据不流动。问题出在 TCP 连接和 HTTP/2 保活机制上。gRPC 默认的 HTTP/2 ping 间隔很长,某些网络设备会把空闲连接回收掉。解决方案是在服务端和客户端同时开启 HTTP/2 keepalive,把 ping 间隔调短。
4.2 压测和上线前自查
协议选完,代码写完,上线前我一定会做这件事:压测。压测不是看并发能扛多少,而是要验证协议在目标负载下的表现是否符合选型预期。常用的工具是 wrk 配合自定义脚本去压 HTTP 场景,WebSocket 连接数可以用 wsbench,MQTT 可以用 mqtt-benchmark。不过压测工具只能模拟连接和数据量,真正重要的是观察服务端的资源消耗曲线。连接从 1000 涨到 5000 时,CPU、内存、线程、文件描述符各项指标要分开统计。
上线前的自查清单我觉得比压测触发的问题更实用。第一,所有连接是否启用了 TLS,生产环境不要裸奔用明文。第二,反向代理层的超时时间、缓冲开关、连接头是否配置正确。第三,服务端对连接数量是否有上限保护,防止单个客户端异常占用大量连接。第四,消息是否做了限流和大小限制,避免超大消息拖垮整个通道。第五,是否有完整的监控日志,包括连接建立、断开、重连、消息积压和数据量统计。这些项目看起来都很基础,但每一条我都遇到过失守导致事故的情况。
5. 最后说点我的实际体会
协议选型的洁癖是很常见的,但做了这么多项目之后我的体会是:选择实时通信协议,不要先想着炫技,而要先想着如何降低整个系统的复杂度。WebSocket、SSE、MQTT、WebRTC、gRPC 各有各的主场,它们之间完全可以共存。一个大型系统里同时出现 WebSocket 和 SSE 是很正常的事,因为不同模块的需求本来就不一样。真正该避免的,是某个团队因为熟悉某个协议就把所有实时功能都往上堆。踩坑踩得多了以后,我现在做选型时会额外问一个问题:三到六个月之后接手的同事,能不能快速看懂这套通信方案?如果方案先进到只有我一个人能维护,那就是失败的选型。最后再分享一个小技巧:不管最后选了哪个协议,都先做一个最小可用的 POC,把真实数据流跑通,再决定是否全面铺开。纸上对比十次,不如真实流量跑一遍。