3

开源IM项目OpenIM 客户端SDK架构剖析-确保消息的有序性,以及消息百分百可达

 2 years ago
source link: https://studygolang.com/articles/35542
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

开源IM项目OpenIM 客户端SDK架构剖析-确保消息的有序性,以及消息百分百可达

OpenIM · 4天之前 · 126 次点击 · 预计阅读时间 3 分钟 · 大约8小时之前 开始浏览    

开源IM项目OpenIM第二版对于客户端架构进行了局部重构,解决了消息触发时序等bug,也梳理了内部模块。目前已经接近尾声,本文重点讲解SDK架构,以便大家深入了解OpenIM,并希望大家能深度参与开发。很多开发者有个误区,认为IM的挑战主要在服务端,当然服务端有其挑战,包括性能、压力、时延等,但优秀的IM架构需要服务端和客户端完美配合,比如消息对齐机制,本地缓存和后台数据同步,app多端如何实时同步。

github 6.5K star 具体地址:

OpenIM Corporation ​github.com/OpenIMSDK 客户端重点问题总结:

(1)如何确保消息有序性;

(2)如何确保消息百分百可达;

(2)如果确保本地db和服务端数据的一致性;

(3)如何高效地实现多端同步;

(4)如果确保消息即时达到;

(5)消息发送的异步性,如何确保消息发送的一致性;

本文从架构角度重点解答第1,2两个问题

客户端模块划分和协程模型

https://pic4.zhimg.com/80/v2-e18bb88ac7e0c9c5851468debbcfc7fb_1440w.jpg

WsConn:ws连接管理器。提供函数供其他方调用,具体包括:

(1)ws连接服务端,和OpenIM服务端保持长连接;

(2)关闭ws连接;

(3)通过ws发送请求;

WsRespAsyn:ws请求-响应同步器,因为ws是异步处理,需要把请求和响应关联起来,提供函数供其他方调用(消息发送,心跳发送,拉取历史消息等)

(1)getCh:为每个请求生成一个channel和msgIncr,使用map关联起来 msgIncr->channel

(2)notifyResp:对于ws收到的每个响应,通过msgIncr找到channel,并往channel发送响应,通知响应到达;

Ws:模块对WsConn 和 WsRespAsyn功能进行整合(1)请求响应同步化,提供函数SendReqWaitResp,调用者通过ws发送请求后,等待此请求的响应达到。(2)对于接收到的推送消息,把消息写入PushMsgAndMaxSeqCh channel,触发MsgSync消息同步协程。

具体实现:ReadData协程:接收服务端ws数据,并根据收到的数据类型(心跳、推送、踢出登录、拉取历史消息等),触发不同的逻辑处理,(1)对于主动发送请求的响应,则调用WsRespAsyn的notifyResp响应触发接口;(2)对于push消息,写入PushMsgAndMaxSeqCh ,触发MsgSync消息同步协程。

MsgSync:消息同步器;包含Ws 和conversationCh 、 PushMsgAndMaxSeqCh ,启动消息同步协程,对PushMsgAndMaxSeqCh 中的读取的数据做处理,具体包括:

(1)从PushMsgAndMaxSeqCh 读取服务端最大seq:SvrMaxSeq(由heartbeat写入的),对比本地最大seq:LocalMaxSeq和服务端最大seq: SvrMaxSeq,计算出缺失的seq,从服务器拉取历史消息,放入conversationCh ,触发conversation协程处理;

(2)从PushMsgAndMaxSeqCh 读取ws推送消息(由Ws的ReadData写入的推送消息),如果消息中的seq+1==LocalMaxSeq,则写入conversationCh,触发conversation处理,否则从服务端拉取消息补齐[LocalMaxSeq+1, seq],放入conversationCh ,触发conversation协程处理;

heartbeat:心跳管理器,包括MsgSync

(1)心跳协程,从服务端定时获取最大seq:SvrMaxSeq,然后把SvrMaxSeq让入PushMsgAndMaxSeqCh ,触发MsgSync消息同步协程。

心跳和消息同步融合

https://pic1.zhimg.com/80/v2-21ce2e8b631a5ad67e26750fd5e768a4_1440w.jpg

在心跳逻辑中触发消息同步

(1)心跳协程每30秒通过ws从服务端获取最大seq:SvrMaxSeq;

(2)心跳协程把SvrMaxSeq写入PushMsgAndMaxSeqCh ,触发MsgSync消息同步协程;

(3)MsgSync消息同步协程从PushMsgAndMaxSeqCh 中读取SvrMaxSeq,

(4)MsgSync消息同步协程对比本地最大seq: LocalMaxSeq和SvrMaxSeq,如果有缺失,则通过ws拉取历史消息,范围为:[localMaxSeq+1,SvrMaxSeq],

(6)MsgSync消息同步协程把拉取到的缺失的历史消息写入conversationCh 中;

(7)msg-conversation消息会话协程从conversationCh 中读取缺失的历史消息,按照消息类型做业务处理,具体包括消息落地本地db,触发新消息回调,触发会话改变回调(或新增回调)

push消息触发同步

{{https://pic1.zhimg.com/80/v2-050980bb8dcd15836e7cc9913151f584_1440w.jpg(uploading...)}} 以push消息触发同步:

(1)Ws的ReadData协程收到服务端的推送消息,

(2)Ws的ReadData协程把推送消息写入PushMsgAndMaxSeqCh ,触发MsgSync消息同步协程。

(3)MsgSync消息同步协程从PushMsgAndMaxSeqCh 中读取推送消息,如果msg中的seq比本地最大seq大1,则跳过第4步,直接写入conversationCh,触发conversation处理;

(4)服务端拉取消息补齐[LocalMaxSeq+1, seq],放入conversationCh ,触发conversation协程处理;

(5)以下基本与以心跳触发同步过程一样。

由于seq是按照消息的客观事件递增生成的,对于推送消息,如果比本地最大seq大1,则消息可以无缝对接。否则要么推送的是过时消息,要么推送消息和本地消息有差异,需要通过ws拉取后写入本地,并触发相应回调。至此,客户端消息和服务端消息完全同步,并保证新消息回调的有序性。

重点参考我们开发文档:https://doc.rentsoft.cn/


有疑问加站长微信联系(非本文作者))

280

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK