Redis 热 Key、大 Key 如何发现和治理?
热 Key 和大 Key 经常同时出现,却是两种问题:热 Key 的访问频率过高,大 Key 的 value 体积或元素数过大。小 Key 也能成为热点,冷门 Key 也可能巨大。治理前必须分别测量 QPS、字节数和操作复杂度。
1. 两类风险
热 Key 会导致:单分片 CPU/网络打满、集群负载不均、缓存击穿时数据库瞬时过载。大 Key 会导致:单次命令耗时、网络包过大、复制/AOF 放大、迁移阻塞以及删除时集中释放内存。
例如一个 20 MB String 每秒访问一次不算热但很大;一个 100 字节配置每秒读取 10 万次很热但不大。
2. 如何发现热 Key
可组合使用:
- 客户端埋点,按业务 Key 前缀统计 QPS 和延迟;
- Redis
INFO commandstats了解命令总体分布; redis-cli --hotkeys(依赖 LFU 访问频率元数据,通常要求allkeys-lfu或volatile-lfu,且执行 SCAN 会产生额外负载);- 代理层、网关或云监控的 Key 采样;
- 分片 CPU、网络明显倾斜时定位对应 slot;
- 短时
MONITOR仅限受控诊断,生产长期开启代价很高。
不要把完整用户 Key 作为高基数监控标签,否则监控系统先被打爆。可在客户端做 Top-K、采样或按前缀聚合。
3. 如何发现大 Key
redis-cli --bigkeys
redis-cli --memkeys
MEMORY USAGE some:key SAMPLES 5
扫描命令本身会消耗资源,宜在低峰、从节点或受控环境分批执行。STRLEN、HLEN、LLEN、SCARD、ZCARD 可查看逻辑规模;内存占用还受编码、成员长度和采样精度影响。
需要为不同类型定义阈值,而不是一个绝对“大于 1 MB”:10 万成员的 Hash 与 1 MB String 的操作风险不同。
4. 热 Key 治理
本地缓存
对变更少的热点配置增加进程内缓存,显著减少 Redis QPS。代价是多副本一致性,应使用短 TTL、版本推送或失效通知,并允许短时间旧值。
复制热点副本
把只读热点复制为多个逻辑 Key:product:1:replica:0..N,客户端按哈希或随机读取。更新时要同时失效或版本切换,适合读多写少。
请求合并与限流
同一实例内用 singleflight 合并并发加载;对昂贵接口按用户和全局限流。缓存失效时只允许有限请求回源。
Redis Cluster 的副本读可分担部分读取,但要考虑复制延迟和客户端路由能力。
5. 大 Key 治理
- 大 String:压缩、拆块、改存对象存储并只缓存地址;
- 大 Hash:按业务维度分桶,如
user-events:{userId}:{month}; - 大 List/Set/ZSet:按时间、哈希或范围分片,并限制单桶元素数;
- 全量读取改成分页或
HSCAN/SSCAN/ZSCAN; - 保留周期数据按分桶 Key 设置 TTL,避免逐成员清理。
拆分不能只按固定数量,还应设计索引、并发更新、过期和迁移策略。
6. 删除大 Key 为什么危险
DEL 需要同步释放对象内部大量元素,可能阻塞主线程。优先:
UNLINK huge:key
UNLINK 先从键空间摘除,再把可异步释放的内存回收工作交给后台线程;命令本身仍需处理参数和键查找,瞬间提交海量 Key 也会造成压力。也可配置 lazy free 相关选项,但要监控后台释放队列和内存下降速度。对于超大集合,还可按 SCAN 分批删除成员,最后删除 Key。
过期大 Key 同样可能带来释放尖峰,因此治理要从写入阶段控制大小,而不是等过期时处理。
7. 集群迁移与持久化放大
大 Key 在 slot 迁移时传输时间长,失败重试成本高;每次更新大 value 都可能增加复制带宽和 AOF 体积。fork 期间修改大量内存页还会扩大写时复制开销。
所以容量评审不能只看“Redis 能装下”,还要看复制、备份、故障转移和扩缩容是否能在目标时间内完成。
8. 预防清单
- Key 设计文档是否规定最大 value 和最大元素数?
- 是否按前缀监控 QPS、命中率、字节数和 p99?
- 全量命令是否改为分页/SCAN?
- 热点失效是否有请求合并与回源限流?
- 大对象删除是否使用 UNLINK 或分批方案?
- 集群分片是否出现 CPU、网络和内存倾斜?
- 是否做过大 Key 的复制、迁移和恢复演练?
热 Key 需要分散流量,大 Key 需要拆分数据与限制操作规模。最有效的治理不是事故后扫描,而是在写入接口就设置容量边界,并持续观察 Key 级别的访问分布。