消息丢失?5min教你用Redis中List实现安全队列解决~

428 阅读2分钟

上篇文章记录了使用Redis当中List实现消息队列

解决的问题

  • 这篇文章则是记录了如何解决Redis中List实现消息队列出现的消息丢失的问题

业务场景

  • 负责的项目:
    • 通过实车回传的二进制数据提取出对算法同学有价值的数据

数据无价值,经过处理分析的数据是有价值的

  • 之前可能提取的数据只有A和B,但是之后有C数据的需求,那么意味着需要全量重新跑一次数据

  • 项目架构:

    • 请求只是把数据放入Redis的List队列当中,处理的Channel从队列去取
  • 问题:

    • 发现怎么磁盘就突然爆满了
  • 分析:

    • 从List队列当中取数据之后完成一个二进制数据的信息提取需要分钟级,由于我使用的都是无限Channel,下载Channel一直在List队列消费消息,然后将消息传入提取信息的Channel
    • 但是可能只有几个提取信息的Channel的执行,因为下载的速度远远大于提取信息的速度,导致很多二进制文件下载到本地等待提取信息

如果这个时候重启服务,那么这些等待提取信息的二进制数据对应的消息就会丢失

流程概述.png

解决办法

  • Redis 提供了 RPOPLPUSH、BRPOPLPUSH(阻塞)两个命令,含义是从 source List队列 读取消息的同时把这条消息复制到另一个 dest List队列 中(备份),并且是原子操作。
命令描述
BRPOPLPUSH source destination timeout从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
RPOPLPUSH source destination命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素
  • 相当于是两个队列,一个是source队列,还有一个是备份队列
    • 如果正确执行成功的话,就会将dest队列(备份队列)中的数据删除掉,如果异常退出的话,数据在备份队列不会删除
    • 在重启的时候drain备份队列的数据,将数据移动到source队列继续执行

解决了由List实现的轻量级队列出现的消息丢失的问题

安全队列.png

  • 这样就可以保证消息队列的可靠性

如果想使用List搭一个轻量级的消息队列,需要考虑业务可能会存在的一些问题,比如可靠性,重复消费等问题