上篇提到了, IM协议层是主要解决会话和消息的同步, 在实现上, 以推模式为主, 拉模式为辅.
本文Agenda:
提示: 本系列文章不会单纯的给出结论, 希望能够分享的是"如何分析, 如何得出的结论"的思路.
同步是通过将server的位置同步到client的位置, 最终实现了消息的同步.
大前提条件
小前提条件
3. client可以同步到server的位置
4. server在此流程中, 将消息内容带给端上
结论
实现消息内容的同步
用户A发送了10,000条消息给B, 并且B仅有A一个会话. server的同步队列, 仅能记录单人的1000个同步事件, 在不同的场景下(场景为何如此划分, 请参考上篇文章)的处理.
总共有四个步骤
此四个步骤便是同步协议的核心流程.
如果加上建联的过程. 便是完整的同步协议方案.
完整的同步协议方案, 整体可以认为分为四个阶段.
即离线消息同步, 是保证了client与server的同步位点是一样的. 这也是微信的WeiSync的设计思路的前提假设: client与server是状态同步的.
因而
同步位点, 是server和client用于判定server的同步队列, 当前已经同步到的位置信息.以及用于server和client之间判断还有那些信息未同步的判断依据.
版本号的方式, client是OK的. 但是对于server而言, 如果server需要清空对应的队列时, 便需要记录已经清空的最新的版本号. 这样在新消息来临时, 才能比较准确的记录.
时间戳的方式, client是OK的. 如果是比较活跃的群聊, 单位时间内的消息暴涨, 采用毫秒的时间戳, 也是可能会有重复的记录. 建议采用纳秒.
如生成单独的uuid, 也是可以的. 不过对于server而言, 由于是字符串匹配, 检测client已经同步到的位置, 耗时会比较久.
因而采用纳秒级别的时间戳是一种比较好的解决方式.
采取纳秒的方式作为同步位点, 另外, 为了做方便做后续的协议升级, 除了同步位点外, 还需要增加一个同步协议版本号的元素.
即同步协议版本号 + 纳秒的同步位点. 作为同步协议的同步位点解决方案
client和server均需要持有同步位点.
server记录client的设备维度的同步位点 + 天然持有的同步队列的同步位点信息.
client记录当前设备上账号的同步位点信息.
ps: 英文名字是我定义出来的.
英文名便比较好理解. Sync Gap Overflow. 同步gap时, 内容过多, server拒绝主动同步. 即告知client, 需要client主动拉取. 从推模式切成了拉模式.
gap一般的处理, 也是一个端到端的问题.
出现SyncGapOverflow, 是client的同步位点, 已经不在同步队列中.
而不在同步队列中, client的位点太老可以导致, 也可能是server对同步队列做了定期清理机制导致.
因而一般的SyncGapOverflow的触发原因有两类
ACK机制, 即ACK消息. “回复已经收到数据”. 而在同步协议的场景下, 是指 client 确认收到了sever的同步数据, 给到server的一个确认消息.
目的:
1. server确认同步消息消费了, 即保证消息的可靠性投递和消费
2. server根据此确认消息, 标记client的当前同步位点
当用户离线后时, server记录的最新同步位点的index位于10,000, 而client的同步位点的index位于9,900.
用户再次登录时,
Ack的逻辑, 可以直接参考TCP的Ack机制.
一般来讲, 消息同步是附属于同步协议的, 但是严格来讲, 同步协议与消息同步是可以做分割的
同步协议仅推送最新的同步位点信息,同步后, client 回复ack. 而client每次在收到同步位点信息时, 跟本地做比对, 然后主动拉取中间的消息内容,
即同步协议仅推送server最新的变更通知, client收到通知后, 回复ack. 主动拉取. 最大程度的使用拉模式. 依然以用户短暂离线再次在线为例.如图所示.
处理流程
而这种Ack机制, 也确实保证了是收到了消息通知, 但是没有保证client的消息数据正常处理了. 选择此种方案需要慎重.
同步协议的上层, 从IM的角度来看,是包含了会话和消息, 不过如果从IM整体的系统来看, 可能还有User的Profile等等. 如果IM的系统还有直播等内容, 那么同步协议正常来讲, 与直播也有是有关系的.
因而, 从一般的设计来看, 包含了
会话存在新增会话, 删除会话, 会话属性变更等等.
消息存在新增消息, 撤回消息, 删除消息, 消息的属性变更等等.
新增了联系人, 联系人的Profile有变更,如昵称等等.
虽然userProfile有如此的变更, 但是对于业务而言, UserProfile的变更, 是否需要一定对接到同步协议中, 有待商定. 可以参考下微信的feature. 尤其是在群聊中, 当点击一个群中user的头像时, 群聊时头像是V1, 而点进去后, 看到头像变了, 是V2, 再返回群聊时, 头像变为了V2. 因而UserProfile的行为不一定与同步协议强绑定.
其他业务可能需要进行事件通知, 如直播中的评论的新增等等(可以通过拉模式, 也可以通过推模式).
针对上层的这么多行为, 如何进行支持呢? 按照同类合并即可.
先按照业务划分, 业务再进行细化.
业务划分为IM, 直播等
IM的事件划分为会话事件以及消息事件.
会话事件可拆分 新增会话, 会话删除, 会话属性变更等具体事件.
消息事件可拆分 新消息, 消息撤回, 消息删除, 消息属性变更等具体事件.
因而整体的业务逻辑可以按照如下结构划分.
即按照 biz_type, sub_biz_type, event的三层业务结构支持上层业务
本文通过同步协议的各个场景细化, 比较完整的介绍了
1. 同步协议的方案.
2. 在设计同步协议中, 几个比较关键的元素的设计, 同步位点, Gap过大机制, Ack机制.
3. 同步协议通过biz_type, sub_biz_type, 以及event的三层业务结构支持上层业务