您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
真实案例解析缓存大热key的致命陷阱
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
真实案例解析缓存大热key的致命陷阱
fl****
2024-12-17
IP归属:北京
100浏览
### 引言 在现代软件架构中,缓存是提高系统性能和响应速度的重要手段。然而,如果不正确地使用缓存,可能会导致严重的线上事故,尤其是缓存的大热key问题更是老生常谈。本文将探讨一个常见但容易被忽视的问题:缓存大热key和缓存击穿问题。我们将从一个真实案例入手,分析其原因,并提供解决方案和预防措施。 ### 案例描述 某系统在双十一大促期间,遇到了一个严重的线上事故。业务人员在创建一个大型活动,该大型活动由于活动条件和活动奖励比较多,导致生成的缓存内容非常大。活动上线后,系统就开始出现各种异常告警,核心UMP监控可用率由100%持续下降到20%,系统访问Redis的调用次数和查询性能也断崖式下降,后续更是产生连锁反应影响了其他多个核心接口的可用率,导致整个系统服务不可用。 ### 原因分析 在这个系统中,为了提高查询活动的性能,我们开发团队决定使用Redis作为缓存系统。将每个活动信息作为一个key-value存储在Redis中。由于业务需要,有时候业务运营人员也会创建一个非常庞大的活动,来支撑双十一期间的各种玩法。针对这种庞大的活动,我们开发团队也提前预料到了可能会出现的大key和热key问题,所以在查询活动缓存之前增加了一层本地jvm缓存,本地jvm缓存5分钟,缓存失效后再去回源查询Redis中的活动缓存,本以为会万无一失,没想到最后还是出了问题。 ![image.png](https://s3.cn-north-1.jdcloud-oss.com/shendengbucket1/2024-11-29-17-5656bXvRUyer65P11xy.png) 查询方法伪代码 ```java ActivityCache present = activityLocalCache.getIfPresent(activityDetailCacheKey); if (present != null) { ActivityCache activityCache = incentiveActivityPOConvert.copyActivityCache(present); return activityCache } ActivityCache remoteCache = getCacheFromRedis(activityDetailCacheKey); activityLocalCache.put(activityDetailCacheKey, remoteCache); return remoteCache; ``` 查询活动缓存流程如上图所示,为什么加了本地缓存还是出了问题? 这里其实就存在着第一个缓存陷阱:缓存击穿问题。首先解释一下什么是缓存击穿;缓存击穿(Cache Miss)是指在高并发的系统中,如果某个缓存键对应的值在缓存中不存在(即缓存失效),那么所有请求都会直接访问后端数据库,导致数据库的负载瞬间增加,可能会引发数据库宕机或服务不可用的情况。所以在本次事故里边,运营人员审批活动上线的一瞬间,活动缓存只是写入到了Redis缓存中,但是本地缓存还都是空的,所以此时就会有大量请求来同时访问Redis。 按照以往经验,Redis缓存都是纯内存操作,查询性能可以满足大量请求同时查询活动缓存,就在此时我们却陷入了第二个缓存陷阱:网络带宽瓶颈;Redis的高并发性能毋庸置疑,但是我们却忽略了一个大key和热key对网络带宽的影响,本次引发问题的大热key大小达到了1.5M,经过事后了解京东Redis对单分片的网络带宽也有限流,默认200M,根据换算,该热key最多只能支持133次的并发访问。所以就在活动上线的同一时刻,加上缓存击穿的影响,迅速达到了Redis单分片的带宽限流阈值,导致Redis线程进入阻塞状态,以至于所有的业务服务器都无法查询Redis缓存成功,最终引发了缓存雪崩效应。 ### 解决方案 为了解决这个问题,我们开发团队采取了以下措施: 1. **大key治理**:更换缓存对象序列化方法,由原来的JSON序列化调整为Protostuff序列化方式。治理效果:缓存对象大小由1.5M减少到了0.5M。 2. **使用压缩算法**:在存储缓存对象时,再使用压缩算法(如gzip)对数据进行压缩,注意设置压缩阈值,超过一定阈值后再进行压缩,以减少占用的内存空间和网络传输的数据量。压缩效果:500k压缩到了17k。 3. **缓存回源优化**:本地缓存miss后回源查询Redis增加线程锁,减少回源Redis并发数量。 4. **监控和优化Redis配置**:定期监控Redis网络传输情况,根据实际情况调整Redis的限流配置,以确保Redis的稳定运行。 治理后业务伪代码如下: ```java ActivityCache present = activityLocalCache.get(activityDetailCacheKey, key -> getCacheFromRedis(key)); if (present != null) { return present; } ``` ```java /** * 查询二进制缓存 * * @param activityDetailCacheBinKey * @return */ private ActivityCache getBinCacheFromJimdb(String activityDetailCacheBinKey) { List<byte[]> activityByteList = slaveCluster.hMget(activityDetailCacheBinKey.getBytes(),"stock".getBytes()); if (activityByteList.get(0) != null && activityByteList.get(0).length > 0) { byte[] decompress = ByteCompressionUtil.decompress(activityByteList.get(0)); ActivityCache activityCache = ProtostuffUtil.deserialize(decompress, ActivityCache.class); if (activityCache != null) { if (activityByteList.get(1) != null && activityByteList.get(1).length > 0) { activityCache.setAvailableStock(Integer.valueOf(new String(activityByteList.get(1)))); } return activityCache; } } return null; ``` ### 预防措施 为了避免类似的问题再次发生,开发团队采取了以下预防措施: 1. **设计阶段考虑缓存策略**:在系统设计阶段,充分考虑缓存的使用场景和数据特性,避免盲目使用大key缓存。 2. **进行压力测试和性能评估**:在上线前,进行充分的压力测试和性能评估,模拟高并发和大数据量的情况,及时发现和解决潜在问题。 3. **定期进行系统优化和升级**:随着业务的发展和技术的进步,定期对系统进行优化和升级,引入新的技术和工具来提高系统的性能和稳定性。 ### 结论 缓存大key和热key是缓存使用中常见的陷阱,千万不要心存侥幸,否则会引发严重的线上事故。通过本文的案例分析和解决方案,我们希望能够帮助读者更好地理解和应对这个问题。记住,合理使用缓存是提高系统性能的关键,而不是简单地将所有数据都存储在缓存中。
上一篇:善用Optional,告别NPE
下一篇:垃圾短信?手机自动识别垃圾短信逻辑的分析
fl****
文章数
11
阅读量
2879
作者其他文章
01
千万级数据深分页查询SQL性能优化实践
一、系统介绍和问题描述 如何在Mysql中实现上亿数据的遍历查询?先来介绍一下系统主角:关注系统,主要是维护京东用户和业务对象之前的关注关系;并对外提供各种关系查询,比如查询用户的关注商品或店铺列表,查询用户是否关注了某个商品或店铺等。但是最近接到了一个新需求,要求提供查询关注对象的粉丝列表接口功能。该功能的难点就是关注对象的粉丝数量过多,不少店铺的粉丝数量都是千万级别,并且有些大V
01
ElasticSearch - 批量更新bulk死锁问题排查
一、问题系统介绍1. 监听商品变更MQ消息,查询商品最新的信息,调用BulkProcessor批量更新ES集群中的商品字段信息;2. 由于商品数据非常多,所以将商品数据存储到ES集群上,整个ES集群共划分了256个分片,并根据商品的三级类目ID进行分片路由。比如一个SKU的商品名称发生变化,我们就会收到这个SKU的变更MQ消息,然后再去查询商品接口,将商品的最新名称查询回来,再根据这个SKU的三级
01
京东统一头尾管理系统探索实践
系统背景 问:修改一个网站的文案需要多久?对于一个小型个人网站来说,估计很简单,几分钟就能修改完成并发布。但如果说要修改的是上百个网站的文案呢?那估计就得需要产品提需求,研发排期开发,测试进行回归验证。由于涉及的应用众多,而每个应用都有自己的研发需求,可能无法快速排期进行文案修改。所以看似一个非常简单的需求,涉及到的应用和部门比较多的时候,也就成了产品经理的恶梦。尤其是像京东商城这样
01
百亿规模京东实时浏览记录系统的设计与实现
1. 系统介绍浏览记录系统主要用来记录京东用户的实时浏览记录,并提供实时查询浏览数据的功能。在线用户访问一次商品详情页,浏览记录系统就会记录用户的一条浏览数据,并针对该浏览数据进行商品维度去重等一系列处理并存储。然后用户可以通过我的京东或其他入口查询用户的实时浏览商品记录,实时性可以达到毫秒级。目前本系统可以为京东每个用户提供最近200条的浏览记录查询展示。2. 系统设计与实现2.1 系统整体架构
fl****
文章数
11
阅读量
2879
作者其他文章
01
千万级数据深分页查询SQL性能优化实践
01
ElasticSearch - 批量更新bulk死锁问题排查
01
京东统一头尾管理系统探索实践
01
百亿规模京东实时浏览记录系统的设计与实现
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号