news 2026/4/23 12:15:50

Redis突然变慢,排查发现是BigKey惹的祸

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis突然变慢,排查发现是BigKey惹的祸

线上Redis响应时间从平均1ms飙到了50ms,业务接口全都变慢了。

查了半天,最后发现是一个BigKey导致的。记录一下排查过程。


问题现象

监控数据

  • Redis平均响应时间:1ms → 50ms
  • 业务接口P99延迟:50ms → 500ms
  • Redis CPU:20% → 80%
  • 内存使用:正常

特点

  • 突然变慢,不是逐渐变慢
  • 所有命令都变慢,不只是特定命令
  • 重启后好一段时间,然后又变慢

排查过程

Step 1:查看慢查询日志

redis-cli# 查看慢查询日志SLOWLOG GET20

输出:

1) 1) (integer) 1001 2) (integer) 1702345678 3) (integer) 45123 # 微秒,约45ms 4) 1) "HGETALL" 2) "user:session:12345"

发现大量HGETALL命令耗时几十毫秒,正常应该是亚毫秒级。

Step 2:查看这个Key的信息

# 查看Key类型TYPE user:session:12345# hash# 查看Hash的字段数量HLEN user:session:12345# 182356# 查看Key占用内存DEBUG OBJECT user:session:12345# serializedlength:15728640 约15MB

问题找到了!这个Hash有18万个字段,占用15MB内存。

这就是BigKey,对它执行HGETALL要把18万个字段全部遍历,当然慢。

Step 3:查找其他BigKey

# Redis 4.0+ 可以用 --bigkeys 扫描redis-cli --bigkeys# 或者用 SCAN 配合 DEBUG OBJECTredis-cli --scan --pattern'*'|whilereadkey;dosize=$(redis-cli DEBUG OBJECT"$key"2>/dev/null|grep-oP'serializedlength:\K\d+')if["$size"-gt1048576];then# 大于1MBecho"$key:$sizebytes"fidone

扫描结果发现了多个BigKey:

user:session:12345: 15728640 bytes (15MB) cache:product:list: 8388608 bytes (8MB) temp:import:batch: 5242880 bytes (5MB)

Step 4:分析业务逻辑

查代码发现问题:

// 问题代码:把整个session存成一个大Hash@OverridepublicvoidsaveSession(StringsessionId,Map<String,Object>data){Stringkey="user:session:"+sessionId;// 每次访问都往里加数据,从来不清理redisTemplate.opsForHash().putAll(key,data);}// 获取时用HGETALLpublicMap<String,Object>getSession(StringsessionId){Stringkey="user:session:"+sessionId;returnredisTemplate.opsForHash().entries(key);// HGETALL}

问题

  1. Session数据一直往Hash里加,不删除
  2. 时间一长,Hash就变成了BigKey
  3. 每次获取Session都用HGETALL,遍历整个Hash

BigKey的危害

1. 阻塞单线程

Redis是单线程的,操作BigKey时会阻塞其他命令:

正常Key(1KB): 1ms完成 BigKey(10MB): 50ms完成 这50ms内其他所有命令都在排队等待

2. 网络带宽压力

每次HGETALL返回15MB数据 1秒请求10次 = 150MB/s 网络可能成为瓶颈

3. 内存不均衡

如果是Redis集群,BigKey会导致某个节点内存远大于其他节点。

4. 删除时阻塞

DEL user:session:12345# 删除15MB的Key,可能阻塞好几秒

解决方案

方案一:拆分BigKey

把大Hash拆成多个小Hash:

// 优化前:一个大Hashuser:session:12345{field1:v1,field2:v2,...field180000:v180000}// 优化后:按照某种规则拆分user:session:12345:0{field1:v1,...field1000:v1000}user:session:12345:1{field1001:v1001,...field2000:v2000}...

方案二:改用合适的数据结构

Session数据不需要存18万个字段,只需要保留最近访问的数据:

// 使用String存储序列化后的数据,设置过期时间publicvoidsaveSession(StringsessionId,SessionDatadata){Stringkey="user:session:"+sessionId;Stringjson=JSON.toJSONString(data);redisTemplate.opsForValue().set(key,json,30,TimeUnit.MINUTES);}

