Redis 监控与故障排查实战:INFO、慢查询与大键定位
Redis 平时快得像内存一样,一旦出故障,表现往往很统一:接口超时、命中率骤降、内存莫名涨满、主从断开。真正难的不是“重启大法”,而是第一时间判断问题出在内存、命令、连接还是复制链路。本文不讲内存参数调优(站内另有《Redis 内存优化》一篇),只讲一件事:用 Redis 自带的监控手段把故障定位到点上。
问题与适用环境
本文适用于以下场景:业务反馈 Redis 变慢或超时、实例内存持续上涨、缓存命中率下降、主从复制中断,以及日常巡检想建立一套固定的看数顺序。环境为 Redis 7.x 单机或主从部署,管理机上装有 redis-cli,示例主机名为 redis-01、地址为 192.0.2.10。
前置条件
- 能用 redis-cli 连接目标实例并通过 AUTH 认证(如有密码);
- 具备 CONFIG GET 查看配置的权限(排查阶段先只读,不急着改参数);
- 了解实例的部署形态:单机、主从还是哨兵,知道从节点地址;
- 建议先把本次排查的基线记下来:正常时段的 QPS、内存和连接数,异常时才有对照。
一、读懂 INFO:逐段看关键指标
INFO 是排查的第一站,它按段输出运行状态。先整体看一遍,再按段取数:
redis-cli -h 192.0.2.10 -p 6379 INFO
redis-cli -h 192.0.2.10 -p 6379 INFO memory
redis-cli -h 192.0.2.10 -p 6379 INFO stats
redis-cli -h 192.0.2.10 -p 6379 INFO clients
Memory 段:内存与碎片
used_memory 是 Redis 分配器实际使用的内存(字节),监控告警看它的人类可读版 used_memory_human 即可;used_memory_rss 是操作系统视角的常驻内存。两者的比值就是 mem_fragmentation_ratio:略大于 1 属正常,超过 1.5 说明碎片严重、内存被“虚占”;小于 1 则意味着系统在用 swap,必须立即处理。同时对照 maxmemory:used_memory 顶到上限后,新写入会触发淘汰或报错,这是很多“内存打满”故障的直接信号。
Clients 段:连接与阻塞
connected_clients 是当前连接数,结合 maxclients(默认 10000)看是否被连接泄漏顶满;blocked_clients 是正阻塞在 BLPOP、BRPOP、XREAD 等阻塞命令上的客户端数量。偶尔大于 0 正常,若持续大于 0 且不断增长,说明消费端处理不过来或有人在生产环境滥用阻塞命令,要结合慢查询继续往下查。
Stats 段:命中率、淘汰与吞吐
instantaneous_ops_per_sec 是瞬时 QPS,看抖动最直观。缓存效果看两个累计计数器 keyspace_hits 与 keyspace_misses,命中率 = hits ÷(hits + misses)。例如 hits 为 9,500,000、misses 为 500,000,命中率就是 95%;命中率突然下跌,往往是缓存过期策略变更、批量失效或流量结构变了。evicted_keys 是因内存上限被淘汰的键数:它持续增长,说明实例在“淘汰抖动”——刚写进去就被赶出来,业务表现为命中率低、回源数据库压力大。本站内存调优那篇讲过参数怎么改,这里只强调:evicted_keys 是判断“内存不够用”的最硬证据。
二、慢查询日志:配置与 SLOWLOG 分析
Redis 单线程执行命令,一条慢命令堵住,后面所有请求排队。慢查询日志记录的是命令的纯执行耗时(不含网络传输和排队时间),两个参数控制它:
redis-cli -h 192.0.2.10 -p 6379 CONFIG GET slowlog-log-slower-than
redis-cli -h 192.0.2.10 -p 6379 CONFIG GET slowlog-max-len
slowlog-log-slower-than 单位是微秒,默认 10000 即 10ms,超过这个耗时的命令才会被记录;设为 0 记录全部命令,设为 -1 关闭。slowlog-max-len 默认 128,是环形队列长度,满了会挤掉旧记录,繁忙实例可适当调大。排查时直接取最近的记录看:
127.0.0.1:6379> SLOWLOG GET 5
1) 1) (integer) 128
2) (integer) 1762000000
3) (integer) 15230
4) 1) "KEYS"
2) "user:*"
5) "192.0.2.20:51234"
6) ""
2) 1) (integer) 127
2) (integer) 1761999900
3) (integer) 52110
4) 1) "SMEMBERS"
2) "hot:set"
5) "192.0.2.20:51108"
6) ""
127.0.0.1:6379> SLOWLOG LEN
(integer) 128
每条记录依次是:自增 id、发生时间戳、耗时(微秒)、命令及参数、客户端地址。分析时先看命令类型:KEYS、带大范围的 SCAN 误用、对大集合做 SMEMBERS/HGETALL 全量拉取,是慢查询的三大常客;再看来源地址,定位是哪台应用服务器、哪个业务在发。常用配套命令还有 SLOWLOG RESET 清空日志。注意慢日志只存在内存里,实例重启即丢,故障复盘要及时留存。
三、redis-cli 工具箱:大键、热点键与延迟
找大键:--bigkeys
redis-cli -h 192.0.2.10 -p 6379 --bigkeys
redis-cli -h 192.0.2.10 -p 6379 --bigkeys -i 0.1
--bigkeys 底层用 SCAN 渐进扫描全库,对每种类型抽样统计最大键,最后按类型汇总第一名。它对线上影响较小,但扫描仍有成本,-i 是每批扫描后的休眠秒数,生产高峰建议带上。输出里的“Biggest string found”等行就是各类型的大键名单,记下来给后面渐进处理用。
找热点键:--hotkeys(有前提)
--hotkeys 依赖 LFU 计数器采样,所以前提是淘汰策略必须为 LFU 类:先用 CONFIG GET maxmemory-policy 确认是 allkeys-lfu 或 volatile-lfu,否则扫不出结果。策略不是 LFU 时不要为了抓热点贸然在线上改策略(会影响淘汰行为),可改在从节点上临时开启 LFU 后再扫。
redis-cli -h 192.0.2.10 -p 6379 CONFIG GET maxmemory-policy
redis-cli -h 192.0.2.10 -p 6379 --hotkeys
量延迟:--latency 与 LATENCY 系列
分清“网络慢”还是“实例慢”,先用 --latency 持续发 PING 测往返耗时和抖动;--latency-history 按区间输出历史采样,适合蹲一段时间抓毛刺。实例内部的延迟事件则要打开延迟监控:把 latency-monitor-threshold 设为毫秒阈值(如 100),超过阈值的 fork、命令执行、过期删除等事件会被分类记录,然后用 LATENCY DOCTOR 出诊断报告、LATENCY LATEST 看最近事件、LATENCY HISTORY fork 看某类事件的明细。
redis-cli -h 192.0.2.10 -p 6379 --latency
redis-cli -h 192.0.2.10 -p 6379 --latency-history
redis-cli -h 192.0.2.10 -p 6379 CONFIG SET latency-monitor-threshold 100
127.0.0.1:6379> LATENCY DOCTOR
127.0.0.1:6379> LATENCY LATEST
127.0.0.1:6379> LATENCY HISTORY fork
四、内存诊断:MEMORY DOCTOR 与主动碎片整理
当 mem_fragmentation_ratio 居高不下时,运行 MEMORY DOCTOR,它会直接给出人话版诊断:碎片情况、RSS 占用、分配器状态和处理建议。配合 MEMORY STATS 看细节、MEMORY USAGE keyname 查单个键的真实占用(含内部开销)。如果确认是碎片问题且实例使用默认的 jemalloc 分配器,可开启运行时碎片整理:CONFIG SET activedefrag yes。它在后台渐进搬移内存,代价是少量 CPU,建议在业务低峰开启并观察一两天碎片率变化,而不是长期无脑打开。
127.0.0.1:6379> MEMORY DOCTOR
127.0.0.1:6379> MEMORY USAGE hot:set
127.0.0.1:6379> CONFIG SET activedefrag yes
五、大键的危害与渐进式处理
大键的危害有三层:一是单线程执行模型下,读取、删除大键都会长时间阻塞主线程,造成“假死”式抖动;二是网络带宽被单次响应打满;三是内存分布倾斜,主从同步和持久化时容易放大延迟。处理原则是“拆”和“缓”:写入侧把一个大 Hash/大集合按业务维度拆成多个小键;存量大键删除时不要用 DEL——DEL 同步释放内存同样会阻塞,改用 UNLINK,它把释放动作丢给后台线程异步完成。需要遍历或分批清理大集合内部元素时,用 SSCAN/HSCAN/ZSCAN 游标分批取、分批删,避免一次性全量操作。
127.0.0.1:6379> UNLINK hot:set
(integer) 1
127.0.0.1:6379> HSCAN big:hash 0 COUNT 500
127.0.0.1:6379> SSCAN big:set 0 COUNT 500
六、常见故障场景排查路径
场景 1:内存打满与淘汰抖动
顺序看 INFO memory 与 stats:used_memory 是否顶住 maxmemory、evicted_keys 是否持续增长、命中率是否同步下滑。再用 --bigkeys 找是否有新写入的大键在“吃”内存,最后回业务侧确认是不是有批量回填、缓存雪崩式的集中写入。先止血(暂停回填、临时扩容或调大 maxmemory),再谈治理。
场景 2:fork 导致的延迟毛刺
表现为周期性、成片出现的毫秒级毛刺,和 BGSAVE、AOF 重写的时间点对得上。看 INFO persistence 段的 latest_fork_usec(最近一次 fork 耗时,微秒)和 LATENCY HISTORY fork 的事件记录:内存越大 fork 越慢,写时复制还会放大内存占用。排查方向是错开持久化与业务高峰、控制单实例内存体量,而不是去关持久化。
场景 3:客户端连接堆积
connected_clients 异常高于基线、业务报连接超时:先看 maxclients 是否被顶满,再用 CLIENT LIST 按连接时长和空闲时间排序,找长连接不释放、空闲连接成片的来源地址,多半是某台应用的连接池泄漏或新版本未复用连接。对症的是修客户端和连接池配置,单纯调大 maxclients 只是续命。
场景 4:主从同步断裂
在从节点执行 INFO replication:看 master_link_status 是否为 down、master_last_io_seconds_ago 是否不断变大;再在主节点看同一段,确认从节点是否还在 slave 列表里。常见原因是复制积压缓冲区太小、全量同步频繁:Stats 段的 sync_full 次数不断上涨而 sync_partial_ok 不涨,说明从节点老是追不上只能全量同步,要结合网络抖动和 repl-backlog-size 一起看。先恢复链路,再查根因,别急着重启从节点。
redis-cli -h 192.0.2.11 -p 6379 INFO replication
redis-cli -h 192.0.2.10 -p 6379 INFO replication
redis-cli -h 192.0.2.10 -p 6379 CLIENT LIST
验证
按本文走完一轮后,做三个确认:第一,INFO 各段关键指标已截图或落盘,能说出每一项的当前值和含义;第二,故意在测试库执行一条慢命令(如对大集合做全量读取),SLOWLOG GET 能把它捞出来,说明监控链路是通的;第三,--bigkeys、MEMORY DOCTOR 均能正常输出报告,延迟监控开启后 LATENCY LATEST 有事件记录。三个都过,这套排查手段才算真正可用,而不是出了事才发现命令没权限。
常见问题
命中率要多高才算正常?没有统一标准,取决于业务:纯缓存场景一般希望 95% 以上;命中率低但 evicted_keys 为 0,多半是业务本身缓存穿透或键设计问题,不是实例故障。
--hotkeys 扫不出结果?先查 maxmemory-policy,不是 LFU 类策略就没有 LFU 计数器,自然没有热点数据,属于前提不满足,不是命令坏了。
慢日志里全是正常命令,但业务还是慢?慢日志只记执行耗时,不记排队和网络时间。此时去看 LATENCY 的 command 事件和 --latency 的网络往返,把“排队堵”和“路上慢”分开再下结论。
blocked_clients 一直是几十,正常吗?用阻塞命令做队列消费的系统有常驻阻塞连接是正常的,关键看趋势:稳定不变是业务形态,持续攀升才是消费跟不上。
小结
Redis 排查的顺序感比命令本身更重要:先 INFO 分段定方向(内存、连接、命中、淘汰),再用慢查询定位到具体命令和来源,接着用 --bigkeys、--hotkeys、LATENCY、MEMORY DOCTOR 把“大键、热点、延迟毛刺、碎片”四个高频元凶逐个排除,最后按场景路径收尾。把这套顺序练成巡检习惯,大多数 Redis 故障都能在十分钟内定位到点上,而不是停留在“感觉它变慢了”。







