聊聊 Redis 的 BigKey:你以为删个 key 而已,结果整个集群卡死了 之前线上遇到过一次比较离谱的事故简单复盘一下。某天下午监控突然报警Redis 集群的响应延迟从平时的 1ms 飙到了 200ms部分接口直接超时。第一反应是看慢查询日志结果发现罪魁祸首就是一个DEL操作——删了一个 value 有 50 多万字段的 hash key直接阻塞了整个 Redis 实例。这就是典型的 BigKey 问题。什么是 BigKey没有严格的官方定义但社区里一般这么判断String 类型value 超过10KBHash / List / Set / ZSet元素数量超过5000或者整体序列化后超过100KB当然这个阈值不是死的得看你的业务场景和 Redis 实例的规格。但核心逻辑是一样的一个 key 太大了导致单次操作耗时过高阻塞其他请求。为什么 BigKey 危险Redis 是单线程处理命令的6.0 之后网络 IO 多线程了但命令执行还是单线程。这意味着一个慢操作会把后面所有请求都堵住。常见的翻车场景删除大 keyDEL一个大 hashRedis 要释放大量内存直接阻塞遍历大 keyHGETALL一个几十万 field 的 hash慢查询直接拉满过期淘汰key 设了 TTL到期后 Redis 内部删除也会阻塞主从同步大 key 导致 RDB 快照时间变长主从切换时延迟飙升怎么发现 BigKey方法一redis-cli --bigkeysredis-cli --bigkeys -a your_password这个命令会扫描整个数据库统计每种数据类型的最大 key。生产环境慎用扫描本身也有开销建议在从节点上跑。方法二MEMORY USAGEMEMORY USAGE my_key查看单个 key 的内存占用适合你已经怀疑某个 key 有问题的时候。方法三SLOWLOGSLOWLOG GET 20慢查询日志里如果频繁出现对某个 key 的操作大概率就是 BigKey。方法四监控 代码埋点在应用层对 Redis 操作做耗时统计超过阈值就告警。这个最实用能第一时间发现问题。怎么解决拆分 key最常见的方案。比如一个 hash 存了 100 万个用户信息可以按取模拆成多个 key// 原来 redis.hset(user:info, userId, userInfo); // 拆分后 int bucket userId % 1000; redis.hset(user:info: bucket, userId, userInfo);渐进式删除Redis 4.0 之后支持UNLINK命令异步删除不会阻塞主线程UNLINK my_big_key如果是老版本可以自己写个脚本分批删-- Lua 脚本分批删除 hash 的 field local key KEYS[1] local count tonumber(ARGV[1]) local fields redis.call(HKEYS, key) for i 1, math.min(count, #fields) do redis.call(HDEL, key, fields[i]) end return #fields避免HGETALL改用HSCANHSCAN my_hash 0 COUNT 100游标式遍历每次只取一小批不会一次性把整个 key 读出来。合理设置过期时间如果大 key 需要过期不要直接设 TTL而是用定时任务分批删除元素最后再删 key 本身。写在最后BigKey 这东西平时没事的时候感觉不到一旦触发就是线上事故。建议在日常开发中代码 review 的时候关注 Redis 的数据结构设计上线前用--bigkeys扫一遍监控里加上 Redis 慢查询告警别等到凌晨三点被电话叫醒才想起来看慢查询日志。