本文引用了45岁老架构师尼恩的技术分享,有修订和重新排版。
1、引言
接上篇《如何保障分布式IM聊天系统的消息有序性(即消息不乱)》,本文主要聚焦分布式IM聊天系统消息可靠性问题,即如何保证消息不丢失。

2、系列文章
为了更好以进行内容呈现,本文拆分两了上下两篇。
本文是2篇文章中的第 1 篇:
本篇主要聚焦的是分布式IM聊天系统消息可靠性问题。
3、痛点拆解:聊天消息总是丢?不是网络差,是设计没兜底
产品做着做着,用户开始投诉:"我明明发了消息,对方怎么没收到?"。你查日志发现------消息真丢了。但更可怕的是:你也不知道它什么时候丢的。
这背后,其实是移动场景下的经典三连击:
- *1)*地铁进隧道,网络闪断;
- *2)*App 被系统杀掉,进程没了;
- *3)*对方服务器刚好在发布,接口500......
你以为只是"发一下",其实要穿越重重险境才能抵达。
结果就是:
消息发不出去 → 用户以为被无视;
或者重试太多 → 对方收到一堆重复"在吗?";
最后用户体验崩了,客服工单爆了。
所以问题本质不是"快不快",而是:
"宁可慢点,也不能丢;就算重发,也不能重复。"
这就是我们常说的可靠消息投递 ------一个看似简单的需求,却是高可用系统的分水岭。
4、解决方案:三层兜底,像保险一样层层防
光靠"发一次"肯定不行。
我们要学保险公司,给关键消息上三重保险:
- *1)*自己先复印一份存档 → 客户端本地存
- *2)*邮局签收后锁进保险柜,并异地备份 → 服务端落盘 + 副本
- *3)*如果没收到回执,隔段时间再寄,但对方只认一次 → 超时重试 + 幂等去重
每一层都不贵,合起来却能扛住99%的异常。下面看每层怎么落地。
5、第一层:客户端兜底 ------ 消息先存本地,解决网络不稳定问题
**记住一句话:**只要没收到 ACK,就当没发成功。
所以第一步不是联网,而是先把消息塞进手机本地数据库(比如 SQLite)。
就像下面这样:
db.saveLocalMsg(msg); // 先落库,保命
boolean sendOk = network.send(msg);
if (!sendOk) {
scheduleRetry(msg, 1000); // 发失败?排队重试
}
再加上客户端scheduleRetry 采用阶梯式重试策略:
- *1)*第1次失败 → 1秒后重试
- *2)*第2次失败 → 3秒后重试
- *3)*第3次失败 → 5秒后重试
避免雪崩式刷屏,既保障可靠性,又不压垮服务。只有等到服务端明确说"我收到了",才把这条消息从本地删掉。
就像快递发货单:客户签收了,你才能撕票。
这样哪怕 App 崩溃、手机重启,下次打开照样继续发------用户体验无缝衔接。而如果不做这一步?一旦断网或崩溃,消息直接蒸发,用户永远不知道。
6、第二层:服务端兜底 ------ 实现 服务端持久化的高可靠
客户端发来了,服务端能不能直接处理完就返回?绝对不行!
如果此时机器宕机,消息还在内存里没来得及持久化,那就真的丢了。
正确做法是两步走:
- *1)*收到消息立刻写入 RocketMQ(支持刷盘、集群同步);
- *2)*同步复制到至少3个副本节点,确保单点故障不丢数据。
伪代码如下:
rocketMQ.send(msg); // 必须落盘,断电也不怕
replicaService.syncTo3Replicas(msg); // 多副本容灾
response.sendAck(msg.getUniqueKey()); // 此时才能回 ACK
**这一步的关键是:**ACK 必须在落盘之后发!否则就是"虚假确认",等于骗客户端"我收到了",其实自己也没保住。
这一层扛住了服务端单机崩溃的风险,是整个链路的数据基石。
7、第三层:幂等性设计 ------ 保障exact one
前面两层解决了"存得住"的问题,但这还不够。现实是:网络可能超时、包可能丢失、ACK 可能没传回来。
于是客户端必须重试。但重试带来新问题:
"我已经处理过了,再来一遍怎么办?"
**解决办法是:**用唯一键 + 幂等控制。
每个消息生成全局唯一的 key(如 sessionID:msgID),服务端通过 Redis 的原子操作判断是否已处理。
就像下面的代码这样:
String uniqueKey = msg.getUniqueKey();
if (redis.setNx(uniqueKey, "processed", 86400)) {
processMsg(msg); // 第一次来,正常处理
} else {
log.info("重复消息,忽略:{}", uniqueKey);
}
**setNx 是关键:**只有 key 不存在时才设置成功,保证多实例并发下也不会重复消费。
8、IM消息可靠性架构的核心流程总结
上面三层如何联动?一张图讲清楚全链路生命周期:

