消息不丢不重的三层保障
「消息必达」不是一句口号,而是三个互相兜底的机制叠加:落库应答、会话序号去重补拉、离线推送兜底。缺一层,弱网下就会出问题。
在 IM 系统里,丢消息和重复消息是最容易被用户投诉、也最难复现的两类问题。它们几乎都发生在同一个场景:网络抖动、切换、断线重连。
要在这个场景下保持正确,需要三层机制同时生效。
第一层:先落库,再应答
客户端发出消息后,服务端必须先把消息持久化到多个副本,再返回发送成功的确认。如果先应答后落库,一旦节点故障,用户看到「已发送」但对方永远收不到。
这一层的代价是发送延迟略高,但换来的是「已发送」这三个字可信。
第二层:会话序号 + 补拉
每个会话维护单调递增的序号。客户端按序号判断连续性:发现缺口就向服务端补拉区间消息;收到重复序号直接丢弃。
这套机制让「断线期间的消息」和「重连后的重复消息」都能被自动修正,而不依赖客户端做复杂的本地状态管理。
第三层:离线推送兜底
当长连接不可用(应用被杀、系统限制后台)时,离线推送是唯一能触达用户的手段。它的作用是提醒,不是传输——用户点开应用后仍然走补拉流程,因此不会因为推送丢失而丢消息。
三层为什么要一起做
只做落库,断线期间的消息无法补齐;只做序号补拉,进程被杀时用户根本不知道有新消息;只做推送,推送本身不可靠。三层叠加,才构成「不丢不重」的闭环。
判断一套 IM 是否可靠,问一句就够:断线重连之后,客户端怎么知道该补哪一段消息?