1. 为什么我劝你别再把 info 当成"看一眼内存"的指令
很多人对 Redis 的info指令的印象,大概停留在"运维排障时敲一下,看看内存用了多少、连接数多少"这个层面。我早期也是这样,直到有一次线上一个缓存集群出现间歇性超时,监控大盘上 QPS 和内存都正常,最后是靠info里latency和commandstats两段数据才定位到问题——某个业务方在批量调用一个复杂度很高的命令,把单线程堵住了。从那以后我才真正把info当成一个"诊断仪表盘"来用,而不是一个"内存查看器"。
info是 Redis 内置的状态查询指令,它把服务端运行时的各类指标按模块分段输出,涵盖服务基本信息、客户端连接、内存占用、持久化状态、主从复制、CPU 消耗、命令调用统计、集群状态、键空间分布等。它能解决的问题非常实际:判断实例是否健康、定位性能瓶颈、评估容量水位、排查主从延迟、审计命令使用是否合理。适合谁来参考?我觉得三类人最该吃透它——一是负责 Redis 运维的工程师,二是写业务代码但需要对自己用的命令负责的后端开发,三是做容量规划和稳定性建设的同学。哪怕你只是刚接触 Redis 的新手,把info的各段含义搞明白,也比背一堆命令语法更有长期价值,因为它直接对应"这个实例现在到底怎么样"这个最核心的问题。
这篇内容我会按"整体设计思路—分段细节拆解—实操排查流程—常见坑与速查表"的顺序展开,中间穿插我自己踩过的坑和参数判断经验。所有命令和输出结构都基于 Redis 的通用实现,不同版本字段会有增减,我会在关键处标注版本差异,避免你照着老资料对不上号。
2. info 指令的整体设计与输出结构拆解
2.1 一条指令背后的分段设计逻辑
info最容易被忽略的设计点,是它默认并不返回全部内容,而是按"段"(section)组织,你可以只取关心的部分。这个设计不是随便定的,背后是性能与可读性的权衡:全量info在指标很多的实例上输出可能上千行,如果每次排障都拉全量,既浪费带宽也干扰阅读。所以 Redis 允许你用info <section>精确取段,比如info memory只看内存、info replication只看主从。
默认不带参数执行info时,返回的是"默认段集合",通常包括 server、clients、memory、persistence、stats、replication、cpu、cluster、keyspace 这些核心段,而commandstats、latencystats、errorstats这类统计段默认不返回,需要显式指定。这个细节很多人不知道,导致排查命令级问题时敲了info却找不到commandstats,还以为是指令不支持。
从实现角度看,info是同步执行的,它会在主线程里遍历各个模块收集指标。这意味着在超大实例上频繁调用全量info本身也会占用一点主线程时间,虽然单次开销很小,但如果你写了个脚本每秒全量拉一次,累积起来就不是小事了。我的建议是:日常监控用info的指定段,且采集间隔别太激进;需要全量快照时再拉全量。
2.2 各段职责的横向对照
为了让你一眼看清每段管什么,我整理了一张对照表。这张表是我自己排障时贴在便签上的版本,按"排障时最常看"的顺序排列:
| 段名 | 核心职责 | 典型排障场景 | 是否默认返回 |
|---|---|---|---|
| server | 版本、运行模式、运行时长、配置文件路径 | 确认实例身份、版本兼容性 | 是 |
| clients | 当前连接数、阻塞连接、最大连接数 | 连接打满、连接泄漏 | 是 |
| memory | 内存占用、碎片率、峰值、淘汰统计 | 内存告警、碎片过高 | 是 |
| persistence | RDB/AOF 状态、最近保存结果 | 持久化失败、fork 阻塞 | 是 |
| stats | 命令总数、命中未命中、过期键数 | 命中率低、键过期异常 | 是 |
| replication | 主从角色、偏移量、从库状态 | 主从延迟、复制断开 | 是 |
| cpu | 用户态/内核态/后台 CPU 消耗 | CPU 飙高定位 | 是 |
| commandstats | 各命令调用次数与耗时 | 慢命令、命令滥用 | 否 |
| latencystats | 各命令延迟百分位分布 | 尾延迟分析 | 否 |
| errorstats | 各类错误计数 | 客户端报错归因 | 否 |
| cluster | 集群状态、槽位分配 | 集群健康检查 | 是 |
| keyspace | 各库键数量与过期键数量 | 键分布、过期堆积 | 是 |
这张表的价值在于:当你遇到某类问题时,能立刻知道该看哪一段,而不是盲目全量拉。比如"连接数告警"直接看 clients,"主从延迟"直接看 replication,路径非常清晰。
2.3 为什么指定段比全量更值得养成习惯
我见过不少团队的监控脚本是这么写的:定时执行info,然后把整段文本丢进解析器提取几个字段。这种写法能跑,但有两个隐患。第一,全量输出随版本升级字段会变,解析器容易因为多了一行而报错;第二,全量拉取在指标多的实例上开销更大。改成info memory、info stats这种精确取段后,解析逻辑更稳定,采集开销也更可控。
还有一个更隐蔽的点:info的输出格式是"段名 + 冒号分隔的键值对",不同版本对同一字段的单位可能调整(比如内存单位、时间单位),如果你用全量文本做正则匹配,很容易匹配到别的段里同名字段。指定段之后,解析范围被限定,出错概率大幅下降。这是我在维护一套跨版本监控采集时踩过的坑,后来全部改成按段采集才稳定下来。
3. 核心分段逐项拆解与关键字段解读
3.1 server 与 clients:先确认"我是谁、谁在连我"
info server这段看起来最"静态",但排障时它是第一步。里面几个字段值得重点关注:redis_version决定你能用哪些特性、字段是否存在;redis_mode告诉你这是单机、哨兵还是集群模式,模式不同后续排查路径完全不同;uptime_in_seconds反映实例运行时长,如果这个值很小但你印象中实例跑了很久,那说明它刚重启过,可能是崩溃重启,必须查日志;config_file能确认实例加载的是哪个配置文件,避免"改了配置没生效"的乌龙——我遇到过好几次,运维改的是 A 路径的配置,实例实际加载的是 B 路径,白折腾半天。
info clients这段字段不多但极其关键。connected_clients是当前连接数,maxclients是上限,两者一对比就知道水位。blocked_clients表示正在阻塞等待的客户端数量,比如执行了阻塞类命令的客户端,这个值持续偏高往往意味着有业务在用阻塞操作且没设合理超时。client_recent_max_input_buffer和client_recent_max_output_buffer反映客户端缓冲区峰值,如果输出缓冲区异常大,可能是某个客户端消费太慢导致服务端堆积,严重时会拖垮内存。
注意:
connected_clients接近maxclients时,新连接会被拒绝,业务侧表现为连接超时。这时候别急着调大上限,先确认是不是连接池配置不合理或存在连接泄漏,盲目调大只是把问题往后推。
3.2 memory:内存水位与碎片率的正确读法
info memory是大家最熟的一段,但真正读对的人不多。核心字段有这么几个:used_memory是 Redis 分配器统计的已用内存,used_memory_rss是操作系统视角的常驻内存,used_memory_peak是历史峰值,mem_fragmentation_ratio是rss / used_memory的比值,也就是碎片率。
碎片率怎么判断?我的经验是:比值在 1 到 1.5 之间基本正常;超过 1.5 说明内存碎片偏多,可以考虑在低峰期做碎片整理(具体手段取决于版本支持情况);如果比值小于 1,说明部分内存被换出到磁盘了,这通常意味着物理内存紧张,性能会明显下降,属于危险信号。这里要强调,碎片率不是越低越好,略大于 1 是健康的,因为分配器本身有管理开销。
还有一个常被误读的字段是used_memory_dataset和used_memory_overhead的区分。前者是纯数据占用,后者是管理结构开销。如果你的数据量不大但used_memory_overhead很高,可能是键数量太多导致元数据开销大,这时候要考虑是否键的粒度太细、能否合并。maxmemory和maxmemory_policy也要一起看,确认淘汰策略是否和业务预期一致——我见过把策略设成不淘汰、结果内存打满后写入直接报错的案例,业务方还以为是 Redis 挂了。
3.3 persistence:持久化状态里的隐藏信号
info persistence这段在排障时经常被跳过,但它藏着不少信号。rdb_last_bgsave_status和aof_last_bgrewrite_status告诉你最近一次后台保存是否成功,如果是 err,说明持久化已经出问题了,只是还没影响到读写所以没人发现。rdb_last_save_time是最近一次成功保存的时间戳,如果这个时间离现在很久,而你的配置是定时保存,那就要怀疑保存是否被阻塞或失败了。
rdb_changes_since_last_save表示自上次保存以来有多少次写操作,这个值持续增长而不回落,说明保存一直没成功触发。latest_fork_usec记录最近一次 fork 的耗时(微秒),这个字段很关键:fork 耗时过长会阻塞主线程,导致请求毛刺。如果这个值达到几十毫秒甚至更高,说明实例数据量大或系统内存压力大,需要考虑调整保存策略或拆分实例。
提示:
aof_rewrite_in_progress和rdb_bgsave_in_progress为 1 时表示后台任务正在进行,此时主线程可能受 fork 影响。排查延迟毛刺时,把毛刺时间点和这两个字段对照,往往能对上。
3.4 stats 与 commandstats:命中率与命令画像
info stats里最常看的是keyspace_hits和keyspace_misses,两者算出命中率。命中率低不一定是坏事,要看业务模型:如果大量请求本来就是查不存在的键(比如防穿透逻辑),低命中率是正常的;但如果预期高命中却很低,就要查是不是键设计有问题、过期时间太短、或者缓存被频繁淘汰。expired_keys和evicted_keys也要分开看,前者是自然过期,后者是被淘汰策略清掉的,后者持续增长说明内存不够用了。
info commandstats默认不返回,需要显式指定。它按命令维度给出calls(调用次数)、usec(总耗时微秒)、usec_per_call(单次平均耗时)。这段是定位"谁在拖慢实例"的利器。我的用法是:先看calls排序找出高频命令,再看usec_per_call找出单次耗时高的命令,两者交叉就能锁定问题命令。比如某个遍历类命令调用次数不多但单次耗时极高,或者某个简单命令调用量巨大导致总耗时占比高,都能从这里看出来。
info latencystats更进一步,给出各命令延迟的百分位分布(如 p50、p99、p999),适合分析尾延迟。平均值会掩盖长尾,百分位才能反映真实用户体验。如果你的业务对 p99 敏感,这段比commandstats的平均值更有参考价值。
3.5 replication 与 cpu:主从健康与算力去向
info replication里,role告诉你当前是主还是从;connected_slaves是从库数量;每个从库的offset和主库的master_repl_offset对比,差值就是从库延迟的字节数。延迟持续增大说明从库同步跟不上,可能是网络带宽、从库负载或主库写入太猛。master_link_status为 down 时表示主从连接断了,这是必须立刻处理的信号。
info cpu这段字段少但信息密度高:used_cpu_sys是内核态消耗,used_cpu_user是用户态消耗,used_cpu_sys_children和used_cpu_user_children是后台子进程消耗。如果used_cpu_sys异常高,可能是系统调用频繁或网络 IO 压力大;如果used_cpu_user高,多半是命令计算密集。把 CPU 消耗和commandstats对照,能进一步确认是哪个命令在吃算力。
4. 实操排查流程:从 info 到定位问题的完整路径
4.1 第一步:建立基线,别等出事才看
排查的前提是知道"正常长什么样"。我的做法是在实例稳定运行一段时间后,采集一次各段的基准值存档,包括连接数区间、内存水位、命中率、命令耗时分布等。有了基线,异常时一对比就能看出偏离。比如平时connected_clients在 200 左右,突然涨到 800,即使没到上限也值得警惕,可能是连接泄漏的前兆。
采集基线时建议用指定段而不是全量,脚本里按段解析成结构化数据存起来。下面是一个采集思路的伪代码示例,展示如何按段取数并提取关键字段:
# 分别采集关键段,避免全量输出带来的解析不稳定 redis-cli info clients > clients.txt redis-cli info memory > memory.txt redis-cli info stats > stats.txt redis-cli info replication > replication.txt拿到文本后按行解析"键:值"即可。这里的关键经验是:采集脚本要对字段缺失做容错,不同版本字段有增减,硬编码字段名一旦缺失就报错,会导致整个采集链路中断。我一般会给每个字段设默认值,缺失时记录告警而不是直接崩。
4.2 第二步:按症状选段,缩小排查范围
不同症状对应不同段,这是提效的核心。我整理了一个"症状到段"的映射,实际排障时按这个走,基本不会跑偏:
| 症状表现 | 优先查看的段 | 重点字段 |
|---|---|---|
| 连接超时、拒绝连接 | clients | connected_clients、maxclients、blocked_clients |
| 内存告警 | memory | used_memory、mem_fragmentation_ratio、evicted_keys |
| 请求变慢、毛刺 | commandstats、latencystats、persistence | usec_per_call、p99、latest_fork_usec |
| 主从数据不一致 | replication | master_repl_offset、从库 offset、master_link_status |
| 持久化异常 | persistence | rdb_last_bgsave_status、aof_last_bgrewrite_status |
| CPU 飙高 | cpu、commandstats | used_cpu_user、高频高耗时命令 |
| 缓存命中率下降 | stats | keyspace_hits、keyspace_misses、evicted_keys |
这张表不是教条,实际排查往往是多段联动。比如"请求变慢",我会先看latencystats确认是哪个命令的尾延迟高,再看commandstats确认它的调用量和平均耗时,最后看persistence排除 fork 阻塞,三步下来基本能定性。
4.3 第三步:用 commandstats 做命令级归因的实操记录
分享一次真实的排查过程(细节做了脱敏)。某段时间业务反馈偶发超时,监控上 QPS 正常、内存正常、连接数正常,常规指标全绿。我先拉了info latencystats,发现某个读类命令的 p99 明显高于其他命令;接着拉info commandstats,看到这个命令的usec_per_call是同类命令的好几倍,calls也不低。进一步确认是业务方在循环里对这个命令做了大量调用,且每次操作的集合规模很大。
定位之后,处理方式不是去调 Redis 参数,而是推动业务侧改调用方式:把循环调用改成批量操作,减少单次操作的数据规模。改完之后 p99 回落,超时消失。这个案例说明,info的价值不只是"看服务端状态",更是"把服务端状态翻译成业务侧可行动的问题"。如果只盯着内存和连接数,这个问题永远定位不到。
提示:
commandstats的统计是累计值,重启后会清零。做对比分析时,要么在重启后重新建立基线,要么用两次采集的差值来计算区间内的真实调用情况,直接看累计值容易误判。
4.4 第四步:把 info 接入日常巡检的落地方式
单次排障靠人敲命令没问题,但要长期稳定,得把info的关键字段接入巡检。我的做法是选一组"红线指标"做定时检查:连接数水位超过 80% 告警、碎片率超过 1.5 告警、命中率低于基线一定比例告警、主从 offset 差值超过阈值告警、持久化状态为 err 立即告警。这些指标不需要全量采集,按段取数即可,开销可控。
巡检脚本里有个细节值得说:告警阈值要结合基线动态调整,而不是写死。比如连接数上限是 10000,但你的基线只有 200,那 80% 的 10000 是 8000,等真到 8000 早就出事了。更合理的做法是基于基线设相对阈值,比如超过基线 3 倍就预警。这个思路是我在被"阈值写死导致告警太晚"坑过之后改的。
5. 常见问题与排查技巧实录
5.1 info 输出字段对不上、找不到某段怎么办
最常见的问题是"我照着资料找某个字段,结果输出里没有"。原因通常有两个:一是版本差异,字段是后续版本新增的,老版本没有;二是段没选对,某些段默认不返回,必须显式指定。解决办法是先info全量看一眼有哪些段,再针对性地info <section>。如果确认版本支持但字段仍缺失,检查是不是该功能没启用(比如没开集群就不会有完整的 cluster 段内容)。
还有一种情况是字段名相似导致看错,比如内存相关的字段有好几个前缀相近的,单位也不同。我的习惯是看字段时连带看它的单位后缀(如_bytes、_usec、_seconds),避免把微秒当毫秒、把字节当 KB。
5.2 碎片率忽高忽低,到底该不该处理
碎片率波动是正常的,分配器在分配释放过程中本来就会产生碎片。判断要不要处理,看两点:一是碎片率是否持续高于阈值(比如长期在 1.5 以上),二是used_memory_rss是否明显高于used_memory且影响了系统内存。如果只是短时波动,不用管;如果持续偏高且内存吃紧,再考虑在低峰期做整理。整理本身有开销,别在业务高峰做。
5.3 主从延迟看着不大,业务却读到旧数据
info replication里的 offset 差值小,不代表业务读到的就是新数据。如果业务读的是从库,而从库同步存在网络往返和本地应用延迟,即使 offset 差值很小,也可能读到旧值。排查这类问题,除了看 offset,还要看从库的slave_repl_offset增长是否连续、主库写入是否集中在某些时段。我的经验是:对一致性要求高的读,别依赖从库;对延迟敏感的监控,把 offset 差值和业务侧读到的数据版本做交叉验证,比单看 offset 更可靠。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查动作 |
|---|---|---|
| info 里找不到 commandstats | 该段默认不返回 | 显式执行 info commandstats |
| 连接数缓慢上涨不回落 | 连接泄漏或连接池配置不当 | 看 clients 段,结合客户端侧连接管理排查 |
| 内存没满但写入报错 | 淘汰策略为不淘汰且已达上限 | 看 memory 段的 maxmemory 与 policy |
| 请求毛刺与持久化时间吻合 | fork 阻塞主线程 | 看 persistence 段 latest_fork_usec |
| 命中率骤降 | 键集中过期或缓存被大量淘汰 | 看 stats 段 expired_keys、evicted_keys |
| 主从 offset 差值持续增大 | 从库同步跟不上 | 看 replication 段,排查网络与从库负载 |
| CPU 用户态偏高 | 计算密集型命令调用过多 | 结合 commandstats 定位高耗时命令 |
5.5 几个我踩过的坑,直接抄结论
第一个坑:曾经用全量info做监控采集,某次版本升级后多了一个段,解析脚本的正则匹配到了错误字段,导致内存告警误报。结论是按段采集、按字段解析,别用全量文本做模糊匹配。
第二个坑:把used_memory当成操作系统实际占用去和机器内存对比,结果误判内存充足,实际used_memory_rss已经接近物理内存上限。结论是容量评估看 rss,分配器视角看 used_memory,两者要一起看。
第三个坑:主从延迟排查只看 offset 差值,忽略了从库自身的负载,结果从库因为其他任务 CPU 打满,同步慢但 offset 差值看起来不大。结论是主从问题要两端一起看,别只盯主库指标。
第四个坑:commandstats的累计值在重启后清零,做趋势对比时没注意,得出"命令调用量骤降"的错误结论。结论是统计类字段要区分累计值和区间值,重启是重要分界点。
6. 把 info 用出价值的几个进阶思路
6.1 用 info 做容量规划而不是事后救火
容量规划的核心是趋势,不是瞬时值。定期采集used_memory、connected_clients、keyspace的键数量,画出增长曲线,就能预估什么时候需要扩容。我的经验是留出至少 30% 的内存余量应对峰值和碎片,别等用到 90% 才动手。键数量的增长也要关注,键太多会导致元数据开销上升,即使数据量不大也可能内存吃紧。
6.2 用 commandstats 反推业务代码的合理性
commandstats不只是运维工具,开发也能用。定期看自己业务用到的命令的调用量和单次耗时,能发现很多代码层面的问题:循环里调单条命令、对大集合做全量操作、用了复杂度高的命令却没控制数据规模。这些问题在代码 review 时不一定看得出来,但在commandstats里一目了然。我现在的习惯是,新业务上线一段时间后,主动拉一次commandstats看看自己贡献了哪些命令、耗时占比多少,相当于给代码做一次"运行时体检"。
6.3 建立自己的 info 解读清单
最后分享一个我一直在用的方法:把最常看的字段整理成一张个人清单,标注每个字段的正常范围、异常含义、对应动作。清单不用很长,十几二十个字段就够覆盖大部分场景。时间久了你会发现,排障时根本不需要全量拉取,看一眼清单上的几个关键字段,问题方向就出来了。这份清单会随着你踩坑不断更新,它本身就是你经验的沉淀。
我个人在实际操作中的体会是,info这个指令的门槛不在"会不会敲",而在"看不看得懂、看不看得准"。同样一段输出,新手看到的是数字,老手看到的是实例的健康画像和潜在风险。把每个字段背后的含义、单位、正常区间、异常信号搞清楚,再结合业务场景去解读,info才真正从"看一眼内存"变成"诊断整个实例"的入口。后续如果你想把这块用得更深,可以沿着"按段采集做监控—按症状建排查路径—按命令做业务归因"这条线继续扩展,每一步都能落到具体的脚本和清单上,不需要额外的工具就能跑起来。