Redis 5.0 Stream 消费者 pending 消息堆积通常因消费者崩溃未 ACK 导致,清理核心是用 XCLAIM 接管空闲消息所有权,再用 XACK 确认或 XDEL 删除。适用场景是消费者组内有僵尸消费者,风险边界是强制接管可能引发重复消费,直接删除会导致业务数据丢失。
先说结论:清理 pending 消息需先识别空闲超时条目,通过命令强制转移所有权后确认删除,不可直接清空消费者组。
- 先确认:使用
XPENDING查看 pending 列表及空闲时长 - 先处理:对超过阈值的消息用
XCLAIM转移给维护消费者 - 再验证:再次执行
XPENDING确认数量下降且无异常阻塞
命令速用版
以下命令可直接在 redis-cli 执行,替换占位符为实际业务名称:
# 查看消费者组 pending 消息概要 XPENDING mystream mygroup # 查看特定范围内 pending 消息详情(含空闲时间) XPENDING mystream mygroup - + 10 # 接管空闲超过 60000ms 的消息给新消费者 new_consumer XCLAIM mystream mygroup new_consumer 60000 id1 id2 id3 # 确认已处理的消息(清理 pending 状态) XACK mystream mygroup id1 id2 # 强制删除无法处理的消息(数据丢失风险) XDEL mystream id1 id2
为什么会这样
Pending 消息过多是因为消费者组(Consumer Group)机制记录了已投递但未确认的消息列表(PEL)。
当消费者使用 XREADGROUP 获取消息后,Redis 会将消息放入 PEL 并标记为 pending 状态。只有收到 XACK 命令后,消息才会从 PEL 移除。如果消费者进程崩溃、网络断开或逻辑卡死未发送 ACK,消息会一直保留在 pending 状态,导致新消息无法被该消费者组正常调度,内存持续增长。
分步处理
按以下步骤清理堆积,操作前建议对 key 进行备份:
- 评估堆积情况
执行XPENDING mystream mygroup。返回结果包含 pending 总数、最小/最大 ID、消费者列表。如果总数过大,需分批处理。 - 识别僵尸消息
执行XPENDING mystream mygroup - + 10。查看返回结果中的空闲时间(idle time)。筛选出 idle 时间远超正常处理耗时的消息 ID。 - 接管消息所有权
使用XCLAIM将超时消息转移给一个正常的维护消费者。
命令:XCLAIM mystream mygroup maint_consumer 60000 id1 id2 ...
参数60000代表最小空闲时间毫秒数,只有超过此时间的消息才会被转移。 - 确认或删除
接管后,业务逻辑需判断消息是否可重放。可重放则处理后发送XACK;不可重放或有毒消息则使用XDEL从流中彻底删除。
怎么验证是否生效
执行清理操作后,再次运行 XPENDING mystream mygroup。
观察返回的 pending 总数是否显著下降。同时监控消费者组 lag 状态,确认新消息能正常被消费。检查应用日志,确认接管的消息没有引发重复业务副作用。
常见坑
- MINIDLE 设置过短:如果
XCLAIM的空闲时间阈值设置太小,可能从正常工作的消费者手中抢走消息,导致重复消费。 - 直接删除消费者组:使用
XGROUP DESTROY会清空所有 pending 状态但也会丢失消费进度,仅建议在测试环境或数据可丢弃场景使用。 - 忽略消息重放副作用:接管后的消息重新处理可能触发重复扣款或通知,业务层需实现幂等性。
常见问题
XCLAIM 和 XACK 有什么区别?
XCLAIM 用于变更消息所有权,将 pending 消息从一个消费者转移给另一个;XACK 用于确认消息已处理完成,将消息从 pending 列表中移除。
消费者还在运行但 pending 不减少怎么办?
检查消费者代码逻辑,确认是否在业务处理完成后调用了 XACK 命令,或者是否存在异常捕获块漏发 ACK 的情况。
Redis 5.0 支持 XAUTOCLAIM 吗?
不支持,XAUTOCLAIM 是 Redis 6.2 引入的命令,5.0 版本必须使用 XCLAIM 配合 XPENDING 手动管理。
参考来源
- Redis Documentation, Command Reference, https://redis.io/commands/
- Redis Documentation, Streams, https://redis.io/docs/data-types/streams/