真实案例解析缓存大热key的致命陷阱
在现代软件架构中,缓存是提高系统性能和响应速度的重要手段。然而,如果不正确地使用缓存,可能会导致严重的线上事故,尤其是缓存的大热key问题更是老生常谈。本文将探讨一个常见但容易被忽视的问题:缓存大热key和缓存击穿问题。我们将从一个真实案例入手,分析其原因,并提供解决方案和预防措施。
某系统在双十一大促期间,遇到了一个严重的线上事故。业务人员在创建一个大型活动,该大型活动由于活动条件和活动奖励比较多,导致生成的缓存内容非常大。活动上线后,系统就开始出现各种异常告警,核心UMP监控可用率由100%持续下降到20%,系统访问Redis的调用次数和查询性能也断崖式下降,后续更是产生连锁反应影响了其他多个核心接口的可用率,导致整个系统服务不可用。
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;
为了解决这个问题,开发团队采取了以下措施:
大key治理:更换缓存对象序列化方法,由原来的JSON序列化调整为Protostuff序列化方式。治理效果:缓存对象大小由1.5M减少到了0.5M。 使用压缩算法:在存储缓存对象时,再使用压缩算法(如gzip)对数据进行压缩,注意设置压缩阈值,超过一定阈值后再进行压缩,以减少占用的内存空间和网络传输的数据量。压缩效果:500k压缩到了17k。
缓存回源优化:本地缓存miss后回源查询Redis增加线程锁,减少回源Redis并发数量。
监控和优化Redis配置:定期监控Redis网络传输情况,根据实际情况调整Redis的限流配置,以确保Redis的稳定运行。
治理后业务伪代码如下:
ActivityCache present = activityLocalCache.get(activityDetailCacheKey, key -> getCacheFromRedis(key));if (present != null) {return present;}
/*** 查询二进制缓存** @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;
为了避免类似的问题再次发生,开发团队采取了以下预防措施:
设计阶段考虑缓存策略:在系统设计阶段,充分考虑缓存的使用场景和数据特性,避免盲目使用大key缓存。
进行压力测试和性能评估:在上线前,进行充分的压力测试和性能评估,模拟高并发和大数据量的情况,及时发现和解决潜在问题。
定期进行系统优化和升级:随着业务的发展和技术的进步,定期对系统进行优化和升级,引入新的技术和工具来提高系统的性能和稳定性。
缓存大key和热key是缓存使用中常见的陷阱,千万不要心存侥幸,否则会引发严重的线上事故。通过本文的案例分析和解决方案,我们希望能够帮助读者更好地理解和应对这个问题。记住,合理使用缓存是提高系统性能的关键,而不是简单地将所有数据都存储在缓存中。
推荐阅读
Daniel H. Wagner Prize | 京东供应链创新与实践:应用数据驱动的库存选品和调拨算法提升履约效率