本文作者“商文默”,有订正和改变。
1、写在后面
即时通讯网整顿的大量IM技术文章中(见本文末“参考资料”一节),无关音讯可靠性和一致性问题的文章占了很大比重,起因是IM这类零碎抛开各种目迷五色的产品性能和技术个性,保障音讯的可靠性和一致性简直是IM产品必须的素质。
试想如果一个IM连收回的音讯都不晓得对方到底能不能收到、收回的聊天内容对方看到的到底是不是“胡说八道”(重大乱序问题),这样的APP用户必定不会让他在手机上过夜(必定第一工夫卸载了),因为最根本的聊天逻辑都无奈实现,它曾经失去了IM软件自身的意义。
不过,另一个方面来讲,IM零碎是不规范的(尽管已经XMPP这种协定试图解决这个问题,但事实证明那基本不事实),各家简直都是自已的公有协定、不同的实现逻辑,这也决定了即便同一个技术问题,对于IM来说很难有固定的实现套路和规范的解决方案。
所以,对于本文来说,文中作者尽管提供了无关IM音讯“可靠性”与“一致性”问题的解决方案,但计划到底合不合理、适不适宜你,这就是仁者见仁、智者见智的事了。用人话说就是:本文内容仅供参考,具体的解决方案请务联合自已的零碎构架和实现状况,多浏览几篇即时通讯网上无关这个技术话题的文章,取其精华,找到适宜自已的技术计划和思路才是最理智的。
学习交换:
- 即时通讯/推送技术开发交换5群:215477170 [举荐]
- 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》
- 开源IM框架源码:https://github.com/JackJiang2...
(本文同步公布于:http://www.52im.net/thread-35...
2、本文引言
丛所周之,即时通讯聊天(IM)零碎必须要解决音讯可靠性及音讯一致性问题(PS:如果具体IM零碎是什么你都还没弄明确,先读这篇《零根底IM开发入门(一):什么是IM零碎?》)。
这两个问题,艰深来说就是:
- 1)音讯可靠性:简略来说就是不丢音讯,会话一方发送音讯,音讯胜利达到对方并正确显示;
- 2)音讯一致性:包含发送一方音讯统一及会话单方音讯统一,要求音讯不反复,不乱序。
本文会从典型的IM音讯发送逻辑开始,简略易懂地说明音讯可靠性、一致性问题的原理及可参考的技术解决办法,或者技术计划并不完满,但心愿能为你的IM技术问题解决带来启发。
3、典型IM音讯发送过程
IM的音讯发送个别的实现过程能够分为两个阶段:
- 1)发送方发送音讯、服务端接管、返回音讯 ACK 给发送方;
- 2)服务端将音讯推送到接管方。
判断音讯发送是否胜利次要根据第一阶段——即服务器是否承受到音讯。
对于音讯发送者来说,音讯状态能够分为三类:
- 1)正在发送;
- 2)发送胜利;
- 3)发送失败。
具体来说,这三类状态的具体意义是:
- 1)正在发送:发送方触发发送事件开始,到收到服务端返回音讯对应 ACK 之前;
- 2)发送胜利:发送方收到音讯对应 ACK 回复;
- 3)发送失败:超过肯定重发次数,未收到音讯对应 ACK 回复。
对应的音讯发送流程如下图所示:
4、IM音讯可靠性
限于篇幅,对于IM音讯可靠性的基本概念和具体原理倡议浏览《零根底IM开发入门(三):什么是IM零碎的可靠性?》,本文着重谈谈解决思路。
4.1 重发机制
保障音讯发送第一阶段(见本文“3、典型IM音讯发送过程”一节)音讯胜利发送的办法是设立重发机制:
- 1)根据肯定时长内是否收到音讯对应 ACK,判断音讯是否要重发;
- 2)如果超过预设时长,就从新发送;
- 3)当重发次数超过预设次数,就不再重发,断定该音讯发送失败,批改音讯发送状态。
PS:具体的残缺计划级代码实现,能够参考MobileIMSDK 中无关QoS机制的代码实现。
4.2 会话记录查看
音讯发送第二阶段(见本文“3、典型IM音讯发送过程”一节)服务端推送音讯到接管方,如果连贯断开,会失落音讯。
所以要保障音讯残缺,就须要在建设连贯后,依据上一条音讯(曾经 ACK)工夫戳,获取会话记录,一次返回一段时间内所有音讯(PS:中大型利用中,音讯的拉取也不是个简略事件,详情能够浏览《IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》)。
另一种保障办法是退出定时轮询,查看音讯完整性,具体的思路如下图所示。
建设连贯流程图:
4.3 须要思考的两个问题
音讯重发、会话记录查看须要思考两个问题:
- 1)音讯是否会反复发送;
- 2)音讯程序是否会被打乱。
举两个例子。
对于音讯重发问题:
- 1)如果丢音讯的点在音讯达到服务端之前,服务端并没有收到音讯,发送方从新发送失落音讯,服务端接管胜利,不会产生两条雷同音讯;
- 2)而如果服务端接管到音讯,返回 ACK 失落,这时再发送一次雷同音讯,就可能造成音讯反复。
对于音讯程序问题:
- 1)如果发送方连发三条音讯,第一、第三条胜利被服务端接管,第二条丢了,那第三条音讯是否会被记录?
- 2)如果这时第二条音讯达到服务端,其程序是在第三条工夫之前还是之后(服务端个别都会给记录打一个工夫戳)?
5、IM音讯一致性
同上节一样,对于IM音讯一致性的基本概念和具体原理倡议浏览《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》。
5.1 应用 uuid 音讯去重
对于音讯重发问题,能够给每条音讯减少属性 uuid 作为音讯惟一标识,重发消息 uuid 不变,前端依据 uuid 去重。大抵思路就是这样。
PS:对于IM来说,音讯ID也是个很大的技术话题,有趣味能够读上面这个系列:
- 《IM音讯ID技术专题(一):微信的海量IM聊天音讯序列号生成实际(算法原理篇)》
- 《IM音讯ID技术专题(二):微信的海量IM聊天音讯序列号生成实际(容灾计划篇)》
- 《IM音讯ID技术专题(三):解密融云IM产品的聊天音讯ID生成策略》
- 《IM音讯ID技术专题(四):深度解密美团的分布式ID生成算法》
- 《IM音讯ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》
- 《IM音讯ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》
5.2 应用向量时钟进行音讯排序
对于音讯排序问题:因为在聊天中,音讯的程序对于发送方的表述有重要的影响,音讯不残缺或程序颠倒都可能造成语意不连贯,甚至误解。所以须要保障发送方发送音讯程序,而会话单方音讯排序须要思考理论状况。
在个别的认知里:状态是正在发送的音讯,应该还没有被对方看到,只有发送胜利的音讯,才会被对方看到。但在实现中,音讯发送胜利是以服务器接管音讯并返回 ACK 胜利为判断根据,而不是被对方接管到。
那么就会呈现这样一个问题:如果一条音讯状态是正在发送,此时收到一条音讯,那么收到的音讯是在正在发送的音讯之前还是之后?
这是一个上下文关系,关键问题是:发送方是以哪条所见音讯为根据发送音讯的。
这里提供一种思路:借鉴分布式系统中的向量时钟算法(见《分布式系统中的向量时钟算法》)。
先简略形容向量时钟算法:
向量时钟算法用于在分布式系统中生成事件偏序关系,并纠正因果关系。一个零碎蕴含 N 个节点,每个节点产生的音讯体中蕴含该节点的逻辑时钟,整体零碎的向量时钟由 N 维逻辑时钟组成,并在每个节点产生的音讯体中传递。
简略来说,向量时钟算法的实现原理如下:
- 1)初始状态,向量值为 0;
- 2)每次节点解决完节点事件,该节点时钟+1;
- 3)每次节点发送音讯,将蕴含本身时钟的零碎向量时钟一起发送;
- 4)每次节点收到音讯,更新向量时钟,该节点时钟+1,其余节点比照每个节点本地保留的向量时钟值和音讯体中向量时钟值,取最大值;
- 5)节点同时收到多条音讯,判断接管音讯的向量时钟之间是否存在偏序关系。
针对上述的第5)点:
- 1)如果存在偏序关系,则合并向量时钟,取偏序较大的向量时钟;
- 2)如果不存在偏序关系,则不能合并。
偏序关系:如果 A 向量中的每一维都大于等于 B 向量,则 A、B 之间存在偏序关系,否则不存在偏序关系。
对于IM为聊天音讯排序来说,其实就是解决聊天音讯的上下文语境,决定音讯之间的因果关系。
参考向量时钟算法:假如有 N 个音讯会话方,零碎的向量时钟由 N 维时钟组成,向量时钟在各方发送的音讯体中传递,并根据向量时钟排序。
具体实现思路如下:
- 1)零碎向量时钟设为 (0, 0, …, N);
- 2)节点发送音讯,更新零碎向量时钟,该节点时钟加一,其余节点不变;
- 3)节点接管音讯,更新零碎向量时钟,该节点时钟加一;其余节点比照每个节点本地保留的向量时钟的值和音讯中向量时钟的值,取最大值;
- 4)根据音讯体内零碎向量时钟的偏序关系决定音讯程序。
针对上述第4)点:
- 1)如果能够确定偏序关系,则依据偏序关系由小到大显示;
- 2)如果多条音讯不能确定偏序关系,则依照天然程序(接管到的程序)显示。
向量时钟在实践上能够解决大部分音讯一致性的问题,但在实现中还须要思考理论应用时的体验。
这其中最须要关注的问题是:是否要强制排序,或者说,如果理论显示程序和向量时钟之间的偏序关系不统一,是否要挪动音讯之间的程序。
举个例子:在一个有多人的会话中,如果有一方网速特地慢,收不到音讯,也发不出音讯。在他看到的最初的音讯之后,其他人曾经开始新的话题,这时他对于上一个话题的音讯终于发送胜利,并被其他人收到。
此时就存在这样一个问题:这条对于上一个话题的音讯是显示在最初,还是移到较早工夫?
- 1)如果显示在最初,但音讯内容和目前的话题不相干,其他人可能会感到莫名其妙;
- 2)如果把音讯移到较早工夫,那么这条音讯可能不会被其他人看到,或者看到后面多了一条音讯,会有种突兀的感觉。
IM 的场景很多,也很简单,更多的时候须要从产品角度思考问题。
对于音讯是否须要排序的问题,这里只提出一个比拟通用的计划:倡议会话中不强制排序,会话历史记录中依照向量时钟的偏序关系进行排序。
6、本文小结
对于 IM 零碎音讯可靠性及一致性问题,通过音讯重发机制保障音讯胜利被服务端接管,通过会话记录查看保障收取音讯残缺,从而保障整个音讯发送过程的可靠性。应用 uuid 音讯去重,参考向量时钟算法进行音讯排序,为保障音讯一致性提供一种解决方案。
总之,IM这类零碎看似简略,实则水深似海,如果你是IM开发老手,能够从《新手入门一篇就够:从零开发挪动端IM》这篇动手零碎学习。如果你自认为已是IM新手,这里整顿的 IM中大型架构设计 方面的文章或者能够参考一下。
7、参考资料
[1] 零根底IM开发入门(三):什么是IM零碎的可靠性?
[2] 零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?
[3] IM音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递
[4] IM音讯送达保障机制实现(二):保障离线音讯的牢靠投递
[5] 如何保障IM实时音讯的“时序性”与“一致性”?
[6] 一个低成本确保IM音讯时序的办法探讨
[7] IM群聊音讯如此简单,如何保障不丢不重?
[8] 齐全自已开发的IM该如何设计“失败重试”机制?
[9] IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递
[10] 从客户端的角度来谈谈挪动端IM的音讯可靠性和送达机制
[11] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[12] 从老手到专家:如何设计一套亿级音讯量的分布式IM零碎
本文已同步公布于“即时通讯技术圈”公众号。
▲ 本文在公众号上的链接是:点此进入。同步公布链接是:http://www.52im.net/thread-35...