主题
Redis 监控指标与告警
一句话:Redis 的监控不是把
INFO抄一遍,而是按「资源→进程→服务→业务」四层找出最先变坏的那一环;它快在内存,所以故障几乎都从内存水位、fork 停顿和复制延迟开始,盯住这几个先兆,才能在 DB 被打穿之前动手。
适用版本:Redis 7.x / 8.x。INFO 字段与默认值以官方文档为准,6.0 之前的差异单独标注。
为什么需要
Redis 在链路里通常只做一件事:替后端挡读。它变慢或不可用,压力不会消失,只会平移给 DB。更麻烦的是,Redis 的故障往往不是进程退出——进程还在,但内存满了、fork 卡了、主从断了,指标上只是几个数字缓慢变化。等业务侧报超时,DB 连接池通常已经被打满。所以监控要解决的是:在用户感知之前,看到哪个数字先不对。
核心机制
四层观察面
| 层 | 看什么 | 回答的问题 |
|---|---|---|
| 资源 | CPU、RSS、磁盘 IO/空间、网络、swap | 是不是机器先扛不住了 |
| 进程 | INFO memory/clients/stats/persistence | Redis 自己是否健康、是否在做重活 |
| 服务 | INFO replication、Sentinel、CLUSTER INFO | 高可用链路是否已经退化 |
| 业务 | 命中率、P99 延迟、错误率、回源量 | 用户是否已经受影响 |
排查从下往上:业务报警时先排除资源层,再看进程层有没有淘汰、fork 或阻塞,最后才怀疑服务层。反过来,服务层指标异常时业务层可能还没感觉,这正是提前处置的窗口。
资源层:先排除机器
Redis 单线程执行命令,CPU 打满通常不是「算得多」,而是命令本身是 O(N)(KEYS、大 key 的 HGETALL),或 fork 后的 COW 在复制页表。内存要看 RSS 而不只是 used_memory:RSS 包含分配器碎片和 fork 期间的 COW 页,RSS 远高于 used_memory 时,容器更容易被 OOM Killer 杀。磁盘只在持久化和 AOF 重写时重要,但它慢会直接拖住写路径;网络看带宽和重传,集群模式还要看跨节点流量。
进程层:INFO 里的先兆
- 内存:
used_memory是分配器视角的逻辑用量,used_memory_rss是操作系统视角的物理占用,maxmemory是淘汰触发线。三者一起看,才能区分「数据真的多」和「碎片/COW 让 RSS 虚高」。evicted_keys持续增长,说明已经在丢数据换空间,命中率下降只是时间问题。 - 客户端:
connected_clients接近maxclients时新连接会被拒,rejected_connections开始增长;blocked_clients高说明大量客户端卡在BLPOP、WAIT这类阻塞命令上,通常是下游慢或锁等待。 - 吞吐与延迟:
instantaneous_ops_per_sec掉零不一定是没流量,也可能是主线程被阻塞。latency和slowlog回答「慢在哪条命令」,latest_fork_usec回答「最近一次 fork 卡了多久」——fork 期间主线程停摆,这是 Redis 特有的延迟来源。 - 持久化:
rdb_last_bgsave_status和aof_last_write_status不是ok就是硬故障,通常先于业务报错出现;rdb_changes_since_last_save持续变大,说明快照一直没成功。 - 缓存效果:
keyspace_hits / (hits + misses)是命中率。它没有绝对标准,要和自己的基线比;突然掉 10 个点,通常意味着批量过期、淘汰或热 key 消失。
服务层:主从、哨兵、集群
- 主从:
master_link_status为down时,master_link_down_since_seconds才开始计时;恢复后如果 offset 差(主节点master_repl_offset与从节点slave_repl_offset之差)持续扩大,说明从节点追不上,不只是「断了一下」。sync_full增长意味着发生了全量同步,会带来 fork、RDB 传输和带宽峰值。 - 哨兵:
INFO sentinel看 master 的status、slaves、sentinels,SENTINEL masters看quorum。主观下线(sdown)是单个哨兵的判断,客观下线(odown)才是多数派共识;只报 sdown 会产生大量误报。 - 集群:
cluster_state:ok、16384 个槽全覆盖、cluster_slots_pfail和cluster_slots_fail为 0 才算健康。pfail是疑似失联,先查网络和节点负载;fail是已判定失败,要考虑槽迁移和副本接管。
两条典型的雪崩链路
箭头方向就是预警顺序:内存水位和命中率斜率远早于 DB 承压,fork 耗时和延迟分位远早于连接数异常。
链路一:内存打满 → 淘汰 → 命中率下降 → 请求打到 DB。 写入持续增长,used_memory 顶到 maxmemory,evicted_keys 开始上涨。被淘汰的未必是最冷的 key,而是采样窗口里「看起来不热」的 key,热点也可能中招。命中率下降后,同样的请求穿透到 DB;DB 连接池被占满,接口超时,客户端重试又把流量放大。等 evicted_keys 报警时,DB 通常已经承压,真正的预警点是内存水位和命中率斜率。
链路二:fork/持久化/大 key → 延迟升高 → 客户端超时重试 → 连接与 CPU 进一步升高。BGSAVE 或 AOF 重写触发 fork,latest_fork_usec 飙升;fork 期间主线程暂停,COW 又让内存页翻倍。大 key 的删除或读取会让单条命令执行很久。客户端超时后重试,connected_clients 和 QPS 同时上涨,主线程更忙,延迟继续升高,形成正反馈。这条链路里 CPU 可能不高,但延迟和连接数会同时异常。
最小上手
bash
# 进程层一次看全:内存、客户端、持久化、复制
redis-cli INFO
redis-cli INFO memory | grep -E "used_memory|maxmemory|mem_fragmentation"
redis-cli INFO stats | grep -E "evicted_keys|keyspace_hits|keyspace_misses|rejected_connections|latest_fork_usec"
redis-cli INFO clients | grep -E "connected_clients|blocked_clients"
redis-cli INFO replication | grep -E "master_link_status|master_repl_offset|slave_repl_offset"
# 延迟与慢命令
redis-cli --latency
redis-cli SLOWLOG GET 10
# 大 key / 热 key(SCAN 采样,都有额外开销,低峰执行)
redis-cli --bigkeys
redis-cli --hotkeys # 需要 maxmemory-policy 为 LFU,否则直接报错
redis-cli CLUSTER INFOPrometheus 侧用 redis_exporter 抓取(exporter 版本不同,指标名以官方文档为准):
yaml
scrape_configs:
- job_name: redis
static_configs:
- targets: ["redis-exporter:9121"]bash
docker run -d --name redis-exporter -p 9121:9121 \
oliver006/redis_exporter -redis.addr redis://redis:6379生产动作
下面是一组起点阈值,必须按自己的基线校准,不要当成通用标准。
| 指标 | 预警 | 告警 | 处置 |
|---|---|---|---|
used_memory / maxmemory | > 75% | > 90% | 查大 key 和增长最快的 key,扩容或调淘汰策略 |
evicted_keys 速率 | 纯缓存实例持续 > 0 | 快速上涨 | 先扩容,再核对 TTL 与淘汰策略 |
| 命中率 | 比 7 日基线低 5–10 个点 | 低 10 个点以上 | 查批量过期、热 key、淘汰 |
connected_clients / maxclients | > 80% | > 90% 或 rejected_connections > 0 | 查连接泄漏与客户端连接池 |
blocked_clients | 明显高于基线 | 持续上涨 | 查阻塞命令与下游依赖 |
latency P99 / slowlog | 超基线 2 倍 | 持续超基线且业务超时 | 定位 O(N) 命令、大 key、fork |
latest_fork_usec | 超过实例基线 | 接近或超过业务超时时间 | 关自动 RDB、错峰重写、拆小实例 |
rdb_last_bgsave_status / aof_last_write_status | — | 非 ok | 立即查磁盘空间、权限、fork |
master_link_status / offset 差 | down 超过 10s | down 超过 60s 或 offset 差持续扩大 | 查网络、复制缓冲、从节点负载 |
cluster_state / slots_pfail / slots_fail | pfail > 0 | state 非 ok 或 fail > 0 | 查节点存活、槽覆盖、迁移状态 |
主从、哨兵、集群的判断不能混:主从看「链路 + 追赶能力」,master_link_status 是通断,offset 差是追赶速度,sync_full 增长说明在反复全量同步;哨兵看「共识」,单个哨兵的 sdown 不算故障,quorum 决定能否判定 odown,真正切换还需要多数哨兵投票;集群看「槽」,节点活着但槽没覆盖,集群一样不可用。
处置顺序先保业务再查根因:内存和连接类问题先限流或扩容,持久化状态异常先确认磁盘,延迟问题先用 SLOWLOG 定位命令,再决定是否 kill 客户端或降级。
边界
Redis 的强项是低延迟和简单数据结构,代价是内存贵、持久化弱、单线程怕慢命令。这决定了它适合做缓存和会话,不适合当唯一数据源;也决定了监控必须优先盯内存、fork、慢命令和复制延迟,而不是像磁盘数据库那样盯 IO 利用率。异步复制下切换丢最近写入是固有窗口,监控只能提前发现,不能消除。
| 维度 | 适合 | 不适合 |
|---|---|---|
| 数据量 | 热数据能装进内存,GB 到百 GB 级 | 全量数据远大于内存,靠 Redis 存主数据 |
| 一致性 | 可接受异步复制和切换丢少量写 | 要求强一致、零丢失的核心账务 |
| 查询形态 | 按 key 点查、简单结构、计数和排行榜 | 多条件关联、范围聚合、复杂事务 |
| 团队成本 | 能维护主从/哨兵/集群并做容量规划 | 没人盯内存和 fork,指望它自愈 |
还有几个容易误判的地方:
used_memory与used_memory_rss的差值来自分配器碎片、COW 和页对齐,不能互相替代;容器里要以 RSS 对照内存 limit。maxmemory不包含副本输出缓冲、AOF 缓冲等开销,「没到 maxmemory」不等于「不会 OOM」。- 阈值随业务变化:延迟敏感业务和离线缓存的警戒线完全不同,表里的数字只是起点。
MONITOR会把每条命令复制给监控连接,开销大且可能泄漏敏感数据,不能常开;--bigkeys/--hotkeys走 SCAN 或依赖 LFU,也有开销,放低峰执行。- 采集本身有成本:
INFO很轻,但高频SCAN、大数量SLOWLOG GET和 exporter 的全量采集都会增加主线程负担;采样间隔太长又会漏掉尖刺。
相关:04-内存管理、03-持久化、06-主从复制、07-哨兵模式、08-集群模式、10-大Key问题、11-热点Key问题、99-生产检查清单。
讲清楚
Redis 监控的核心不是指标数量,而是分层定位:资源层排除机器,进程层看内存、fork、连接和慢命令,服务层看复制与集群共识,业务层确认用户是否已经受影响。Redis 快在内存、弱在持久化和单线程,所以典型雪崩只有两条:内存打满后淘汰把命中率打下去,请求回源压垮 DB;fork、持久化或大 key 把延迟拉高,客户端重试再放大连接和 CPU。预警要放在内存水位、命中率斜率和 fork 耗时上,而不是等业务超时。阈值只是起点,必须按自己的基线和业务超时校准。