XREAD单消费者会漏消息,因其无消费位点记录且不处理pending消息,必须用XREAD GROUP配合XACK/XPENDING/XCLAIM才能确保至少一次交付。

为什么XREAD单消费者会漏消息
因为 XREAD 默认是阻塞读,但一旦超时或连接中断,没来得及处理的 pending 消息不会自动重推——它只管“拉一次”,不保证“交付成功”。你用 count 1 + block 0 看似实时,实则跳过了 pending 队列恢复逻辑。
- 必须显式用
XREAD GROUP启动消费者组,哪怕只有 1 个消费者 -
XREAD(无 GROUP)本质是游标读,不记录消费位点,重启后从头开始或直接跳过 - 真实点对点场景中,“单消费者”不等于“不用消费者组”,而是
GROUP里只起一个 client
XADD 发送时必须带消息 ID 吗
不必须,但强烈建议用 * 让 Redis 自动生成递增 ID;手动指定 ID 只在需要严格顺序对齐或幂等重放时才用。乱填非递增 ID(比如 1-1 后跟 0-1)会导致 XREAD 阻塞失效甚至报错 ERR The ID specified in XREAD is equal or smaller than the target stream top item。
- 普通场景一律用
XADD mystream * field value - 要回溯测试?用
XADD mystream 1600000000000-0 field value手动插老时间戳 ID - 避免用纯数字 ID(如
123),Redis 要求格式为ms-seq,否则报错ERR Invalid stream ID specified as argument
如何确保每条消息只被一个消费者拿到
靠消费者组 + XPENDING + XCLAIM 组合实现“至少一次”语义下的实际单次交付。单纯依赖 XREAD GROUP 不够——如果消费者崩了,消息会卡在 pending 状态,但不会自动转给其他人(因为你是点对点,不是广播)。
- 创建组:
XGROUP CREATE mystream mygroup $ MKSTREAM - 读取消息:
XREAD GROUP mygroup consumer1 COUNT 1 STREAMS mystream > - 处理完必须调
XACK mystream mygroup <id>,否则下次XREAD还会返回它 - 消费者宕机?用
XPENDING mystream mygroup - + 10查 pending 消息,再用XCLAIM抢过来(点对点下通常就是自己重试)
Stream 做点对点比 Pub/Sub 或 List 好在哪
核心就一条:有持久化位点 + 可追溯历史。Pub/Sub 没存储,断连即丢;List 的 BRPOP 虽能阻塞,但无法按 ID 回溯、无法查看谁消费了哪条、也无法安全地重新分配失败任务。
- Stream 支持
XTRIM控制长度,避免无限膨胀 - 同一个 stream 可同时服务多个独立点对点通道(不同 group),复用底层结构
- 注意:
XLEN和XPENDING是 O(1),但XRANGE扫全量是 O(N),别在大 stream 上裸用
事情说清了就结束。真正难的不是发和收,是消费者挂了以后怎么判断该不该重试、重试时怎么避免重复处理——这得结合业务状态机,Redis 只管消息流,不管你的订单是不是已支付。

















