上篇文章记录了使用Redis当中List实现消息队列
解决的问题
- 这篇文章则是记录了如何解决Redis中List实现消息队列出现的消息丢失的问题
业务场景
- 负责的项目:
- 通过实车回传的二进制数据提取出对算法同学有价值的数据
数据无价值,经过处理分析的数据是有价值的
-
之前可能提取的数据只有A和B,但是之后有C数据的需求,那么意味着需要全量重新跑一次数据
-
项目架构:
- 请求只是把数据放入Redis的List队列当中,处理的Channel从队列去取
-
问题:
- 发现怎么磁盘就突然爆满了
-
分析:
- 从List队列当中取数据之后完成一个二进制数据的信息提取需要分钟级,由于我使用的都是无限Channel,下载Channel一直在List队列消费消息,然后将消息传入提取信息的Channel
- 但是可能只有几个提取信息的Channel的执行,因为下载的速度远远大于提取信息的速度,导致很多二进制文件下载到本地等待提取信息
如果这个时候重启服务,那么这些等待提取信息的二进制数据对应的消息就会丢失
解决办法
- Redis 提供了
RPOPLPUSH、BRPOPLPUSH(阻塞)两个命令,含义是从 source List队列 读取消息的同时把这条消息复制到另一个 dest List队列 中(备份),并且是原子操作。
| 命令 | 描述 |
|---|---|
| BRPOPLPUSH source destination timeout | 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
| RPOPLPUSH source destination | 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素 |
- 相当于是两个队列,一个是source队列,还有一个是备份队列
- 如果正确执行成功的话,就会将dest队列(备份队列)中的数据删除掉,如果异常退出的话,数据在备份队列不会删除
- 在重启的时候drain备份队列的数据,将数据移动到source队列继续执行
解决了由List实现的轻量级队列出现的消息丢失的问题
- 这样就可以保证消息队列的可靠性
如果想使用List搭一个轻量级的消息队列,需要考虑业务可能会存在的一些问题,比如可靠性,重复消费等问题