方案三:避免HGETALL

// 优化前:获取整个HashMap<String,Object>all=redisTemplate.opsForHash().entries(key);// 优化后:只获取需要的字段Objectvalue=redisTemplate.opsForHash().get(key,"targetField");// 或者批量获取部分字段List<Object>values=redisTemplate.opsForHash().multiGet(key,Arrays.asList("f1","f2"));

方案四:异步删除BigKey

# Redis 4.0+ 支持异步删除UNLINK user:session:12345# 异步删除,不阻塞# 或者渐进式删除Hash# 每次删1000个字段HSCAN user:session:123450COUNT1000HDEL user:session:12345 field1 field2... field1000

最终解决

  1. 临时处理:用UNLINK异步删除那几个BigKey
  2. 代码修复:Session改用String存储,设置30分钟过期
  3. 添加监控:定期扫描BigKey,超过1MB告警

BigKey标准

数据类型BigKey阈值说明
String> 10KB单个值太大
Hash> 5000字段 或 > 10MB字段太多或总大小太大
List> 5000元素元素太多
Set> 5000成员成员太多
ZSet> 5000成员成员太多

排查命令汇总

# 查看慢查询SLOWLOG GET20# 扫描BigKeyredis-cli --bigkeys# 查看Key类型TYPE<key># 查看Hash字段数HLEN<key># 查看List长度LLEN<key># 查看Set成员数SCARD<key># 查看内存占用(需要开启)MEMORY USAGE<key># 查看Key详情DEBUG OBJECT<key># 渐进式扫描HSCAN<key>0COUNT100# 异步删除UNLINK<key>

预防措施

1. 设计阶段

✅ 预估数据量,避免无限增长 ✅ 设置合理的过期时间 ✅ 考虑数据拆分策略

2. 开发阶段

✅ 避免使用HGETALL、SMEMBERS等全量命令 ✅ 大数据量使用SCAN系列命令 ✅ 删除大Key使用UNLINK

3. 运维阶段

✅ 定期扫描BigKey ✅ 监控慢查询 ✅ 设置maxmemory-policy

经验总结

现象可能原因
所有命令都变慢BigKey阻塞
特定命令变慢该命令操作了BigKey
内存突然增长写入了BigKey
主从同步延迟BigKey传输

这次的坑:Session数据只写不删,时间一长变成了18万字段的BigKey。

教训

  1. Redis的Key一定要设置过期时间
  2. 避免使用HGETALL等全量命令
  3. 定期扫描BigKey,加入监控

有问题评论区交流~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 7:49:24

【Java毕设全套源码+文档】基于springboot的果蔬种植销售一体化服务平台的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/23 7:50:38

超越SIFT与ORB:深入OpenCV特征检测API的设计哲学与高阶实践

好的&#xff0c;请看这篇关于OpenCV特征检测API的技术文章&#xff1a; 超越SIFT与ORB&#xff1a;深入OpenCV特征检测API的设计哲学与高阶实践 引言&#xff1a;特征检测的演进与OpenCV的桥梁角色 在计算机视觉的宏大叙事中&#xff0c;局部特征检测与描述始终扮演着“基石探…

作者头像 李华
网站建设 2026/4/23 9:17:29

RookieAI_yolov8:颠覆性AI游戏辅助技术实战指南

RookieAI_yolov8&#xff1a;颠覆性AI游戏辅助技术实战指南 【免费下载链接】RookieAI_yolov8 基于yolov8实现的AI自瞄项目 项目地址: https://gitcode.com/gh_mirrors/ro/RookieAI_yolov8 RookieAI_yolov8作为基于YOLOv8深度优化的开源AI自瞄项目&#xff0c;通过革命性…

作者头像 李华
网站建设 2026/4/23 9:19:14

【63】特征匹配:LATCH二值描述符的原理与Python实现

简介 本文围绕2015年CVPR提出的LATCH&#xff08;Learned Arrangements of Three Patch Codes&#xff09;二值特征描述符展开&#xff0c;解析其对传统二值描述符的优化思路——用像素块比较替代点对比较以平衡速度与唯一性。结合OpenCV-Python&#xff0c;我们将完整实现LATC…

作者头像 李华