news 2026/1/16 7:33:36

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/1/14 11:42:20

解锁MPC-HC隐藏技能:DVD播放与章节管理完全掌控指南

解锁MPC-HC隐藏技能&#xff1a;DVD播放与章节管理完全掌控指南 【免费下载链接】mpc-hc Media Player Classic 项目地址: https://gitcode.com/gh_mirrors/mp/mpc-hc 还在为DVD播放时的繁琐操作而烦恼吗&#xff1f;Media Player Classic - Home Cinema (MPC-HC) 这款经…

作者头像 李华
网站建设 2026/1/14 9:39:04

32、深入理解文件系统操作:从挂载到目录管理

深入理解文件系统操作:从挂载到目录管理 在文件系统的操作中,有许多重要的概念和操作需要我们去理解和掌握。下面将详细介绍文件系统中一些关键的操作和概念,包括 iget 与 iput 的配对使用、 minodes 锁定机制、根文件系统挂载、基本文件操作命令(如 ls 、 cd 、…

作者头像 李华
网站建设 2026/1/9 3:46:57

传统CH341驱动开发vs快马AI生成:效率对比测试

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个完整的CH341驱动开发效率对比测试项目。包含传统开发方式的分阶段时间记录模板&#xff0c;以及使用快马平台AI生成的完整驱动代码。要求测试案例覆盖设备枚举、数据传输、…

作者头像 李华
网站建设 2025/12/12 16:05:49

33、EXT2文件系统操作详解

EXT2文件系统操作详解 1. 文件删除与移动 当删除文件条目时,如果该条目是块中的第一个但不是唯一的条目,或者位于块的中间,需要将所有后续条目左移以覆盖被删除的条目,并将被删除条目的 rec_len 加到最后一个条目上,同时不改变父文件的大小。以下是删除前后的块内容示…

作者头像 李华
网站建设 2025/12/12 16:05:30

37、深入理解TCP/IP网络编程:从基础到实践

深入理解TCP/IP网络编程:从基础到实践 1. IP主机与IP地址 主机是支持TCP/IP协议的计算机或设备,每台主机由一个32位的IP地址标识。为方便表示,32位IP地址常采用点分十进制表示,如 134.121.64.1 。主机还有主机名,如 dns1.eecs.wsu.edu ,实际应用中多使用主机名,可通…

作者头像 李华
网站建设 2026/1/9 19:01:35

4步生成专业视频:Wan2.1-I2V-Lightx2v如何重构创作效率

4步生成专业视频&#xff1a;Wan2.1-I2V-Lightx2v如何重构创作效率 【免费下载链接】Wan2.1-I2V-14B-480P-StepDistill-CfgDistill-Lightx2v 项目地址: https://ai.gitcode.com/hf_mirrors/lightx2v/Wan2.1-I2V-14B-480P-StepDistill-CfgDistill-Lightx2v 导语 只需4步…

作者头像 李华