Redis 大 key 与热 key 排查治理:从 HGETALL 到分片打散
一、一次慢查询引发的 Redis 雪崩
一个商品详情页接口平时 20ms 返回,某天下午 P99 突然冲到 2 秒,Redis 监控显示 CPU 并不高,但网络带宽曲线是平的尖峰。抓包和 SLOWLOG 一看,是一条 HGETALL 拿了 1.2MB 的哈希——商品 SKU 的所有规格、库存、图片地址全塞在一个 key 里。
这就是典型的大 key:值大、元素多,单次操作会把网络、序列化和客户端内存一起拖垮。更麻烦的是它还是热 key:所有请求都打同一个分片,那个分片节点再闲也会被打满。
二、怎么把大 key 找出来
1)redis-cli --bigkeys
redis-cli -h 10.0.0.11 -p 6379 --bigkeys
scan 全库,按类型输出最大的 key。优点是简单,缺点是要遍历,生产环境建议在从库上跑,并限速。
2)MEMORY USAGE
redis-cli MEMORY USAGE product:sku:1024
单个 key 精确估算内存占用,配合 SCAN 做抽样扫描,能定位到具体业务 key。
3)离线分析 RDB
redis-rdb-tools -f memory report dump.rdb
把备份 dump 下来分析,对线上零影响,适合定期体检。
4)热 key 看监控
Redis 自带的 hotkeys 需要 LFU 淘汰策略;云上实例一般有 hotkey 分析页。没有的话,可以在客户端埋点统计 key 访问次数,或用 MONITOR 短时间抽样(注意 MONITOR 会明显降低性能,只能开几秒)。
三、治理思路
拆
大 hash 拆成多个小 hash,按字段前缀分桶:
product:sku:1024:base
product:sku:1024:stock
product:sku:1024:images
只取需要的字段,HMGET 代替 HGETALL。这一步往往能把单次操作从 1MB 降到几 KB。
压缩
图片地址、长文本这类字段,写入前 gzip 或只存对象存储路径,不存内容。字符串 value 超过 10KB 就该警惕。
加本地缓存
热 key 在应用侧加一层 Caffeine/Guava 本地缓存,设置 1–5 秒的短 TTL。热点商品被几万次请求打过来时,Redis 只需要承接极少量回源。
打散
对计数类热 key,用 key:{shard} 拆成 N 份,读的时候求和。比如商品浏览量拆成 16 个计数 key,写请求自然分散到 16 个分片。
限流与降级
对确实无法拆的历史 key,在接入层对单 key 做 QPS 限流,超限直接走数据库或返回兜底数据,别让 Redis 单点拖垮整个链路。
四、预防
- 上线前做 key 规范评审:明确类型、预估大小、TTL;
- 在 CI 里加静态检查,禁止
HGETALL、KEYS *、无界LRANGE; - 监控里加"单 key 大小 Top N"和"单分片 QPS/带宽"两个面板;
- 定期跑 bigkey 体检,把 10MB 以上的 key 作为 P1 处理。
五、小结
大 key 和热 key 经常同时出现,根因都是"把聚合数据塞进一个 key"。治理顺序是:先定位(bigkeys / MEMORY USAGE / RDB 分析),再拆分或压缩,最后用本地缓存和分片打散兜住流量。真正有效的预防不是事后优化,而是把 key 设计纳入上线评审。
- 点赞
- 收藏
- 关注作者
评论(0)