Redis的Stream类型自5.0版本推出以后,逐渐成为消息队列和事件溯源场景中的重要结构。当我们需要确认某个Stream内部到底存了多少消息、消费者组的工作状态是否正常、有没有消费者卡住不动时,XINFO就是最直接也最权威的查询入口。它并不是用来读写消息的,而是专门暴露Stream及其附属对象的元数据,帮助运维和开发在不出错的前提下看清运行全貌。

一、XINFO STREAM:摸清流本身的底细
XINFO STREAM是最基础也最常用的子命令,它的作用是返回指定Stream自身的结构信息。执行后会得到一系列字段,比如length表示当前消息总数,radix-tree-keys和radix-tree-nodes反映底层基数树压缩情况,first-entry与last-entry分别是首尾消息内容,entries-added记录历史累计追加数。这些信息对于判断流是否无限膨胀、是否有写入但无人消费非常关键。
在真实业务里,假设有一个订单事件流order_events,我们可以用如下命令查看:
127.0.0.1:6379> XINFO STREAM order_events
1) length
2) (integer) 1250
3) radix-tree-keys
4) (integer) 3
5) radix-tree-nodes
6) (integer) 4
7) last-generated-id
8) 1690000000000-0
9) first-entry
10) 1) 1689990000000-0
2) 1) "type"
2) "create"
3) "uid"
4) "1001"
11) last-entry
12) 1) 1690000000000-0
2) 1) "type"
2) "pay"
3) "uid"
4) "1050"
13) entries-added
14) (integer) 1250
从上面的输出能看出,流里一共有1250条消息,首条是创建事件,末条是支付事件,说明生产端在正常写入。如果此时length很大而消费者组pending也很大,就说明消费端处理滞后。相比直接XREAD遍历,XINFO STREAM的消耗极小,因为它只读取元数据而不反序列化全部消息体。
需要注意的是,first-entry和last-entry在流非常大时也可能只展示简要结构,但足以判断时间跨度。很多新手会误以为XINFO STREAM能列出全部消息,其实它只给边界样本,完整消息仍需XREAD或XRANGE获取。理解这一点能避免误用导致网络开销暴涨。
二、XINFO GROUPS:掌握消费者组的消费进度
当Stream被多个消费者组订阅时,XINFO GROUPS可以列出每个组的名称、已投递的最大ID、待确认消息数、空闲毫秒数等。其中last-delivered-id代表该组已经发给消费者的最高序号,pending代表还没被XACK确认的消息量,这个数值如果持续增长,往往意味着消费者故障或逻辑漏 ack。
以下示例展示如何观察组状态:
127.0.0.1:6379> XINFO GROUPS order_events 1) 1) name 2) "cg_1" 3) consumers 4) (integer) 2 5) pending 6) (integer) 35 7) last-delivered-id 8) 1690000000000-0 2) 1) name 2) "cg_2" 3) consumers 4) (integer) 1 5) pending 6) (integer) 0 7) last-delivered-id 8) 1689995000000-0
从结果看,cg_1有35条待确认,且有两个消费者,可能其中一个已经掉线但消息已分配;cg_2则完全追上。针对cg_1,我们可以进一步用XPENDING拉出具体哪些ID卡住,再决定是否用XCLAIM转移给活着的消费者。XINFO GROUPS本身不解决堆积,但它是发现堆积的第一道哨卡。
在集群部署中,如果客户端报告“消息丢了”,先查XINFO GROUPS基本能分清是生产没写、组没建、还是组卡住。它比翻应用日志更快,因为Redis本身就是状态源头。另外,消费者组空闲时间(name之后的字段在某些版本以毫秒显示)也能辅助判断是否有长期无消费的僵尸组,便于定期清理。
三、XINFO CONSUMERS:定位单个消费者的悬挂消息
在确认了某个组有问题之后,XINFO CONSUMERS可以深入到组内的某个具体消费者,查看它的pending数量、空闲时间以及已下发未确认的消息样本。这个粒度对于多实例部署尤其重要,因为往往只是其中一个Pod逻辑异常,导致它名下的消息全部悬挂。
调用方式是在组名后加上消费者名:
127.0.0.1:6379> XINFO CONSUMERS order_events cg_1 1) 1) name 2) "consumer_a" 3) pending 4) (integer) 30 5) idle 6) (integer) 120000 2) 1) name 2) "consumer_b" 3) pending 4) (integer) 5 5) idle 6) (integer) 500
上面显示consumer_a已经空闲120秒却还挂着30条pending,而consumer_b几乎实时处理。这种不对称基本指向consumer_a进程卡死或重启后未正确处理中断。此时可以结合XPENDING与XCLAIM把consumer_a的pending消息迁走,保障业务连续性。
从权限与性能角度看,XINFO CONSUMERS只读取内存结构,不会阻塞主线程过久,即便在百万级消息的流上也能瞬间返回。但它返回的pending只是计数和idle,不展开ID列表,所以详细 reclaim 方案仍需配合其他命令。把XINFO三层子命令串起来用,就形成了一套从流到组再到个人的完整观测链路,这也是Redis官方推荐的健康检查路径。
四、常见误用与查询组合建议
不少团队在监控脚本里只定时跑XINFO STREAM,却忽略了GROUPS和CONSUMERS,结果流长度正常就以为没问题,实际上组已经堆积成山。正确的做法是三层都采集,尤其GROUPS的pending应作为核心告警指标。另外有人把XINFO当成调试命令偶尔手写,其实它很适合写进Prometheus exporter,用redis-cli或连接池周期性拉取。
还有一个典型误区是试图用XINFO查询已删除的消息。Stream的XDEL只是做逻辑标记,XINFO STREAM的length会相应减少,但底层树节点不一定立刻回收,因此不能把它当作精确审计工具。若需要强一致审计,应在业务层另建日志。总体而言,XINFO系列命令设计精简、开销低,是Stream运维不可绕开的基础能力,掌握其输出字段含义能显著降低排障时间。