← 返回最佳实践列表

*Redis 大 Key 和热 Key:排查与处理方法

大 Key 指单个键的值或集合规模过大,热 Key 指单个键在短时间内承受过高访问量。两者不是同一个问题:大 Key 主要带来内存、序列化、网络传输和删除开销,热 Key 主要造成单节点 CPU、带宽和下游回源压力。一个键也可能同时具有这两种特征。

*先判断问题类型

现象 更可能的原因 优先检查
HGETALL、LRANGE 0 -1 等命令进入慢查询 大键或返回结果过多 键大小、集合长度、命令复杂度
删除某个键时出现延迟尖峰 大键同步释放内存 DEL/UNLINK 使用方式、lazyfree 配置
某个集群节点 CPU 或带宽明显高于其他节点 热键或槽位数据倾斜 键级访问量、节点指标、键和槽分布
热点缓存失效后数据库压力突然上升 热键集中回源 缓存未命中、回源并发、数据库指标
实例内存增长但键数量变化不大 单键值增长或大键 MEMORY USAGE、集合长度、内存趋势

不要用“字符串超过 10 KB”或“集合超过 1000 个元素”作为通用判定标准。同样的数据量,在低频后台任务和超高频在线请求中的影响完全不同。应结合命令、访问频率、返回大小和延迟目标判断。

*大 Key 排查

*用 --bigkeys 做初步筛查

redis-cli -h 127.0.0.1 -p 6379 --bigkeys

--bigkeys 通过扫描找出各类型中较大的键,适合发现问题线索。它不会直接给出完整的内存排名,也不代表扫描没有成本;键很多时仍会增加实例和网络负载,应在低峰期或合适的副本上运行。

*测量指定键的内存

redis-cli MEMORY USAGE cache:product:1001
redis-cli MEMORY USAGE user:1000 SAMPLES 100

返回值单位是字节。SAMPLES 用于控制集合嵌套元素的抽样数量;抽样结果不是全量精确测量。还可以结合类型和长度判断读取风险:

redis-cli TYPE user:1000
redis-cli HLEN user:1000
redis-cli STRLEN cache:product:1001

对 List、Set、Sorted Set 和 Stream,分别使用 LLEN、SCARD、ZCARD 和 XLEN。

*从慢查询确认实际影响

redis-cli SLOWLOG GET 20

重点看命令是否读取或修改了整个大对象。GET 一个超大字符串、HGETALL 一个大哈希、SMEMBERS 一个大集合,都可能产生明显的 CPU、内存复制和网络开销。

离线分析 RDB 可以减少在线扫描干扰,但需要额外工具,并注意 RDB 只代表快照时刻。在线指标和离线结果应相互验证。

*大 Key 处理

*减少全量读取

把一次性读取整个对象改为按需或分批读取:

# 只读取需要的哈希字段
HMGET user:1000 name status

# 分批遍历哈希
HSCAN user:1000 0 COUNT 100

# 只读取列表的一页
LRANGE queue:jobs 0 99

# 按排名范围读取有序集合
ZRANGE leaderboard 0 99

HSCAN、SSCAN 和 ZSCAN 的 COUNT 是工作量提示,不保证每次返回相同数量。调用方必须继续处理游标直到结束。

*按业务边界拆分

拆分方式应保留明确的读取和写入规则,例如:

  • 把用户基本资料、权限和偏好拆成不同的键,而不是把所有字段放进一个哈希。
  • 把长期增长的列表或 Stream 按日期、租户或业务分桶,并设置保留周期。
  • 把大型集合按明确维度拆分;如果查询需要跨分片,应由应用合并结果并评估额外开销。
  • 大文件或大对象放入对象存储,Redis 只保存元数据和引用。

不建议在没有访问模式依据时直接对键做随机取模分片。这样可能让单键查询变成多分片查询,反而增加复杂度。

*谨慎压缩和删除

压缩大字符串可以减少内存和网络传输,但会增加客户端 CPU 开销,也会降低可读性。应使用真实数据测试压缩率、序列化成本和兼容性。

Redis 4.0 及以上版本可以评估异步删除:

UNLINK cache:large-object

UNLINK 把对象释放工作交给后台线程,但键的删除和命令处理并非完全没有成本。批量清理时仍应限制速度并观察延迟。lazyfree-lazy-user-del yes 会把显式 DEL 改为类似 UNLINK 的行为,修改前应确认版本、运维习惯和监控是否适配。

*热 Key 排查

*先确认是哪一个键

可从以下来源交叉定位:

  • 客户端按命令和键前缀统计请求量、耗时与返回值大小。
  • Redis 节点 CPU、网络吞吐和命令统计的突增。
  • 缓存未命中后,下游数据库或服务的查询热点。
  • 短时间、受控的诊断采样。

在配置 LFU 淘汰策略时,可以使用:

redis-cli --hotkeys

--hotkeys 依赖 LFU 的访问计数,不是所有淘汰策略下都能使用,也不等于完整、精确的键级 QPS 统计。

MONITOR 会输出服务器处理的命令,本身可能带来显著开销。生产环境不应长时间开启,更不能把含密码或敏感数据的输出直接写入普通日志。

*本地缓存适合允许短暂旧值的读热点

对于读多写少、允许短暂不一致的数据,可以在应用进程内增加小容量、短 TTL 的本地缓存:

请求 → 本地缓存 → Redis → 数据源

本地缓存必须有容量上限和过期时间,并考虑多实例之间的数据更新。主动失效很难同时覆盖所有进程,因此不能把本地缓存当作强一致存储。

*限制缓存重建并发

热点键失效时,使用单航班、请求合并或带唯一值的锁,让少量请求负责回源,其余请求等待、返回可接受的旧值或降级结果。不要只写一个不带过期时间的 SETNX,否则重建失败可能形成永久阻塞。

相关加解锁示例见 Redis 分布式锁。

*按读写特征拆分热点

  • 读热点:本地缓存、只读副本、静态化或请求合并。
  • 写热点计数器:拆成多个子计数器,读取时汇总;需要确认是否接受汇总的额外延迟。
  • 排行榜:限制返回范围,避免每次读取完整榜单。
  • 热点任务:评估是否需要把任务分布到多个队列,而不是所有消费者争用一个键。

副本读取可能返回旧数据;热点键拆分也会改变原子性和查询方式。采用前必须明确这些语义变化。

*集群环境的注意事项

Redis Cluster 把一个键映射到一个槽,单个热键仍由单个主节点负责。增加普通节点不会自动分摊这个键的访问量。

使用 {tag} 哈希标签可以让多个键进入同一个槽,适用于需要多键操作的场景;它不能用于把同一个热键分散到多个节点。槽迁移解决的是槽的位置和容量分布,不会把一个键内部自动拆分。

*处理前后的验证清单

  1. 记录问题命令、键类型、大小、访问频率和影响时间范围。
  2. 先在测试环境验证拆分、读取和删除逻辑,尤其是旧数据兼容。
  3. 采用渐进迁移或双写时,明确失败补偿和数据核对方式。
  4. 观察 Redis 延迟、CPU、带宽、内存以及下游数据源指标。
  5. 确认慢查询、节点倾斜和回源并发确实下降,再扩大变更范围。

相关文档:性能优化指南、内存优化、Redis 最佳实践。