😱 前言:凌晨 3 点的报警电话
场景还原:你的手机突然响了,监控显示 Redis 集群 CPU 飙升到 100%,客户端连接大量超时。
你登上服务器一看,内存也没满,QPS 也不高。重启?没用。扩容?来不及。
最后排查发现,竟然是一个实习生往 List 里塞了 500 万条日志数据……
这就是bigkey的威力。它不是病,发作起来真要命。
🐳 一、 什么是 bigkey?(标准定义)
Redis 中的 bigkey 不是指 Key 本身的字符串长(虽然那也叫 key 过长),而是指Value 占用的内存过大。
通用的判定标准:
- String 类型:单个 Value 超过10KB(严格标准)或5MB(宽松标准)。
- Collection 类型(List, Hash, Set, ZSet):元素个数超过5000 个或总大小超过10MB。
💥 二、 它是如何拖垮集群的?
Redis 是单线程模型(6.0 之前完全单线程,6.0 之后网络 IO 多线程,但核心命令执行依然是单线程)。
这意味着:所有命令都要排队。
1. 阻塞主线程 (The Blocking)
当你对一个 bigkey 执行读写操作(比如GET一个 10MB 的 String,或者HGETALL一个 500万字段的 Hash):
- 网络 IO 阻塞:传输 10MB 数据需要时间,这期间 CPU 被占用。
- 命令执行阻塞:删除一个大 List 需要释放大量内存,操作系统内存回收也会阻塞线程。
阻塞效应图解 (Mermaid):
2. 集群同步风暴
在 Redis Cluster 模式下,如果发生了分片迁移:
- Redis 需要把 Key 从节点 A 搬到节点 B。
- Bigkey 迁移会超时:导致迁移失败,甚至触发集群重新选举,造成服务震荡。
3. 内存碎片与 OOM
频繁修改 bigkey 会导致内存碎片率上升。当你终于决定删除它时,如果使用普通的DEL,可能会瞬间造成内存剧烈波动。
🛠️ 三、 如何发现 bigkey?(工具实战)
千万别在生产环境用KEYS *!千万别用!
方法 A:在线扫描(轻量级)
Redis 自带了一个扫描工具,虽然简陋但不用安装额外软件。
# -i 0.1 表示每扫描 100 个 key 休息 0.1 秒,防止把生产环境搞挂redis-cli-h127.0.0.1-p6379--bigkeys-i0.1缺点:只能看到每种类型最大的那个 Key,看不到全部。
方法 B:离线 RDB 分析(核武器)✅
这是最推荐的方法。我们不直接扫描线上 Redis,而是把RDB 备份文件拖下来分析。这样对线上服务0 影响。
推荐工具:redis-rdb-tools(Python 编写)
1. 安装工具
pipinstallrdbtools python-lzf2. 生成 CSV 报告
假设你下载了 dump.rdb:
# 找出所有大于 10KB 的 key,并按内存大小排序rdb-cmemory dump.rdb--bytes10240>memory_report.csv3. 结果分析
打开 CSV,你会看到清晰的明细:
database: 数据库 IDtype: 数据类型key: 键名size_in_bytes:真实占用内存大小(最重要的数据)encoding: 编码方式
有了这份报表,你可以直接把表格甩给开发:“这几个 Key 是谁写的?今晚优化掉!”
✂️ 四、 如何优雅地删除 bigkey?
找到 bigkey 后,千万不要直接运行DEL命令!DEL是同步阻塞删除。删除一个 1GB 的 Key,Redis 可能会卡顿几十秒,所有请求全部超时。
1. Redis 4.0+:使用UNLINK(懒删除)
这是 Redis 官方提供的后悔药。
UNLINK my_big_key原理:它把 Key 从元数据中删掉(这一步很快),然后把释放内存的动作丢给后台线程(Background Thread)去慢慢做。
2. Redis 4.0 以下:渐进式删除 (Manual)
如果你还在用老版本,必须手动分批删除。
- Hash: 使用
HSCAN每次扫 100 个字段,然后HDEL。 - List: 使用
LTRIM逐步裁减。 - Set: 使用
SSCAN+SREM。 - ZSet: 使用
ZREMRANGEBYRANK。
Python 伪代码示例:
defdelete_big_hash(key):whileTrue:# 每次只取 100 个,避免阻塞cursor,fields=redis.hscan(key,count=100)ifnotfields:break# 批量删除这 100 个redis.hdel(key,*fields.keys())ifcursor==0:break🛡️ 五、 总结与预防
治理 bigkey 最好的办法是预防。
- 数据拆分:如果一个对象太大,拆成多个 Key(如
User:1:base,User:1:detail)。 - 定期清理:List 不要做无限队列,必须设置长度限制。
- 设置过期时间:别让 bigkey 变成死得僵尸。
- 监控预警:集成 RDB 分析工具到 CI/CD 或定时任务中,每天早上发送一份“大 Key 榜单”。
Next Step:
趁现在,去你的 Redis 生产环境下载一份 RDB 文件(或者在从库操作),用rdbtools跑一下分析。你可能会被结果吓一跳!