TimeLine模型下确保消息有序不丢

通过《基于TimeLine模型的消息同步机制》一文,我们了解到Timeline模型有非常多的优点,也是钉钉采用的消息同步机制。实际工作中,我们也将该模型应用在了C端用户的消息场景中。实施过程中也遇到了一些问题,积累了一些经验。本文将介绍极端情况丢失消息的问题及解决办法。

一、Timeline概念

Timeline可以简单理解为是一个消息队列,某个用户所有的消息都存储在这个Timeline中,用户的各个端可以从这个队列中同步各自消息。 


bb

图中的例子中,消息发送方是A,消息接收方是B,同时B存在多个接收端,分别是B1、B2和B3。A向B发送消息,消息需要同步到B的多个端,待同步的消息通过一个Timeline来进行交换。A向B发送的所有消息,都会保存在这个Timeline中,B的每个接收端都是独立的从这个Timeline中拉取消息。每个接收端同步完毕后,都会在本地记录下最新同步到的消息的msgid,即最新的一个位点,作为下次消息同步的起始位点。

二、丢失消息的原因

理论上讲,Timeline模型能够确保消息不重不漏。实际实施中,根据系统架构特点以及选用中间件的不同,极端情况下,可能出现丢消息。最主要的原因是某一时刻,Timeline中的数据不连续或不完整

举个例子,如果用户有两条时间间隔非常近的消息msg1、msg2,对应的msgId分别为10,11。由于时间很相近,(分布式系统)某些情况下可能出现msg2先写入TimeLine,如果此时用户某个端正好执行Sync同步消息,将同步到最大msgId为11的msg2消息,造成msg1丢失(msg1此时还没有写入TimeLine)。

下图是IM系统的结构。Dispatcher负责生成msgId,通过Kafka传递给具体业务逻辑处理单元Processor(名称与图不完全一致),Processor将消息写入Redis/MongoDb。 


bb


这个过程中有三个环节会造成顺序不一致

1、消息msgid在Dispatcher节点生成(采用类snowflake算法),由于不同节点时间可能存在误差,有可能造成msgid和时序不一致

2、Kafka有多个patition,不同patition不能保证消息顺序

3、Processor是多实例部署,多线程处理,也不能保证顺序

三、解决办法

1、服务端严格有序

应用神奇的hash算法,把属于同一用户的消息路由到相同的Dispatcher节点,相同的Kafka分区,相同的Processor线程即可保证消息循序性。但是对于群消息,极端情况下还是可能出现时序问题(当然要丢消息还需要客户端正好执行Sync同步,这个概率极低)

2、客户端补偿

服务端为Timeline中的每条消息都进行严格递增编号,叫做sequenceid。从1开始,2、3、4……加一递增。这样,客户端拉取到消息,能够通过sequenceid感知是否丢失消息。如果丢失消息,可以再次尝试拉取。

这里有个问题,这个严格编号服务我们利用了redis,万一redis数据丢失怎么办呢?个人收件箱Timeline中最新一条消息就是已有的最大编号,redis数据万一丢失了可以从这条消息中取得之前的最大编号。

通过这两个方法,能够确保消息可靠性。 

微信ID:farmerbrag

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31556438/viewspace-2219241/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31556438/viewspace-2219241/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值