🚨 一、什么是 Redis 大 Key?
大 Key:指单个 key 存储的数据量过大(value 大)或元素过多(集合类)。
典型例子:
- 一个 string value 是 1MB、10MB
- 一个 hash 里有 5 万字段
- 一个 list 里 10 万项
- 一个 set 装几百万用户 ID
- 一个 zset 存了几百万点赞记录
⚠ 大 Key 不仅大,还会 影响性能、阻塞、CPU、网络带宽、业务延迟。
💣 二、大 Key 的危害(这些都是线上事故根源)
① 阻塞 Redis 单线程(最危险)
Redis 是单线程,大 key 操作(如 DEL、HGETALL、LRANGE)会让 Redis 卡住几十 ms 到秒级。
你系统 QPS 高时 → 直接造成 Redis 主线程阻塞。
② 带宽飙升、网络阻塞
一个 value 是 10MB,你一查,Redis 必须 一次性返回 10MB 数据给业务。
网络、网卡、带宽全被占满。
③ 复制和 AOF 膨胀
主从同步:
大 key 修改一次 → 触发全量复制 → 从库压力巨大
AOF:
一次写操作 = 大量 AOF 记录
文件暴涨
④ 集群槽迁移卡住 / 高延迟
如果你在 Redis Cluster 做重平衡:
某个 slot 里有大 key → slot 迁移非常慢(需要把整个 big key copy)
业务会长期高延迟甚至阻塞。
🔍 三、如何发现 Redis 大 Key?
1. redis-cli 内置扫描大 Key
redis-cli --bigkeys
会扫描每种类型的 top1 大 key。
2. 扫描所有大 key(更精准)
redis-cli --hotkeys
redis-cli --scan
3. 键值长度
MEMORY USAGE key
4. 能力更强的方式(企业级)
- 云Redis自带大 Key 分析(阿里云/腾讯云)
- 腾讯 Tendis / CODIS 大 Key Dashboard
- 自建大 Key 检测脚本(scan + type + s/card)
🛠 四、Redis 大 Key 的解决方案(核心部分)
下面是最关键的内容:怎么拆、怎么改、怎么规避。
我按场景给你拆开讲。
🟢 方案 1:拆分大 Hash / List / Set(最常用)
❓ 场景
一个 hash 里有 10 万字段:
user:detail:321123 → { field1:..., field2:... } 10W 字段
✔ 拆分方式:按 hash 分片
user:detail:321123:0
user:detail:321123:1
user:detail:321123:2
...
hash 分片规则:
int shard = field.hashCode() % 10;
redis.hset("user:detail:321123:" + shard, field, value)
适合:
- Hash 超过 1 万字段
- Set 几十万
- ZSet 大量排序数据
- List 几万长度
标准企业级动作。
🔵 方案 2:大 List → 改为分页 List
比如原来 list 保存 100000 条:
lpush feed:list 100000 items
改为:
feed:list:page:1 → 1000 items
feed:list:page:2 → 1000 items
…
业务查询:
get page N
避免 lrange 一次性读全量。
🟣 方案 3:大 String(大 JSON)分片
比如一个 value 是 3MB 的 JSON:
profile:user:10086 = 3MB 大对象
改为拆分:
profile:user:10086:name
profile:user:10086:settings
profile:user:10086:config
profile:user:10086:stats
或:
profile:user:10086:0
profile:user:10086:1
profile:user:10086:2
避免整体序列化、反序列化、网络传输大型对象。
🔶 方案 4:使用 Redis Stream 替换大 List / Log / Queue
不要存海量 List,换 Stream:
XADD stream * field value
XREAD ...
Stream 天然支持分页、历史裁剪、持久化,有效率极高。
🟡 方案 5:设置合理 TTL + 定期清空(可以防止 cold big key)
很多大 key 是业务逻辑 bug 造成的,比如:
- 留存日志不断累积
- 历史数据没人删除
- 采集数据更新不及时
- 用户旧数据未清理
加 TTL:
EXPIRE key 86400
对一些冷数据有惊人的效果。
🟠 方案 6:Del / Unlink 正确删除大 Key(重点!!!)
❌ 不能用传统 DEL
DEL 是阻塞操作!
会卡主线程,非常危险。
✔ 必须用 async delete:UNLINK
UNLINK key
unlink 的特点:
- 异步删除
- 不阻塞主线程
- Redis 4.0+ 支持
你公司线上必须用它。
🔴 方案 7:Redis Cluster 时避免把大 Key 放一个 slot
slot 靠 CRC16(key) 决定。
你可以在 key 里使用:
user:{10086}:follow
user:{10086}:fans
让相同业务 key 分布正确的 slot
但避免把海量数据塞在同一个 key 中。
⚙ 方案 8:业务改造,避免一次性取大对象
很多人会:
HGETALL user:10086:profile → value 超大
造成超大带宽开销。
正确做法:
- 按需读
- 字段拆分
- 分批读
- 不用 HGETALL,用 HMGET
🔥 五、大 Key 面试超强回答(你可以直接复述)
Redis 大 Key 会引发主线程阻塞、网络带宽占用、主从复制延迟、AOF 膨胀、集群槽迁移卡住,是生产环境最高频隐患之一。解决方案主要包括 key 拆分(hash/list/set 分片)、分批读取、避免一次性大对象、使用 UNLINK 异步删除、采用 Stream 替代大 List、给历史数据加 TTL、防止大 JSON、分页结构化存储等。核心就是“避免单个 key 体积过大,避免一次性读写”。