Skip to main content

解决 Redis 大 Key 问题

解决 Redis 大 Key 问题通常分为 发现 → 拆解 → 优化 → 清理 四个步骤,你可以按这个顺序来操作:


一、发现大 Key(先定位问题)

方法命令/工具说明
--bigkeysredis-cli --bigkeys扫描并返回每种数据类型中最大的 Key(注意:会扫描全库,生产环境建议在低峰期做)。
MEMORY USAGEMEMORY USAGE key精确查看某个 Key 占用的内存(字节)。
SCAN + 推断自定义脚本遍历所有 Key,对疑似大 Key 用 STRLEN/LLEN/HLEN/ZCARD 等判断长度。
监控工具Prometheus + Redis exporter / CacheCloud长期监控慢查询、内存热 Key、大 Key。

二、解决大 Key(核心方法)

根据数据类型不同,采用不同拆分策略:

1. String 类型大 Value(最常见)

  • 压缩:用 snappy / lz4 / gzip 压缩后再存(CPU 换内存+网络)。
  • 拆分为多个小 Key:例如 1MB 的字符串拆成 100 个 10KB 的 key,用 MGET 批量读取。
  • 冷热分离:大对象不全部放 Redis,Redis 只存索引/元数据,实际内容放对象存储(如 S3/OSS)。

2. Hash 类型大 Key(field 过多)

  • 拆分:按 hash(key) % N 将一个大 Hash 拆成 N 个小 Hash(例如 hash_0, hash_1…)。
  • 转换结构:如果每个 field 对应一个独立对象,直接改用 String 分别存储(user:1001:name)。
  • 部分读取:使用 HSCAN 分批获取,避免 HGETALL

3. List / Set / ZSet 类型大 Key(元素过多)

  • 分页 / 分段存储:例如 list:0-999, list:1000-1999
  • 冷数据归档:旧数据移出 Redis,必要时用 Lua 或定时任务转移。
  • 限制长度:使用 LTRIM 定期截断,避免无限增长(如只保留最近 1000 条)。

三、删除大 Key(避免阻塞)

方法适用场景说明
UNLINK(推荐)所有类型异步删除,主线程立即返回,后台线程逐步回收内存,不阻塞服务。
DEL(不推荐)小 Key对大数据量会阻塞 Redis。
分批删除List / Set / Hash / ZSetLRANGE + LTRIM / SSCAN + SREM / HSCAN + HDEL / ZRANGE + ZREMRANGEBYRANK 每次删一小批。

四、预防与常态化治理

  • 设置 Key 长度阈值:代码中拦截超过 1MB 的写入(可配置)。
  • 使用 Hash 代替多个 String:对于字段较多的对象,Hash 比大量独立 String 更省内存(但也要避免单个 Hash 过大)。
  • 读写分离 + 只读副本:将大 Key 的读请求分散到从节点,减少主节点压力。
  • 监控告警:对 maxmemory 使用率、慢日志、大 Key 数量设置告警。

五、集群模式下的特殊处理

  • 数据倾斜:将大 Key 的拆分后分散到不同 slot(如添加随机后缀 {user:123}_part1,但注意 {} 内相同会定向到同一分片)。
  • 使用 Redis 6.0+ 的 TLDRKeyDB:多线程处理删除/释放内存更高效。

一句话总结发现用 --bigkeys,String 压缩或拆分,Hash/List 分段存储,删除用 UNLINK,写入加阈值防御。