首页 > 架构设计 > 软件结构 > 全面揭秘亿级IM即时通讯消息的可靠投递机制
本文由融云技术团队分享,有修订和排版优化。
即时通讯(IM)系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。
综合考虑业务场景、系统复杂度、网络流量、终端能耗等,我们的亿级分布式IM消息系统精心设计了消息收发机制,并不断打磨优化,形成了现在的消息可靠投递机制。
整体思路就是:
本文根据融云亿级IM消息系统的技术实践,总结了分布式IM消息的可靠投递机制,希望能为你的IM开发和知识学习起到抛砖引玉的作用。

以下是融云技术团队分享的其它文章:
一个完整的IM消息交互逻辑,通常会为两段:
消息上行段主要就是依赖IM的实时通道将消息传递给服务端。
这个阶段的消息可靠投递,需要从协议层进行保证,协议层需要提供可靠、有序的双向字节流传输,我们是通过自研的通信协议 RMTP(即 RongCloud Message Transfer Protocol)实现的。
客户端与服务端之间使用长连接,基于 RMTP 协议传输数据。
RMTP协议交互示意图:

如上图所示,协议层通过 QoS、 ACK 等机制,保证IM消息上行段数据传输的可靠性。
经过总结,消息下行段主要有三种行为。
1)客户端主动拉取消息,主动拉取有两个触发方式:
2)服务端主动-发送消息(直发消息):
这是在线消息发送机制之一,简单理解为服务端将消息内容直接发送给客户端,适用于消息频率较低,并且持续交互,比如二人或者群内的正常交流讨论。
3)服务端主动-发送通知(通知拉取):
这是在线消息发送机制之一,简单理解为服务端给客户端发送一个通知,通知包含时间戳等可作为排序索引的内容,客户端收到通知后,依据自身数据,对比通知内时间戳,发起拉取消息的流程。
这种场景适用于较多消息传递:比如某人有很多大规模的群,每个群内都有很多成员正在激烈讨论。通过通知拉取机制,可以有效的减少客户端服务端网络交互次数,并且对多条消息进行打包,提升有效数据载荷。既能保证时效,又能保证性能。
客户端服务端下行段消息交互示意图:

正如上节所言,我们将消息的交互流程进行了拆分:即拆分出上下行。
在上行过程保证发送消息顺序,为了保证消息有序, 最好的方式是按照 userId 区分,然后使用时间戳排序。那么分布式部署情况下,将用户归属到固定的业务服务器上(PS:指的是同一账号的不同端固定连接到相同的业务服务器上),会使得上行排序变得更容易。同时归属到同一个服务器,在多端维护时也更容易。
客户端连接过程:
示意图如下:

小结一下就是:客户端发出消息后,通过接入服务,按照 userId 投递到指定消息服务器,生成消息 Id, 依据最后一条消息时间,确认更新当前消息的时间戳(如果存在相同时间戳则后延)。然后将时间戳,以及消息 Id,通过 Ack 返回给客户端 ; 然后对上行消息使用 userId + 时间戳进行缓存以及持久化存储,后续业务操作均使用此时间戳。
以上业务流程我们称为上行流程,上行过程存储的消息为发件箱消息。
PS:关于消息ID,需要补充说明一下:
我们采用全局唯一的消息 ID 生成策略。保证消息可通过 ID 进行识别,排重。消息ID的结构如下图所示。

如何实现分布式场景下唯一 ID 生成,具体请阅读:《 IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略》。
消息节点在处理完上行流程后,消息按照目标用户投递到所在消息节点,进入下行流程。
下行过程,按照目标 userId 以及本消息在上行过程中生成的时间戳,计算是否需要更新时间戳(正向)。
如果需要更新则对时间戳进行加法操作,直到当前用户时间戳不重复。
如此处理后,目标用户的存储以及客户端接收到消息后的排重可以做到一致,并且可以做到同一个会话内的时间戳是有序的。从而保证同一个接收用户的消息不会出现乱序。
至此:我们已经介绍完了消息的下行交互过程,消息下行过程中的具体实现方式并不简单,以下将详细展开。
1)直发消息:
即服务端主动发送(给目标客户端)的消息:
直发逻辑示意图:

2)通知拉取:
即服务端主动发送通知(给目标客户端):
示意图:

在上图中,3-7 步可能需要循环多次,有以下考虑:
3)服务端直发消息与通知拉取切换逻辑:
主要涉及到的是状态机的更新。
下面示意图集成直发消息与通知拉取过程针对状态机的更新:

至此,消息收发的整个核心流程介绍完毕,余下的内容将介绍多端在线的消息同步处理。
多端按照消息的上下行两个阶段,同样区分为发送方多端同步以及接收方多端同步。
在前面客户端连接 IM 服务过程中(见 本文 4.1节),我们已经将同一个用户的多个客户端汇聚在了同一台服务,那么维护一个 userId 的多端就会变得很简单。
具体逻辑是:
针对上面的第2)点,发送方的多端同步没有经过 IM Server,这么做的好处是:
具体逻辑是:
接收方多端消息同步范围的应用场景,一般都是针对所有终端。
但有一些特殊业务:比如我在 A 客户端上,控制另外某个端的状态,可能需要一些命令消息, 这时候需要这个作用范围,针对性的投递消息。

到此,我们分享完了有关 IM 消息核心处理流程,通过层层拆解逻辑,提供了可靠的消息投递机制。
[1]
零基础IM开发入门(二):什么是IM系统的实时性?
[2]
零基础IM开发入门(三):什么是IM系统的可靠性?
[3]
零基础IM开发入门(四):什么是IM系统的消息时序一致性?
[4]
IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
[5]
IM消息送达保证机制实现(二):保证离线消息的可靠投递
[6]
IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
[7]
理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨
[8]
如何保证IM实时消息的“时序性”与“一致性”?
[9]
IM群聊消息如此复杂,如何保证不丢不重?
[10]
从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
[11]
一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[12]
从新手到专家:如何设计一套亿级消息量的分布式IM系统
[13]
浅谈移动端IM的多点登录和消息漫游原理
[14]
完全自已开发的IM该如何设计“失败重试”机制?
[15]
IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的
[16]
转转平台IM系统架构设计与实践(一):整体架构设计
[17]
如何保障分布式IM聊天系统的消息有序性(即消息不乱)
[18]
微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗
[19]
携程技术分享:亿级流量的办公IM及开放平台技术实践
[20]
一套分布式IM即时通讯系统的技术选型和架构设计
即时通讯技术学习:
- 移动端IM开发入门文章:《 新手入门一篇就够:从零开发移动端IM》
- 开源IM框架源码: https://github.com/JackJiang2011/MobileIMSDK( 备用地址点此)
(本文已同步发布于: http://www.52im.net/thread-3638-1-1.html)
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31137859/viewspace-3117574/ ,如需转载,请注明出处,否则将追究法律责任。