当前位置: 首页 > news >正文

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

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

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


问题现象

监控数据

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

特点

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

排查过程

Step 1:查看慢查询日志

redis-cli# 查看慢查询日志
SLOWLOG GET 20

输出:

1) 1) (integer) 10012) (integer) 17023456783) (integer) 45123      # 微秒,约45ms4) 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 OBJECT
redis-cli --scan --pattern '*' | while read key; dosize=$(redis-cli DEBUG OBJECT "$key" 2>/dev/null | grep -oP 'serializedlength:\K\d+')if [ "$size" -gt 1048576 ]; then  # 大于1MBecho "$key: $size bytes"fi
done

扫描结果发现了多个BigKey:

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

Step 4:分析业务逻辑

查代码发现问题:

// 问题代码:把整个session存成一个大Hash
@Override
public void saveSession(String sessionId, Map<String, Object> data) {String key = "user:session:" + sessionId;// 每次访问都往里加数据,从来不清理redisTemplate.opsForHash().putAll(key, data);
}// 获取时用HGETALL
public Map<String, Object> getSession(String sessionId) {String key = "user:session:" + sessionId;return redisTemplate.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:

// 优化前:一个大Hash
user: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存储序列化后的数据,设置过期时间
public void saveSession(String sessionId, SessionData data) {String key = "user:session:" + sessionId;String json = JSON.toJSONString(data);redisTemplate.opsForValue().set(key, json, 30, TimeUnit.MINUTES);
}

方案三:避免HGETALL

// 优化前:获取整个Hash
Map<String, Object> all = redisTemplate.opsForHash().entries(key);// 优化后:只获取需要的字段
Object value = 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:12345 0 COUNT 1000
HDEL 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 GET 20# 扫描BigKey
redis-cli --bigkeys# 查看Key类型
TYPE <key># 查看Hash字段数
HLEN <key># 查看List长度
LLEN <key># 查看Set成员数
SCARD <key># 查看内存占用(需要开启)
MEMORY USAGE <key># 查看Key详情
DEBUG OBJECT <key># 渐进式扫描
HSCAN <key> 0 COUNT 100# 异步删除
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,加入监控

有问题评论区交流~


http://www.jsqmd.com/news/76879/

相关文章:

  • 2025年管壳式换热器生产厂家排行推荐:5家耐腐蚀设备企业全 - mypinpai
  • Llama-Factory是否支持模型剪枝?轻量化部署方案
  • 手把手教你用JS正则表达式,轻松实现密码强度分步校验
  • 中国木门十大品牌排行榜:2025年行业品质与创新力解析 - 品牌排行榜
  • 2025年售后完善的热像仪供应商TOP5推荐:热像仪优质厂家 - 工业品牌热点
  • 2025垃圾袋行业TOP5权威推荐:河北瑞动包装,破解破袋漏 - myqiye
  • 2025年中国十大热像仪推荐:靠谱的热像仪生产厂家有哪些? - 工业推荐榜
  • 2025年Exd IICT6防爆电动执行器厂家?粉尘防爆电动执行机构厂家? - 品牌推荐大师1
  • 平台工程落地:我把新人的本地环境全扔了,入职10分钟开干
  • 2025年口碑不错的热像仪服务商推荐:看哪家热像仪品质优 - 工业推荐榜
  • AI都帮你写好代码了,你离上线只差这最后一步。
  • YTSage全面指南:5分钟掌握现代化视频下载神器
  • 56、Linux网络服务配置与安全指南
  • 2025年支持HART/Profibus/Modbus协议的智能执行器哪家有?国内十大智能型电动执行器品牌排行榜?国内电动执行器一线品牌知名品牌推荐厂家 - 品牌推荐大师1
  • C++、Qt中打开文件夹获取文件
  • 多存储源文件同步终极方案:5分钟搞定跨平台数据一致性
  • ChatTTS-ui Docker部署完全指南:GPU与CPU版本一键配置
  • 强力打造专属音乐服务器:MPD音乐播放器守护进程深度解析
  • AgenticSeek深度解析:本地自主AI代理的技术架构与实践指南
  • 阿里云服务器上使用docker容器部署了mysql,但是现在想直接在服务器上部署mysql怎么操作?
  • Redis 的内存回收机制详解
  • 基于微信小程序的垃圾分类信息系统毕业设计项目源码
  • 5D动感影院设备与9D裸眼轨道影院投资价格对比解析
  • xv6 文件系统
  • Next.js配置进阶:从基础到企业级实践全指南
  • 2025十大厨余处理器解析:热门机型特点呈现,辅助选购决策 - 资讯焦点
  • VITS语音合成实战指南:从零开始打造你的专属AI语音助手
  • 生产计划和排产计划,到底差在哪?一文讲透生产管理本质
  • 技术拆解:1688 API 接口开发全流程与商品数据抓取方案
  • 阿里云新发的AgentRun 有哪些“大招”,一文详解来了