**整条链路形成闭环:**任何环节出问题,都有对应兜底机制接管。
9、本文小结
至此,《如何保障分布式IM聊天系统的消息有序性和可靠性》这期文章的上下两篇就完结了(上篇点此查看),上篇涉及到的分布式IM聊天系统架构中关于消息有序性问题,下篇则主要聚焦的是消息可靠性问题。
如果你是IM开发新人,想要系统地学习移动端IM开发的话,建议从我整理的这篇《新手入门一篇就够:从零开发移动端IM》开始,这样能保证IM开发知识能从网络到应用层、再从局部设计到整体架构,都有一个系统的学习脉络而不是在信息碎片中苦苦总结。
10、参考资料
1\] [什么是IM聊天系统的可靠性?](http://www.52im.net/thread-3182-1-1.html "什么是IM聊天系统的可靠性?") \[2\] [什么是IM聊天系统的消息时序一致性?](http://www.52im.net/thread-3189-1-1.html "什么是IM聊天系统的消息时序一致性?") \[3\] [微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)](http://www.52im.net/thread-1998-1-1.html "微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)") \[4\] [马蜂窝旅游网的IM系统架构演进之路](http://www.52im.net/thread-2675-1-1.html "马蜂窝旅游网的IM系统架构演进之路") \[5\] [一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等](http://www.52im.net/thread-3445-1-1.html "一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等") \[6\] [从新手到专家:如何设计一套亿级消息量的分布式IM系统](http://www.52im.net/thread-3472-1-1.html "从新手到专家:如何设计一套亿级消息量的分布式IM系统") \[7\] [企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等](http://www.52im.net/thread-3631-1-1.html "企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等") \[8\] [融云技术分享:全面揭秘亿级IM消息的可靠投递机制](http://www.52im.net/thread-3638-1-1.html "融云技术分享:全面揭秘亿级IM消息的可靠投递机制") \[9\] [阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践](http://www.52im.net/thread-3706-1-1.html "阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践") \[10\] [阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计](http://www.52im.net/thread-4012-1-1.html "阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计") \[11\] [基于实践:一套百万消息量小规模IM系统技术要点总结](http://www.52im.net/thread-3752-1-1.html "基于实践:一套百万消息量小规模IM系统技术要点总结") \[12\] [一套分布式IM即时通讯系统的技术选型和架构设计](http://www.52im.net/thread-4564-1-1.html "一套分布式IM即时通讯系统的技术选型和架构设计") \[13\] [转转平台IM系统架构设计与实践(一):整体架构设计](http://www.52im.net/thread-4764-1-1.html "转转平台IM系统架构设计与实践(一):整体架构设计") \[14\] [移动端弱网优化专题(一):通俗易懂,理解移动网络的"弱"和"慢"](http://www.52im.net/thread-1587-1-1.html "移动端弱网优化专题(一):通俗易懂,理解移动网络的“弱”和“慢”") \[15\] [移动端弱网优化专题(二):史上最全移动弱网络优化方法总结](http://www.52im.net/thread-1588-1-1.html "移动端弱网优化专题(二):史上最全移动弱网络优化方法总结") \[16\] [Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?](http://www.52im.net/thread-3098-1-1.html "Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?") \[17\] [从客户端的角度来谈谈移动端IM的消息可靠性和送达机制](http://www.52im.net/thread-1470-1-1.html "从客户端的角度来谈谈移动端IM的消息可靠性和送达机制") \[18\] [IM消息送达保证机制实现(一):保证在线实时消息的可靠投递](http://www.52im.net/thread-294-1-1.html "IM消息送达保证机制实现(一):保证在线实时消息的可靠投递") \[19\] [移动端IM中大规模群消息的推送如何保证效率、实时性?](http://www.52im.net/thread-1221-1-1.html "移动端IM中大规模群消息的推送如何保证效率、实时性?") \[20\] [如何保证IM实时消息的"时序性"与"一致性"?](http://www.52im.net/thread-714-1-1.html "如何保证IM实时消息的“时序性”与“一致性”?") \[21\] [一个低成本确保IM消息时序的方法探讨](http://www.52im.net/thread-866-1-1.html "一个低成本确保IM消息时序的方法探讨") > **即时通讯技术学习:** > > - 移动端IM开发入门文章:《[新手入门一篇就够:从零开发移动端IM](http://www.52im.net/thread-464-1-1.html "新手入门一篇就够:从零开发移动端IM")》 > > - 开源IM框架源码:[https://github.com/JackJiang2011/MobileIMSDK](https://github.com/JackJiang2011/MobileIMSDK "https://github.com/JackJiang2011/MobileIMSDK")([备用地址点此](https://gitee.com/jackjiang/MobileIMSDK "备用地址点此")) (**本文已同步发布于:** [http://www.52im.net/thread-4889-1-1.html](http://www.52im.net/thread-4889-1-1.html "http://www.52im.net/thread-4889-1-1.html"))