Redis BigKey
一、定义
1. 字符串(String)
- Value 大小 ≥ 10KB
2. 集合类(Hash/List/Set/ZSet)
- 元素数量 ≥ 5000(或单 Key 内存占用 ≥ 1MB)
- 可通过
MEMORY USAGE <key>精准获取 Key 内存占用
- 可通过
二、业务场景
1. 日志 / 数据缓存
- 将全量业务日志、批量数据(如订单列表)一次性存入单个 Key
2. 未拆分的业务数据
- 用户全量收货地址、商品全量属性存入单个 Hash Key
3. 消息队列积压
- List 作为消息队列时,消费速度低于生产速度,导致元素堆积成 BigKey
4. 批量导入未分片
- 数据迁移 / 导入时,未按规则拆分,直接将全量数据写入单个 Key
5. 缓存大文件
- 将图片、PDF 等二进制文件以 String 类型存入 Redis(违背 Redis 设计初衷)
三、风险
1. 读取 / 写入耗时
- BigKey 序列化 / 反序列化占用主线程,导致请求延迟飙升(P99 超时)
2. 内存碎片
- BigKey 频繁修改易产生内存碎片,降低 Redis 内存利用率
3. 过期 / 删除阻塞
- DEL 命令删除 BigKey 会阻塞主线程(Redis 8.4 仍未解决,需用 UNLINK)
4. 主从同步延迟
- BigKey 同步占用网络带宽,导致主从节点数据不一致
5. 集群槽位倾斜
- 单个 BigKey 落在某节点,导致该节点内存 / CPU 负载远超其他节点
四、常用操作
1. 生产环境危险命令
- keys / flushdb / flushall
2. 配置 redis.conf 禁用危险命令
# rename-command CONFIG ""
rename-command keys ""
rename-command flushdb ""
rename-command flushall ""
3. 生产环境遍历元素
-
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]- SCAN 遍历键,是一个基于游标的迭代器(O(1))
127.0.0.1:6379> scan 0 match k* count 2 1) "3" 2) 1) "k3" 2) "k4" 127.0.0.1:6379> scan 3 match k* count 2 1) "0" 2) 1) "k2" 2) "k1" -
HSCAN/SSCAN/ZSCAN key cursor [MATCH pattern] [COUNT count] [NOVALUES]- HSCAN 遍历 hash
- SSCAN 遍历 set
- ZSCAN 遍历 zset
五、注意事项
1. 预防层面
(1)数据拆分
- 字符串:按业务维度拆分(如用户日志按天拆分为 user:log:20251230、user:log:20251231)
- 集合类:Hash 按字段范围拆分(如 user:info:1000-2000),List/Set 按数量分片
(2)规范写入
- 禁止直接存储大文件(图片 / 视频),改用分布式文件存储(如 MinIO)+ Redis 存 URL
- 批量写入时限制单次元素数量(如 Hash 单次 HMSET 不超过 1000 字段)
(3)监控预警
-
定期扫描 BigKey:使用 redis-cli --bigkeys 或第三方工具(如 RedisInsight)
[root@yingzai single]#redis-cli -p 6379 -a 12345678 --bigkeys Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. # Scanning the entire keyspace to find biggest keys as well as # average sizes per key type. You can use -i 0.1 to sleep 0.1 sec # per 100 SCAN commands (not usually needed). 100.00% |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| Keys sampled: 4 -------- summary ------- Total key length in bytes is 8 (avg len 2.00) Biggest string found "k3" has 2 bytes 0 lists with 0 items (00.00% of keys, avg size 0.00) 0 hashs with 0 fields (00.00% of keys, avg size 0.00) 0 streams with 0 entries (00.00% of keys, avg size 0.00) 4 strings with 8 bytes (100.00% of keys, avg size 2.00) 0 sets with 0 members (00.00% of keys, avg size 0.00) 0 zsets with 0 members (00.00% of keys, avg size 0.00) -
配置内存告警:对单个 Key 内存占用设置阈值(如 100KB),触发告警及时处理
- Redis 8.4 优化了 MEMORY USAGE 命令性能,可高频检测 Key 内存占用,无显著性能损耗
(4)过期策略
- 避免 BigKey 设置永不过期,按业务周期设置过期时间(如 7 天),减少长期占用
2. 处理层面
(1)删除操作(渐进式删除)
- 禁用 DEL 命令删除 BigKey,改用 UNLINK(异步删除,Redis 8.4 默认支持,后台线程执行)
- 超大集合类 BigKey:分批删除,避免单次操作阻塞
- String 直接 del
- List 使用 trim 截取
- Hash 用 HSCAN 遍历字段,每次读取少量,逐个 HDEL
(2)读取操作
- 避免全量读取 BigKey(如 SMEMBERS、HGETALL),改用分段读取(SSCAN、HSCAN、LRANGE 分页)
- 大字符串读取:按需截取(如 GETRANGE),而非一次性读取全量
(3)集群适配
- BigKey 拆分后均匀分布到不同槽位,避免槽位倾斜
- 禁止在集群中使用跨槽位的 BigKey(如 Hash Tag 导致的单槽位 BigKey)
(4)惰性释放
- 开启 lazy-free 惰性释放配置(lazyfree-lazy-del yes),进一步降低 BigKey 删除的阻塞风险
3. 应急层面
- BigKey 导致主线程阻塞:立即暂停该 Key 的读写,切换到备用 Key 提供服务,低峰期分批清理
- 主从同步延迟:临时降低该 BigKey 的写入频率,或手动触发部分同步(PSYNC)
- 内存溢出风险:优先淘汰非核心 BigKey,或扩容 Redis 节点内存,避免 OOM
六、面试题
1. Redis 的 BigKey、MoreKey、HotKey 问题,如何解决?
(1)概念对比

