Redis 从 0 到 1(二十九):CPU 突然 100%——commandstats 定位法与 6 步排查链路

我不会起名字322 · 后端 / 算法 / 数据库

📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL

文章目录

  • [Redis 从 0 到 1(二十九):CPU 突然 100%------commandstats 定位法与 6 步排查链路](#Redis 从 0 到 1(二十九):CPU 突然 100%——commandstats 定位法与 6 步排查链路)
    • [一、现象:CPU 100%,QPS 没涨](#一、现象:CPU 100%,QPS 没涨)
    • [二、第一步分诊:CPU 花在哪(收藏点 1)](#二、第一步分诊:CPU 花在哪(收藏点 1))
    • [三、6 步排查链路(收藏点 2)](#三、6 步排查链路(收藏点 2))
    • [四、本案复盘:大 key 全量读(收藏点 3)](#四、本案复盘:大 key 全量读(收藏点 3))
    • 五、命令清单
    • [六、排查步骤:CPU 告警后的操作序列](#六、排查步骤:CPU 告警后的操作序列)
    • 七、总结

Redis 从 0 到 1(二十九):CPU 突然 100%------commandstats 定位法与 6 步排查链路

上一篇《Redis 从 0 到 1(二十八):Redis 抖一下,重试把它打挂了------超时/重试/熔断的 Go 封装》我们给客户端装上了保险丝,链接:https://blog.csdn.net/2501_92769340/article/details/167400257 。

本篇起进入故障排查弧线,第一案:凌晨告警 Redis CPU 100%,但 QPS 曲线平平------谁在偷 CPU?

一、现象:CPU 100%,QPS 没涨

凌晨 2:47 监控告警:Redis 实例 CPU 从 30% 飙到 100%,持续不降。看 QPS 曲线------和白天持平,没有流量洪峰。看慢查询日志------也是空的。

CPU 高但 QPS 不高,只剩两种可能:每条命令变贵了 (同样的 QPS 吃了更多 CPU),或者有非命令的 CPU 消耗(fork、AOF 重写、碎片整理)。本篇的 6 步链路就是按这个二分法展开的。

二、第一步分诊:CPU 花在哪(收藏点 1)

证据 指向
INFO commandstats 里某命令 usec_per_call 异常高 命令变贵(大概率大 key/复杂命令)
INFO cpu 高但 commandstats 各项正常 系统级事件:fork、activedefrag、AOF fsync(第 30 篇)
LATENCY DOCTOR 报告 fork 类事件 同上
从库 CPU 高主库正常 从库在消化积压或跑了自己的慢命令

INFO commandstats 每行格式:

复制代码
cmdstat_hgetall:calls=10000,usec=8000000,usec_per_call=800.00,rejected_calls=0,failed_calls=0

三个数字各管一件事:calls 总量、usec 累计耗时、usec_per_call 平均每次。排序看 usec_per_call 的异常项(排除 get/set 这类微秒级基线后,谁高谁可疑);再用 usec(累计)判断它值不值得管------一条 800μs 的 HGETALL 一天只跑 10 次,不是凶手;跑 10 万次就是。

三、6 步排查链路(收藏点 2)

复制代码
1. 分诊    INFO cpu + commandstats + LATENCY DOCTOR → 命令消耗 or 系统事件
2. 定位    commandstats 按 usec_per_call 排序,找异常命令
3. 实证    拿到命令参数(slowlog 没有就去客户端日志/monitor 采样),
           MEMORY USAGE 确认 key 大小,测试库复现耗时
4. 归因    归类:大 key 全量读 / 热 key 高频读 / 命令滥用 / 系统事件
5. 治理    换命令、拆 key、加本地缓存(第 23 篇)、避开高峰做系统任务
6. 回归    压测复现路径验证,指标回落,写复盘

四、本案复盘:大 key 全量读(收藏点 3)

顺着链路走下来的真实结论:某服务的"配置刷新"每 5 秒对每个实例执行一次 HGETALL config:gateway------看着是配置读取,但这个 Hash 被运营塞了 12 万个 field(历史遗留),单次 HGETALL 平均 800μs。每 5 秒一次 × 20 个实例 = 每秒 4 次 × 800μs ≈ 3.2% CPU,加上其他命令的正常基线,凌晨低峰期 CPU 被它顶到 100%(白天 QPS 高反而被稀释)。

治理方案三步:

  1. 改读法 :应用只需要 3 个 field,改 HMGET config:gateway f1 f2 f3,耗时从 800μs 到 15μs;
  2. 改频率:配置刷新从 5 秒一次改 60 秒 + 推送触发(第 23 篇本地缓存同款思路);
  3. 治根本:config Hash 拆出"运营数据"到独立 key(第 22 篇 bigkey 治理的配套动作)。

Go 验证脚本(复现 + 对比治理前后耗时):

go 复制代码
package main

import (
	"context"
	"fmt"
	"time"

	"redis-0to1/redisx"
)

func main() {
	rdb, _ := redisx.NewClient(redisx.Config{Addr: "127.0.0.1:6379", Password: "redis123", PoolSize: 10})
	ctx := context.Background()

	bench := func(name string, fn func()) {
		start := time.Now()
		for i := 0; i < 100; i++ {
			fn()
		}
		fmt.Printf("%s: 平均 %v/次\n", name, time.Since(start)/100)
	}

	bench("HGETALL 12万field", func() { rdb.HGetAll(ctx, "config:gateway").Result() })
	bench("HMGET 3个field", func() { rdb.HMGet(ctx, "config:gateway", "f1", "f2", "f3").Result() })
}

五、命令清单

命令 作用
INFO cpu used_cpu_sys/user,区分内核态与用户态
INFO commandstats 每命令的 calls/usec/usec_per_call
LATENCY DOCTOR 系统级延迟事件诊断(fork、defrag)
SLOWLOG GET 抓到具体命令参数(配合第 21 章采集器)
OBJECT ENCODING / MEMORY USAGE 实证 key 的形态与大小

六、排查步骤:CPU 告警后的操作序列

  1. INFO cpu 确认是真 100%(不是容器配额问题);
  2. INFO commandstats 排序找异常命令------2 分钟内出嫌疑名单;
  3. 无嫌疑 → LATENCY DOCTOR 查系统事件,转第 30 篇(碎片/defrag);
  4. 有嫌疑 → slowlog/客户端日志拿参数 → MEMORY USAGE 实证 → 测试库复现;
  5. 治理后回归压测,CPU 回落曲线写进复盘。

七、总结

  1. CPU 高 ≠ QPS 高:先分诊"命令消耗"还是"系统事件";
  2. commandstats 三字段(calls/usec/usec_per_call)组合排序是定位主力;
  3. 高频 × 中耗时的命令比低频 × 高耗时的更危险;
  4. 治理三板斧:换命令、降频率、拆 key。

下一篇预告:CPU 第一案破完,下一案是"内存虚高"------下一篇《删了一半数据 RSS 不降------内存碎片与 activedefrag 观测》,我们搞清楚 RSS 和 used_memory 为什么分家。

相关推荐
我不会起名字3221 小时前
Redis 从 0 到 1(二十八):Redis 抖一下,重试把它打挂了——超时/重试/熔断的 Go 封装
redis·go·超时·熔断·重试
我不会起名字3223 小时前
Redis 从 0 到 1(三十):删了一半数据 RSS 不降——内存碎片与 activedefrag 观测
redis·内存碎片·rss·排查·activedefrag
csdn_aspnet18 小时前
使用 Docker 和 RedisInsight 设置 Redis 以进行本地开发
redis·docker·容器·redisinsight
用户094248568031 天前
第22章:Redis 持久化 RDB 与 AOF:数据不丢的底线
redis·架构·源码
没有气的汽水1 天前
升级完客户端,redis 又开始大量返回 MOVED:一个埋了七个月的本地配置
redis
csdn_aspnet1 天前
如何在本地 Docker 容器中运行 Redis,并使用 Redis Insight 和 Redis CLI 进行管理
redis·docker·容器
IT规划师1 天前
Redis 数据类型全解 - Bitfield:99% 开发者没用过的位域操作,把内存再砍 80%(七)
redis·bitfield·位域
用户094248568032 天前
第19章:库存扣减与秒杀系统:Redis 扛峰值流量
redis·架构·源码