试想如果一个IM连发出的消息都不知道对方到底能不能收到、发出的聊天内容对方看到的到底是不是“胡言乱语”(严重乱序问题),这样的APP用户肯定不会让他在手机上过夜(肯定第一时间卸载了),因为最基本的聊天逻辑都无法实现,它已经失去了IM软件本身的意义。
不过,另一个方面来讲,IM系统是不标准的(虽然曾经XMPP这种协议试图解决这个问题,但事实证明那根本不现实),各家几乎都是自已的私有协议、不同的实现逻辑,这也决定了即使同一个技术问题,对于IM来说很难有固定的实现套路和标准的解决方案。
所以,对于本文来说,文中作者虽然提供了有关IM消息“可靠性”与“一致性”问题的解决方案,但方案到底合不合理、适不适合你,这就是仁者见仁、智者见智的事了。用人话说就是:本文内容仅供参考,具体的解决方案请务结合自已的系统构架和实现情况,多阅读几篇即时通讯网上有关这个技术话题的文章,取其精华,找到适合自已的技术方案和思路才是最明智的。
丛所周之,即时通讯聊天(IM)系统必需要解决消息可靠性及消息一致性问题(PS:如果具体IM系统是什么你都还没弄明白
这两个问题,通俗来说就是:
1)消息可靠性:简单来说就是不丢消息,会话一方发送消息,消息成功到达对方并正确显示;2)消息一致性:包括发送一方消息一致及会话双方消息一致,要求消息不重复,不乱序。
本文会从典型的IM消息发送逻辑开始,简单易懂地阐明消息可靠性、一致性问题的原理及可参考的技术解决方法,或许技术方案并不完美,但希望能为你的IM技术问题解决带来启发。
IM的消息发送一般的实现过程可以分为两个阶段:
1)发送方发送消息、服务端接收、返回消息 ACK 给发送方;2)服务端将消息推送到接收方。
判断消息发送是否成功主要依据第一阶段——即服务器是否接受到消息。
对于消息发送者来说,消息状态可以分为三类:
1)正在发送;2)发送成功;3)发送失败。
具体来说,这三类状态的具体意义是:
1)正在发送:发送方触发发送事件开始,到收到服务端返回消息对应 ACK 之前;2)发送成功:发送方收到消息对应 ACK 回复;3)发送失败:超过一定重发次数,未收到消息对应 ACK 回复。即时通讯聊天软件app开发可以加小蓝豆的v:weikeyun24咨询
4.1 重发机制
保证消息发送第一阶段(见本文“3、典型IM消息发送过程”一节)消息成功发送的方法是设立重发机制:
1)依据一定时长内是否收到消息对应 ACK,判断消息是否要重发;2)如果超过预设时长,就重新发送;3)当重发次数超过预设次数,就不再重发,判定该消息发送失败,修改消息发送状态。
PS:具体的完整方案级代码实现,可以参考MobileIMSDK 中有关QoS机制的代码实现。
4.2 会话记录检查
消息发送第二阶段(见本文“3、典型IM消息发送过程”一节)服务端推送消息到接收方,如果连接断开,会丢失消息。
所以要保证消息完整,就需要在建立连接后,根据上一条消息(已经 ACK)时间戳,获取会话记录,一次返回一段时间内所有消息(PS:中大型应用中,消息的拉取也不是个简单事情,
4.3 需要考虑的两个问题
消息重发、会话记录检查需要考虑两个问题:
1)消息是否会重复发送;2)消息顺序是否会被打乱。
举两个例子。
关于消息重发问题:
1)如果丢消息的点在消息达到服务端之前,服务端并没有收到消息,发送方重新发送丢失消息,服务端接收成功,不会产生两条相同消息;2)而如果服务端接收到消息,返回 ACK 丢失,这时再发送一次相同消息,就可能造成消息重复。
关于消息顺序问题:
1)如果发送方连发三条消息,第一、第三条成功被服务端接收,第二条丢了,那第三条消息是否会被记录?2)如果这时第二条消息达到服务端,其顺序是在第三条时间之前还是之后(服务端一般都会给记录打一个时间戳)?
5.2 使用向量时钟进行消息排序
对于消息排序问题:因为在聊天中,消息的顺序对于发送方的表述有重要的影响,消息不完整或顺序颠倒都可能造成语意不连贯,甚至曲解。所以需要保证发送方发送消息顺序,而会话双方消息排序需要考虑实际情况。
在一般的认知里:状态是正在发送的消息,应该还没有被对方看到,只有发送成功的消息,才会被对方看到。但在实现中,消息发送成功是以服务器接收消息并返回 ACK 成功为判断依据,而不是被对方接收到。
那么就会出现这样一个问题:如果一条消息状态是正在发送,此时收到一条消息,那么收到的消息是在正在发送的消息之前还是之后?
这是一个上下文关系,关键问题是:发送方是以哪条所见消息为依据发送消息的。
这里提供一种思路:借鉴分布式系统中的向量时钟算法(见《分布式系统中的向量时钟算法》)。
先简单描述向量时钟算法:
向量时钟算法用于在分布式系统中生成事件偏序关系,并纠正因果关系。一个系统包含 N 个节点,每个节点产生的消息体中包含该节点的逻辑时钟,整体系统的向量时钟由 N 维逻辑时钟组成,并在每个节点产生的消息体中传递。
简单来说,向量时钟算法的实现原理如下:
1)初始状态,向量值为 0;2)每次节点处理完节点事件,该节点时钟+1;3)每次节点发送消息,将包含自身时钟的系统向量时钟一起发送;4)每次节点收到消息,更新向量时钟,该节点时钟+1,其他节点对比每个节点本地保留的向量时钟值和消息体中向量时钟值,取最大值;5)节点同时收到多条消息,判断接收消息的向量时钟之间是否存在偏序关系。