开源 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 两个问题
客户端模块划分和协程模型
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 音讯同步协程。
心跳和音讯同步交融
在心跳逻辑中触发音讯同步
(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 音讯触发同步
以 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/
github 地址:OpenIM Corporation