持久化

Redis Stream 主要用于消息队列(MQ,Message Queue)。与传统的 Pub/Sub(发布订阅)那种“阅后即焚”的模式不同,Redis Stream 的持久化可以通过以下三个核心维度来体现:


1.消息的物理持久化

Redis Stream 的数据结构是作为 Redis Key 存储在内存中的。这意味着它直接受 Redis 自身的持久化机制保护:

  • AOF (Append Only File): 每当你执行 XADD 写入一条消息时,Redis 会将该指令记录到 AOF 日志中。即使 Redis 宕机,重启后也会通过回放 AOF 恢复所有的消息。
  • RDB (Snapshot): 定时将内存中的 Stream 数据生成快照保存到磁盘。
  • 对比: Pub/Sub 只是内存中的实时转发,不占用空间也不存入磁盘,一旦重启,未消费的消息彻底消失。

2.消费进度的持久化

这是 Redis Stream 作为 MQ 最强大的地方。它能记录每个消费者组看到哪儿了

  • 状态存储: 消费者组的 last_delivered_id(最后交付 ID)是持久化的。

  • 体现: 如果你的消费者程序崩溃了,重启后只需再次连接,Redis 会告诉它从上次断开的位置继续消费,而不会丢失中间产生的消息。

3.消息确认与待处理列表

edis Stream 保证消息“不丢失”不仅是靠存入磁盘,还靠可靠交付机制

  • PEL 机制: 当消费者读取消息但尚未发送 XACK(确认)时,Redis 会在内部的 PEL 列表中持久化记录这条消息。

  • 体现: 如果消费者拉取了消息但处理到一半宕机了,这条消息依然在 Redis 的 PEL 中。下次启动时,可以通过 XPENDING 指令找回这些“处理中”的消息进行重试。


结构

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

Redis Stream 结构

每个 Stream 都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加消息时自动创建。

Consumer Group: 消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。

last_delivered_id: 游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。

pending_ids: 消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。

消费组

一份数据,多种用途

一个 Redis Stream 通常可以分配多个消费组。分配多个消费组的主要目的是实现 “一份数据,多种用途”。假设有一个电商系统的“订单流”,消费组 A (Inventory_Group):负责扣减库存。消费组 B (Shipping_Group):负责通知物流发货。消费组 C (Data_Warehouse_Group):负责将数据同步到分析数据库。

这样的好处是,每个消费组都有自己独立的 last_delivered_id(偏移量)。组 A 处理到哪儿了,完全不影响组 B。每一条进入 order_stream 的消息,都会分别发送给组 A、组 B 和 组 C。

组间广播,组内竞争

虽然 Stream 可以有多个组,但在同一个消费组内部,通常会有多个消费者(Consumers)

组内的消费者(如 worker_1, worker_2)是竞争关系。一条消息如果被 worker_1 抢走了,worker_2 就不会再收到它。提高横向扩展处理能力,加快消费速度。