• 基于Redis List实现消息队列
  • 发布于 2个月前
  • 295 热度
    0 评论
一 背景
在前面讲Redis Streams时,谈到过它最主要的用途是实现消息队列。那么在Redis Streams出现之前,基于Redis如何实现消息队列呢?有两种方案:1 基于Redis List 来实现消息队列;2 基于发布订阅 (pub/sub) 来实现消息队列。这篇文章讲的是如何基于Redis List实现消息队列。

二 关于消息队列
2.1 何为消息队列
消息队列(Message Queue)是一种常见的软件架构模式,用于传递和处理异步消息。它解耦了发送消息的应用和接收消息的应用之间的直接依赖关系,使得消息的发送者和接收者可以独立地演化和扩展。

2.2 原理
消息队列的基本原理是发送者将消息发送到一个代理(即消息队列),然后接收者从该代理中获取并消费消息。在这里,它充当了消息的缓冲区,确保消息的可靠传递和持久化存储,同时还提供了高吞吐量、低延迟和可伸缩性。具体如下图所示:

2.3 消息队列的优点
1.应用解耦
2.异步通信
3.消息持久化
4.可靠性和可扩展性

三  Redis List 如何实现消息队列
Redis list 的这种数据结构天然支持消息队列,因为list实质上就是一个双向链表。分三部分讲解,如下:

3.1 相关操作命令
实现队列的相关命令如下:

基于Redis List实现队列时,生产消息的流程可以抽象成将数据追加到 list 尾部的操作;同时,可以把消费消息的流程抽象为一次从 list 头部摘取数据的操作. 如此这般,一个简易版的消息队列就实现了。

3.2 基于Redis List 的消费流程
首先是创建对应的消息队列,在Redis中 list 对应的 key 则对应为消息的 topic 名称。
其次是生产者开始生产消息(其实就是给list里面添加消息):
127.0.0.1:6379> lpush test 攻城狮joe
(integer) 1
127.0.0.1:6379>
最后就是消费者消费消息,使用rpop:
127.0.0.1:6379> rpop test
"\xe6\x94\xbb\xe5\x9f\x8e\xe7\x8b\xaejoe"
127.0.0.1:6379>
以上操作就实现 了一个简单的消息队列;需要说明的是,Redis 的 rpop 指令是非阻塞型的,也就是说,即使在 list 没有数据时,也会即时返回一个结果为 nil 的响应,类似下面这样:
127.0.0.1:6379> rpop test
(nil)
127.0.0.1:6379>
在这个过程中,最理想的方式是:在 list 中有数据到达时,消费者可以即时获取到对应的结果;如果 list 数据为空,那么消费者 陷入阻塞等待的状态,直到有数据是才被唤醒进行消费。

所以,Redis 还提供了 BLPOP、BRPOP 这种阻塞式读取的命令(带 B-Bloking的都是阻塞式),客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据。这种方式就节省了不必要的 CPU 开销。

先设置BRPOP等待:

第一个参数是list的key(也可以认为是topic的名称),第二个参数表示阻塞等待的超时时长,达到此阈值仍未获取数据时会返回 nil. 如果设置为 0 ,则代表没有这个超时限制。

当给对应的topic发送消息时:下图右半部分可以看到,接收到消息了,(175.02s)表示等待的时长。

3.3 基于Redis LIst实现消息队列的局限性
首先是没有可靠的ACK模式,简单说,就是 List 队列中的消息一经发送出去,便从队列里删除。如果由于网络原因消费者没有收到消息,或者消费者在处理这条消息的过程中崩溃了,消息就真的丢失了;其次,是没法支持布/订阅模(pub/sub) 式的,如果此时存在多个消费者组,各自需要一份数据时,此时是无法支持这样的需求的。
用户评论