(2)HotKey
1)危害
- 单节点瓶颈:Redis 是单线程处理命令,单个热键的高频访问会占满该节点的 CPU,导致其他请求阻塞
- 网络拥塞:热键的大量请求会耗尽节点的网络带宽,引发延迟飙升
- 主从同步压力:热键的频繁修改会导致主从复制流量过大,从库同步延迟
- 缓存击穿 / 雪崩:若热键过期 / 失效,大量请求会穿透到数据库,压垮后端服务
2)如何检测
-
redis-cli --hotkeys:内置的热键检测工具,通过扫描键空间统计访问频率(缺点:会阻塞主线程,生产环境慎用)
redis-cli --hotkeys -h {host} -p {port} -a {password} -
INFO commandstats:统计各命令的执行次数,结合业务判断热键(如 GET key1 次数远超其他)
redis-cli INFO commandstats | grep -E "cmdstat_get|cmdstat_hget"
3)解决方案
- 核心思路:分散热键的访问压力
- 具体:

(3)MoreKey
1)危害
- 内存耗尽:大量键占用内存,触发 Redis 内存淘汰策略(如 LRU),导致正常数据被淘汰
- 持久化卡顿:RDB 快照生成时需要遍历所有键,键数量过多会导致 fork 耗时、快照文件过大,AOF 重写同理
- 扫描类命令阻塞:KEYS *、SCAN 等命令遍历大量键,阻塞 Redis 主线程
- 扩容迁移慢:Redis Cluster 扩容时,迁移大量键会占用网络和 CPU,导致服务抖动
- 运维成本高:大量键的管理、监控、排查问题难度剧增
2)如何检测
-
INFO keyspace:查看各数据库的键总数
[root@yingzai single]#redis-cli -p 6379 -a 12345678 info keyspace Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. # Keyspace db0:keys=4,expires=0,avg_ttl=0,subexpiry=0 -
dbsize:快速获取当前数据库的键数量
redis-cli dbsize -
SCAN 遍历统计:非阻塞遍历所有键,统计总数(适合超大量键)
redis-cli --scan | wc -l
3)解决方案
- 核心思路:减少键的数量、合理分片、生命周期管理
- 具体:

2. 什么是 Redis BigKey?生产环境中如何定义 BigKey?
- 见上文“定义”部分
3. Redis BigKey 会带来哪些问题?为什么?
- 主线程阻塞:BigKey 序列化 / 删除耗时,Redis 单线程处理命令,会导致所有请求排队
- 内存碎片:BigKey 频繁修改易产生内存碎片,降低内存利用率
- 主从同步延迟:同步 BigKey 需传输大量数据,占用带宽且序列化耗时
- 集群槽位倾斜:单个 BigKey 集中在某节点,导致该节点负载过高
- 网络带宽占用:BigKey 读写需传输大量数据,消耗网络资源
4. DEL 和 UNLINK 删除 BigKey 的区别?
- DEL 是同步删除(阻塞主线程)
- UNLINK 是异步删除(后台线程执行,仅标记 Key 待删除)
5. 为什么 BigKey 会导致 Redis 主从同步延迟?如何解决?
(1)延迟原因
- 主节点同步 BigKey 需将全量数据通过网络发送给从节点,占用带宽且序列化耗时
(2)解决
- 拆分 BigKey、降低写入频率、使用增量同步、临时关闭该 Key 的同步(低峰期补数据)等
6. 生产环境中发现一个 50w 元素的 Set 类型 BigKey,如何安全删除?
- 确认该 Key 无业务读写(或临时切换备用 Key)
- 禁用 DEL 命令,优先用 UNLINK
- 若 UNLINK 仍有风险,用 SSCAN 分批遍历元素,逐个 SREM 删除
- 清理后监控内存释放和主线程阻塞情况
- 复盘产生原因,优化写入逻辑
7. 如何避免业务代码中产生 BigKey?给出具体的技术方案
- 数据拆分:按时间 / 范围 / 哈希分片
- 写入规范:禁止存大文件、批量写入限流
- 监控预警:定期扫描 + 阈值告警
- 过期策略:避免永不过期
8. 集群环境中 BigKey 导致某节点内存使用率 90%,其他节点仅 30%,如何处理?
- 紧急处理:将该 BigKey 拆分,迁移部分数据到其他节点
- 短期优化:调整集群槽位映射,均衡节点负载
- 长期优化:规范 Key 命名和分片规则(如 Hash Tag 避免单槽位堆积),完善 BigKey 监控和自动拆分机制
9. Redis BigKey 和 HotKey 有什么区别?处理方式有哪些不同?
(1)区别
- 定义:BigKey 是内存 / 元素量大,HotKey 是访问频率高
- 影响:BigKey 影响内存 / 阻塞,HotKey 影响 CPU / 带宽
(2)处理方式
- BigKey 侧重拆分 / 异步删除
- HotKey 侧重缓存分片 / 读写分离
10. 为什么不建议用 Redis 存储大文件(如 1MB 以上的图片)?有什么替代方案?
- 原因:Redis 设计初衷是内存缓存,大文件会占用大量内存且读写耗时
- 替代方案:用分布式文件存储(MinIO/OSS)存储文件,Redis 仅存储文件 URL 和元数据