架构师面试(三十一):IM 消息收发逻辑
问题
今天聊一下 IM 系统最核心的业务逻辑。
在上一篇短文《架构师面试(三十):IM 分层架构》中详细分析过,IM 水平分层架构包括:【入口网关层】、【业务逻辑层】、【路由层】和【数据访问层】;除此之外,还有最前端的【终端层】和 最底层的【存储层】。
在这样的架构约束下,完整的消息收发逻辑流程应该如何设计呢? 消息的收发逻辑应当具备可靠性和及时性!
解析
IM 消息的收发需要具备 “可靠性” 和 “及时性”;
“可靠性 ” 一方面要求消息不能丢失,另一方面要求如果接收方在线就应该收到消息,如果不在线就需要通过其他触达通道通知到;“及时性” 要求消息的收发需要低延时。
基于水平分层架构,IM系统完整的消息收发逻辑流程划分为三个阶段,即:生产消息阶段、推送消息阶段 和 消息确认阶段;另外为了保证消息的“可靠性”设计三重保障。整个消息收发逻辑流程如下图所示:
以终端APP(uid = 101)发消息给终端APP(uid = 102)为例说明:
(1)生产消息阶段
终端 APP(uid = 101)基于与 Entry 之间的长连接发送消息到 Entry,因为 Entry 不负责具体的业务逻辑,所以 Entry 会基于与 Logic 之间的 RPC ,将消息请求直接转发到 Logic进行处理(Entry 是如何寻址到 Logic 的,我们会在后面的技术短文中讲解)。
Logic 接收请求后,首先调用 Spam 服务进行风控过滤,然后 Logic 通过 RPC 调用 Das,由 Das 分别写 “消息库”和“联系人库(IM 的消息库和联系人库应该如何设计?我们仍会在后面的技术短文中讲解^-^);写库成功之后,由 Logic 发送 response 到 Entry,由 Entry 转发 response 到 终端APP。(大家可以思考一下,如果终端 APP 没有收到 response 会怎样?)
在生产消息阶段需要重点理解和掌握的是:IM 服务端接收到消息后,是先落库再回复,顺序不能乱了;就好像我们去银行柜台存钱时,业务员一定是先收钱再记账,这个不能错了!
生产消息阶段描述的是消息的生产方和 IM 服务端之间的事情;接下来就是 IM 服务端和消息接收方之间的交互了。
(2)推送消息阶段
Logic 首先访问 Router,获取消息接收方(uid = 102)的在线状态和所连接的 Entry;如果用户uid = 102离线,则 Logic 封装一条 MQ 消息发送到 MQ,由下游的 Extlogic 进行离线用户的消息触达逻辑(包括 推送手机PUSH、推送微信公众号消息、推送 SMS 短信消息、推送 VOIP 等),保证能通过这些通道触达到用户;如果用户uid = 102在线,则 Logic 访问 Router 中缓存的数据,寻址到 Entry 地址,然后 Logic 基于与 Entry之间的 RPC 连接,将消息推送到 Entry(注意:这里的 RPC 与 第一阶段中 Entry 调用 Logic时的 RPC 是两条不同的连接哈!想一下为什么呢?)。
Entry 与 Router 之间有可能数据不一致,即 Router 中缓存的用户uid=102是在线状态,但 Entry 记录uid=102已经离线,这就是典型的IM的【假在线】问题(在后面的技术短文中,我们会详细讲解^-^);如果 Entry 记录用户uid=102离线,则会回调 Logic 的 unreachable 接口,此时Logic 会通过 MQ 通知 Extlogic 走离线用户的消息触达逻辑;如果 Entry 记录用户uid=102在线,则会通过与终端之间的长连接,将消息推送出去。
在推送消息阶段需要重点理解和掌握的是:通过 Router 和 Entry 过滤后,会筛选出【假在线】用户,对于假在线用户,需要通过“离线用户的消息触达逻辑”来触达他们!
是不是通过 Router 和 Entry 过滤后,就可以筛选出所有的“假在线”用户呢?肯定不是的!上面说过为了保证消息的可靠性,设计了三重保障,Router 和 Entry就是第一重保障和第二重保障,第三重保障就是消息处理的第三阶段!
(3)消息确认阶段
Entry 将消息推送给消息接收方之后,消息接收方需要回复 ACK 到IM服务端进行确认;Logic 在一定时间内(比如15秒),如果没有收到消息接收方回复的 ACK,仍然需要通过 MQ 通知下游的 Extlogic 走离线用户的消息触达逻辑。
Logic 针对每一条推送出去的消息都会开启一个倒计时(比如15秒),在消息的吞吐量比较小的时候(比如每秒钟不到10条),我们可以为每条消息都开启一个线程来做专门的业务处理;如果消息的吞吐量比较大的时候(比如每秒钟5000条),又该如何处理呢?这是一个非常典型的业务场景,大家可以思考一下,在后续的技术短文中会陆续讲解。
完整的IM消息逻辑处理流程,在面试时是否可以一气呵成呢?