通过对分层架构 IM 系统的分析,Router 的核心职责是作为中央存储记录在线客户端与 Entry 节点之间的映射关系,在本质上 Router 是一个内存数据库。
客户端已经离线,Entry 还未感知,或者 Entry 已经感知并且切断了连接,但是 Router 中仍记录着该客户端的在线状态数据;如图中,uid 是 102 的用户已经离线,但是 Router 中仍然记录着 102 与 Entry 节点的映射关系。这样造成的直接后果就是,当要向 102 推送消息时,Router 提供的数据则是无效的。
怎么定性 Router 假在线问题呢?
造成这个问题是不是由于整个 IM 系统的分层架构设计有缺陷呢?不是的, Router 假在线问题是一个合理的异常现象,说 【合理】是因为造成这个问题是正常的,是合理的,不是因为整体设计有问题;说【异常】是因为这毕竟会导致不好的结果,的确是一个问题,是需要解决的!
Router 假在线问题是怎么造成的呢?
客户端是移动设备,处于弱网络的环境中,客户端与 Entry 之间的 TCP 连接是很容易断开的;TCP 连接中断后,其两端节点的反应具有延迟性,到 Entry 捕捉住 TCP 连接中断事件时具有一个窗口期,所以 Router 的数据状态与实际情况不一致就是必然的。
更主要的情况是:Entry 感知到连接中断后,需要通过 Logic 写入到 Router 中进行更新,Logic 是业务模块,升级迭代和进程重启非常频繁,会很容易丢掉 Entry 发送的 “连接中断” 事件,所以 Router 假在线问题就产生了。
怎么避免或解决 Router 假在线问题呢?
既然经常重启的 Logic 导致了 Entry 不能百分百成功写 Router,那是否可以由 Entry 直接写 Router 呢?见下图。
由 Entry 直接写 Router 是不可取的。我们在前面的文章(分层架构 IM 系统之架构解读)中分析过,Entry 的核心职责是维护与客户端之间的长连接,不负责处理任何的业务逻辑;而 Router 中存储了与业务逻辑相关的很多字段(比如:deviceType、deviceToken等),由 Entry 直接访问 Router 会造成极大的耦合性,破坏最初的架构原则。
常见的解决 Router 假在线问题的手段有:
-
Router 通过自身的心跳扫描机制,扫描并清理掉过期的数据;
-
Entry 推送消息时,若发现用户已经离线,则 Entry 回调 Logic 的 “unreachable” 接口,由 Logic 清理Router 中的假在线数据;
-
Entry 推送消息时,若没有收到客户端回复的 ACK 时,Logic 也会修复 Router 中的假在线数据。
对 Router 假在线问题进一步抽象:假在线其实是一个分布式系统的 “数据一致性” 问题,为什么不采用 “强一致性” 方式来彻底消除假在线问题呢?也就是采用 CAP 模型中的 CP 模型。
因为 CP 模型会导致系统的可用性大大降低,在访问 Router 时,Router 需要通过类似于一致性协议的手段与Entry 进行通信确认在线状态,其效率可想而知;在互联网中,尤其是非金融领域, AP模型才是最合适的。
IM 以及其他互联网系统,在研发过程中遇到的所有问题,在实践中需要通过低成本的方式来解决,而不能只站在理论层次来纸上谈兵,即【降本增效】。
最后,总结文中关键:
1、什么是 Router 假在线?简单理解为: Router 认为用户在线,而 Entry 中用户已经离线。
2、怎么定性 Router 假在线?合理的异常现象。
3、 Router 假在线问题是如何造成的?主要因素是 中间节点 Logic 的 “不稳定性”。
4、 怎么解决 Router 假在线问题? Router 自身扫描机制 或 由 Entry 通知 Logic 及时修复。