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

OpenIM · · 852 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

开源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](https://static.studygolang.com/220318/1353c35d85fd91a99bc41061cc5f28ed.png) 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](https://static.studygolang.com/220318/df1f35b67dfae1c8618d5c2dcbef738a.png) 在心跳逻辑中触发消息同步 (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/

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

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

852 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传