redis实现消息队列


✅ 一、使用 List 实现消息队列的原理(经典队列模型)

Redis List 本质是什么?

Redis 的 List 是一个 双向链表(quicklist 实现),支持从两端高效地插入和弹出元素。

队列模型怎么实现?

你可以把 List 当成一个先进先出的队列:

  • 生产者使用 LPUSH 把消息推入队列(左边)

  • 消费者使用 RPOP 弹出队列(右边)

  • 如果用 BRPOP,消费者会阻塞等待直到有消息可读

⚙️ 工作机制示意图:

生产者(LPUSH) ---> [msg3, msg2, msg1] ---> 消费者(RPOP/BRPOP)

关键点:

  • 消息是一次性消费的,消费就删除

  • 消息存储在内存中,重启会丢失(除非启用持久化 RDB/AOF)

  • 没有“确认机制”,一旦取出就认为成功消费,失败了消息就丢了

  • 只有一个消费者能消费某条消息(适合单消费者任务)


✅ 二、使用 Pub/Sub 实现发布订阅原理(实时广播模型)

Pub/Sub 本质是什么?

Redis Pub/Sub 是一种观察者模式:发布者发消息,所有订阅者都能实时收到。

消息流动原理:

  • 订阅者用 SUBSCRIBE channel 监听频道

  • 发布者用 PUBLISH channel message 发消息

  • Redis 内部维护一个“订阅表”,将消息转发给所有订阅者

⚙️ 工作机制示意图:

         ---> client1 (订阅中)
        /
发布者 ---> Redis ---> client2 (订阅中)
        \
         ---> client3 (订阅中)

关键点:

  • 消息是实时广播的,一发出就推送给所有在线订阅者

  • 订阅者必须在线,否则收不到消息(没有消息存储)

  • 无法确认消息是否被成功处理

  • 不适合可靠性要求高的业务(如支付、订单)


✅ 三、使用 Stream 实现队列的原理(功能最强的方式)

Stream 本质是什么?

Redis Stream 是一种可持久化、可消费确认、支持多消费者组的日志结构数据类型,很像 Kafka。

核心结构:

  • 每条消息都有一个唯一的 ID(时间戳+序号)

  • 消费组(Consumer Group)可以追踪自己的消费进度

  • 每个组有多个消费者,可以做负载均衡

  • 可以手动 ack 确认消息

⚙️ 工作机制图(消费组模式):

生产者(XADD)
    ↓
 Stream(日志结构) --> 消费组A --> consumer1(读、ACK)
                     \--> consumer2

Stream 的关键机制:

1. 消息持久化

所有消息存储在内存+磁盘,直到被显式删除(XDEL)或设置了最大长度(MAXLEN)

2. 消息ID

自动生成或自定义,格式如:1693566729543-0

3. 消费组(XGROUP)

每个组有自己的消费位置指针,互不干扰

4. ACK 确认机制(XACK)

只有被消费者确认(ack)后,消息才算“处理完成”

5. 待处理队列(PEL)

未被 ack 的消息会留在 Pending List,可以重试(用 XPENDING 查看)

6. 可重复消费

多个消费组可以重复消费同一条消息(广播型消费)


举个完整例子:Stream 消费组流程

  1. 生产者发送:

XADD mystream * msg "hello"
  1. 创建消费组:

XGROUP CREATE mystream mygroup 0 MKSTREAM
  1. 消费者读取:

XREADGROUP GROUP mygroup consumer1 STREAMS mystream >
  1. 消费完成后确认:

XACK mystream mygroup 1693566729543-0
  1. 如果消费者挂掉了没 ack,另一个消费者可以用 XPENDING 查看并 XCLAIM 抢过来处理


✅ 总结:三种方式对比原理

项目 List(列表队列) Pub/Sub(广播) Stream(流)
消息存储 内存(非持久) 不存储 内存+磁盘持久化
消息可重复读 是(所有订阅者) 是(消费组)
多消费者 ✅ 广播 ✅ 负载均衡+广播
ACK 确认机制 ✅ 支持
离线可读 ✅ 支持
场景推荐 简单任务队列 实时推送 高可用、可靠队列

你可能感兴趣的:(redis)