Redis 排查总览与巡检清单
Redis 在多数系统里并不是“一个缓存组件”,而是挡在数据库前的唯一闸门:它的延迟抖动会直接翻译成数据库的 QPS 尖峰,它的内存打满会直接翻译成业务侧的写失败。本章给出 Redis 问题的排查顺序、必须看的 INFO 字段、一张阈值参考表和一套十分钟能跑完的巡检清单。
为什么 Redis 的故障半径等于全站
| 故障形态 | 直接表现 | 传导路径 | 最终后果 |
|---|---|---|---|
| 大量 key 同时过期 | 命中率骤降 | 请求全部回源数据库 | 数据库连接池耗尽、雪崩 |
| 单个分片不可用 | 部分 key 报错 | 无降级逻辑的调用直接失败 | 某业务模块整体不可用 |
| 内存打满触发淘汰 | 数据被静默删除 | 缓存长期低命中 | 读压力持续压在数据库 |
| 主从切换 | 秒级超时与报错 | 客户端未刷新拓扑 | 热点接口 P99 飙升 |
| 慢命令占住单线程 | 所有命令排队 | 全部依赖缓存的接口变慢 | 全站延迟抖动 |
一句话:只要业务无降级地强依赖 Redis,Redis 的抖动就是全站的抖动。所以排查的第一目标不是“找出那条慢命令”,而是“先让请求不再雪崩到数据库”。
排查顺序
1. 客户端报错类型 连接被拒 / 读写超时 / 命令报错 / MOVED,先分清类别
2. 连接与客户端缓冲 connected_clients、blocked_clients、CLIENT LIST 的 omem 与 qbuf
3. 慢查询与阻塞 slowlog get、latency latest,确认是否有命令占住单线程
4. 内存与淘汰 used_memory 与 maxmemory、evicted_keys、内存碎片率
5. 持久化 RDB fork 耗时、AOF 重写状态、最近一次后台保存是否失败
6. 主从与集群 master_link_status、offset 差、cluster_state
7. 宿主资源 CPU steal、网卡丢包、swap、磁盘 IO
顺序反了会白费时间:客户端报“连接超时”时,八成问题在连接数与阻塞,而不是内存;直接去翻内存,往往会错过正在运行的那条慢命令。
INFO 各段落该看哪几行
redis-cli info 输出很长,日常只需要盯住下面这些字段。
| 段落 | 关键字段 | 判读要点 |
|---|---|---|
| clients | connected_clients、blocked_clients | 连接数逼近 maxclients 会开始拒绝新连接;阻塞客户端数持续大于 0 说明有阻塞型命令或慢客户端 |
| memory | used_memory、used_memory_rss、maxmemory、mem_fragmentation_ratio | 前者是分配器记账,后者是操作系统实际占用,比值异常见第 25 章 |
| stats | keyspace_hits、keyspace_misses、evicted_keys、expired_keys、rejected_connections | 命中率、淘汰、过期、拒连四个信号都在这一段 |
| replication | role、master_link_status、master_last_io_seconds_ago、master_repl_offset | 从库掉线或延迟过大,读流量就会读到旧数据 |
| persistence | rdb_last_bgsave_status、aof_last_bgrewrite_status、latest_fork_usec | 后台保存失败要立刻处理;fork 耗时直接对应延迟毛刺 |
| commandstats | cmdstat_<命令> 的 usec_per_call | 用于定位“哪类命令平均耗时最高” |
| errorstats | errorstat_<错误类型> | Redis 6 起可直接看错误类型分布与次数 |
# 一条命令抽出最需要的字段
redis-cli info | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy|connected_clients|blocked_clients|keyspace_hits|keyspace_misses|evicted_keys|expired_keys|rejected_connections'
关键指标阈值参考
| 指标 | 健康 | 关注 | 告警 | 说明 |
|---|---|---|---|---|
命中率 hits/(hits+misses) | 大于 95% | 90% ~ 95% | 小于 90% | 低于 90% 时数据库压力通常已经翻倍 |
evicted_keys 增长 | 0 | 偶发小幅 | 持续增长 | 内存不足,正在删掉有用的数据 |
blocked_clients | 0 | 1 ~ 5 瞬时 | 持续大于 10 | 排查阻塞型命令与慢客户端 |
connected_clients | 小于 maxclients 的 60% | 60% ~ 85% | 大于 85% | 连接泄漏或上游未复用连接 |
used_memory / maxmemory | 小于 70% | 70% ~ 85% | 大于 85% | 需给 fork 与 AOF 重写留余量 |
mem_fragmentation_ratio | 1.0 ~ 1.5 | 1.5 ~ 2.0 | 大于 2.0 或小于 1.0 | 大于 2 是碎片,小于 1 说明已经用了 swap |
latest_fork_usec | 小于 200ms | 200ms ~ 1s | 大于 1s | 对应后台保存时的延迟毛刺 |
master_last_io_seconds_ago | 小于 1 | 1 ~ 5 | 大于 10 | 复制链路或从库负载有问题 |
| 主从 offset 差 | 小于 1MB | 1MB ~ 10MB | 大于 10MB | 差值持续扩大说明复制跟不上 |
rejected_connections | 0 | 偶发 | 持续增长 | 已达 maxclients,扩连接或查泄漏 |
命中率要按分钟级曲线看,不要在故障发生时用累计值判断——累计值会把白天正常时段的表现稀释进去,看起来永远“还行”。
十分钟巡检清单
# 1. 存活与基本信息
redis-cli ping
redis-cli info server | grep -E 'redis_version|uptime_in_seconds|config_file'
# 2. 连接与客户端
redis-cli info clients
redis-cli client list | head -20
# 3. 内存与淘汰
redis-cli info memory | grep -E 'used_memory_human|used_memory_rss_human|maxmemory_human|maxmemory_policy|mem_fragmentation_ratio|mem_clients_normal'
# 4. 命中率、淘汰与拒连
redis-cli info stats | grep -E 'instantaneous_ops_per_sec|keyspace_hits|keyspace_misses|evicted_keys|expired_keys|rejected_connections'
# 5. 持久化状态
redis-cli info persistence | grep -E 'rdb_last_bgsave_status|rdb_changes_since_last_save|latest_fork_usec|aof_last_bgrewrite_status'
# 6. 主从与集群
redis-cli info replication | grep -E 'role|connected_slaves|master_link_status|master_repl_offset|slave_repl_offset'
redis-cli cluster info
# 7. 慢查询与延迟事件
redis-cli slowlog len
redis-cli slowlog get 10
redis-cli latency latest
现象到下一步的对照表
| 客户端看到的现象 | 常见原因 | 先执行什么 |
|---|---|---|
Connection refused | 实例未启动、端口错、只监听 127.0.0.1 | ss -lntp | grep 6379、redis-cli ping |
| 连接或读超时 | 连接数打满、单线程被阻塞 | info clients、slowlog get、client list |
OOM command not allowed | 内存已满且策略为 noeviction | info memory,评估扩容或改淘汰策略 |
MISCONF 或保存失败 | 磁盘满、目录权限错、fork 失败 | info persistence、df -h、看 Redis 日志 |
CLUSTERDOWN | 槽未全部覆盖,有分片掉线 | cluster info、cluster nodes |
MOVED / ASK | 客户端未开启集群模式 | 用 redis-cli -c 或集群感知客户端 |
READONLY You can't write against a read only replica | 写请求被路由到从库 | 查客户端拓扑与故障转移后的地址配置 |
处置动作
- 命中率骤降:先确认是否有批量 key 同时过期或被驱逐,把过期时间打散,并对核心接口临时加本地缓存兜底。
- 内存告急:优先扩容或清理明确可弃的数据,不要临时改成
allkeys-lru就把热数据一起丢掉。 - 阻塞型故障:先用
CLIENT KILL处置慢客户端,再用UNLINK、SCAN分批替代大DEL与KEYS。 - 主从异常:先判断是网络还是从库过载,从库过载时把它从读负载均衡中摘除。
所有动作都要有回退路径,改配置前先用 redis-cli config get <参数名> 记录原值。
预防与常态化巡检
- 把命中率、
evicted_keys、阻塞客户端数、内存水位、主从延迟、慢查询条数做成看板与告警。 - 约定 key 分级:核心数据与可丢弃数据放在不同实例,避免互相挤占内存。
- 生产禁用
KEYS、FLUSHALL、MONITOR等命令,用rename-command重命名或直接禁用。 - 大 key 巡检每周一次,
--bigkeys放在低峰期并加-i 0.1限速。 - 客户端必须配置连接池上限、超时与退避重试,避免 Redis 的一次抖动被放大成雪崩。
小结:Redis 故障按“客户端报错类型 → 连接与缓冲 → 慢查询与阻塞 → 内存与淘汰 → 持久化 → 主从与集群 → 宿主资源”的顺序排查;日常用命中率、淘汰数、阻塞客户端、内存水位、fork 耗时、主从延迟六项做巡检,任何一项越线都要在它演变成全站故障之前处理掉。