用HashedWheelTimer + Redis + RocketMQ发送未来任意时间精度的延迟消息

在目前开源的RockeMQ版本中,并不支持发送任意时间精度的延迟消息。上次面试,碰到这样的面试题---如果要发送任意时间精度的延迟消息,该如何做?当时回答的不好。今天通过查资料,把这种操作简单落地了。

具体的做法是:

1. 生产延迟消息:延迟消息由两部分组成--该笔消息的订单号key+业务数据value;

2. 存储消息:当把延迟消息组装好之后,把该消息(key,value)放入redis中并设置一定的超时时间同时存入时间轮数据结构中;

3. 取出消息:当该消息在时间轮数据结构中到期时,取出key,然后根据这个key去redis中取value;

4. 通过RocketMQ的生产者线程,把消息发送出去,若发送成功,则把redis中该key删除;若是发送失败,则记录日志,人工补偿;

每部分的作用是:

1. HashedWheelTimer:存储消息的key,key到期时,自动弹出---起到一个定时器的作用;

2. Redis:将完整的延迟消息存储到内存中时,还把数据持久化到硬盘,当redis重启时,基本不丢数据;

3. RocketMQ:发送延迟消息;

这里有几个问题需要注意:

1. 当系统突然宕机,服务器重启后,时间轮HashedWheelTimer中的key都将消失,并且很难恢复,此时丢失的key对应在Redis中的value只能等待时间到期,这种情况怎么办,即数据丢失问题?也可以不使用Redis存储完整的消息,把完整的消息直接放入时间轮数据结构中或放入延迟队列DelayQueue中;用这种方式也会存在数据丢失的问题:即系统突然宕机,服务器重启后,未到期的数据都将丢失,因为对数据没有进行持久化;

2. 当key从HashedWheelTimer中取出后,根据该key在Redis中没取到数据,这种情况该怎么办,即数据不一致的问题?

3. 当消息到期后,用RocketMQ发送时,发送好几次都失败了,这时候除了记录日志,人工进行补偿之外,还有什么好的解决方案?--解决办法之一是:把这些发送失败的消息,存入数据库表中;然后启动一个定时任务,定时把发送失败的消息,通过RocketMQ再次发送出去,若发送成功,将该消息从数据库中删除;若这次还是发送失败,则下次定时任务执行时,再继续尝试发送。

这里的HashedWheelTimer可以用Delayqueue代替,它两相比较而言,HashedWheelTimer的时间复杂度比Delayqueue要好些。

本文是从以下博客中得到的启发:

1. https://www.jianshu.com/p/a8c1458998aa  延时任务队列的原理与实现总结

2. https://mp.weixin.qq.com/s?__biz=MzU3MTQ4MzEwMw==&mid=2247483703&idx=1&sn=3ee685fa4237fcb0a50c1d103b1ed19f&chksm=fcde3787cba9be9188d1bd11c5d663e81c9170a36ad100824453f1836e53cdfe1c2ef088b21a&mpshare=1&scene=1&srcid=#rd   

QMQ延时消息设计与实现

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值