为什么Redis的消息机制不适合实现延时队列?

    xiaoxiao2023-12-01  161

    一、背景

    之前了解到一个朋友通过监听key实现来实现延时队列的功能。

    后面了解到包括Java单机版的DelayQueue以及RabbitMQ延时队列/延迟重试等相对更靠谱一些。

    常见的有:

    定期轮询(数据库等)DelayQueueTimerScheduledExecutorService时间轮(kafka)RabbitMQQuartzRedis ZsetKoalaJCronTabSchedulerX(阿里)有赞延迟队列

    具体参见链接:https://juejin.im/post/5b5e52ecf265da0f716c3203

     

    二、为什么?

    Redis通过key失效监听的方式实现延时队列,用到了PubSub机制。

    在Redis5之前版本存在如下两个关键问题:

    (1)Redis的PubSub消息不会持久化,Redis宕机后消息就会被抛弃。

    (2)Redis的消息队列没有太多高级特性,没有ack保证,可靠性不高。

    这样如果消费者没有ack就挂掉,重启后无法再处理这个消息,导致消息丢失。

     

    三、总结

    由于Redis5.9开始引入了Stream,Stream借鉴了Kafka的设计,加入了ack以及PEL以及高可用机制来避免消息丢失。

    具体参见《Redis深度历险》Stream部分章节。

    其中Stream的高可用章节提到:

    "鉴于Redis的指令复制是异步的,在failover发生时,Redis可能会丢失极小部分数据,这一点Redis的其他数据结构也是一样。"

    总之消息队列这一块安全性和可用性提升很大。

    但是如果延时队列还是用的是之前的PubSub,风险依然很大。

    如果用Redis实现延时队列可考虑使用Zset结构,将score设置为超期的时间戳,采用不断轮询小顶堆顶部来核查是否超期,从而试下你延时队列。

    当然可以参考上面提到的其他更成熟的方案。

    四、附录

    介绍Stream的参考文章

    https://redis.io/topics/streams-intro

     

    http://xiaorui.cc/2018/06/07/浅入浅出redis5-0的streams数据结构/

     

    如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。

    明明如月学长 认证博客专家 Java攻城狮 宅男 前网易Java高级工程师。《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《EffectiveJava》独家解析》专栏作者。热爱技术,喜欢思考,乐于分享。
    最新回复(0)