第三部分:缓存雪崩——大量key失效引发的“系统性崩溃”

缓存雪崩的本质是“大量缓存key在同一时间失效,或缓存集群整体故障”,导致请求全量穿透至DB,引发“系统性崩溃”。

案例4:电商首页的“批量过期”灾难

故障现场

某电商平台首页缓存架构为“Redis集群+MySQL”,所有首页商品缓存key(home:item:*)设置相同过期时间(2小时),每日凌晨2点批量更新缓存。

  • 故障:某日凌晨2点,缓存批量过期,首页访问量(5000QPS)全量穿透至MySQL,DB连接池瞬间耗尽,首页无法访问,连带订单、支付等核心服务因依赖首页接口超时,引发系统性崩溃。
根因解剖
  1. 所有热点key设置相同过期时间,导致“时间点共振”;
  2. 缓存更新采用“先删除旧缓存,再更新DB,最后写入新缓存”的方式,存在“更新窗口”内的穿透风险;
  3. 未设置多级缓存,Redis故障后无降级方案。
四层防御方案落地
方案1:过期时间“随机化”

核心逻辑:对同一类key设置基础过期时间+随机偏移量(如2小时±10分钟),避免“时间点共振”。

实战代码

@Service
public class HomeCacheService {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate ItemMapper itemMapper;// 基础过期时间(2小时)private static final long BASE_TTL = 7200;// 随机偏移量范围(±10分钟,即600秒)private static final int RANDOM_OFFSET = 600;/*** 更新首页商品缓存(带随机过期时间)*/public void updateHomeItems() {List<ItemDTO> items = itemMapper.listHomeItems();// 生成随机数生成器Random random = new Random();for (ItemDTO item : items) {String cacheKey = "home:item:" + item.getId();// 计算随机过期时间(BASE_TTL ± RANDOM_OFFSET)long ttl = BASE_TTL + (random.nextInt(2 * RANDOM_OFFSET) - RANDOM_OFFSET);redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(item), ttl, TimeUnit.SECONDS);}}
}

效果:缓存过期时间分散在110-130分钟,避免批量过期,DB峰值QPS从5000降至1500。

方案2:多级缓存架构

核心逻辑:构建“本地缓存(Caffeine)→ Redis → DB”的三级缓存,即使Redis失效,本地缓存仍能拦截部分流量。

实战代码

@Service
public class HomeItemService {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate ItemMapper itemMapper;// 本地缓存(Caffeine):首页商品缓存10分钟private final LoadingCache<String, ItemDTO> localCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(1000).build(this::loadFromRedis);/*** 查询首页商品(三级缓存)*/public ItemDTO getHomeItem(Long itemId) {String key = "home:item:" + itemId;try {// 1. 查询本地缓存return localCache.get(key);} catch (Exception e) {log.warn("本地缓存未命中,itemId={}", itemId, e);// 2. 本地缓存失效,直接查询DB并更新各级缓存ItemDTO item = itemMapper.selectById(itemId);if (item != null) {// 更新RedisredisTemplate.opsForValue().set(key, JSON.toJSONString(item), getRandomTtl(), TimeUnit.SECONDS);// 更新本地缓存localCache.put(key, item);}return item;}}// 从Redis加载(Caffeine的加载函数)private ItemDTO loadFromRedis(String key) {String redisVal = redisTemplate.opsForValue().get(key);return redisVal != null ? JSON.parseObject(redisVal, ItemDTO.class) : null;}// 随机过期时间(同方案1)private long getRandomTtl() { ... }
}

架构图

[用户请求] → [本地缓存(Caffeine)] → [Redis集群] → [MySQL]↓                ↓                ↓10分钟过期       2小时±10分钟     最终数据源

实战效果:Redis集群故障时,本地缓存拦截60%的请求,DB查询量从5000QPS降至2000QPS,系统未崩溃。

方案3:缓存更新“先更新后删除”

核心逻辑:将“删除旧缓存→更新DB→写入新缓存”改为“更新DB→写入新缓存→删除旧缓存”,避免更新窗口内的穿透。

实战代码

@Transactional(rollbackFor = Exception.class)
public void updateItem(ItemDTO item) {// 1. 先更新DBitemMapper.updateById(item);// 2. 写入新缓存(带新版本号)String newKey = "item:v2:" + item.getId();redisTemplate.opsForValue().set(newKey, JSON.toJSONString(item), getRandomTtl(), TimeUnit.SECONDS);// 3. 异步删除旧缓存(避免阻塞主流程)CompletableFuture.runAsync(() -> {String oldKey = "item:v1:" + item.getId();redisTemplate.delete(oldKey);});
}

效果:缓存更新窗口从1秒缩短至10ms,穿透风险降低99%。

方案4:Redis高可用+熔断降级

核心逻辑

  • Redis集群部署(主从+哨兵),确保单点故障不影响整体;
  • 对Redis操作设置熔断(如Resilience4j),故障时快速降级。

实战代码(Redis熔断)

@Service
public class RedisServiceWithFallback {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate CircuitBreakerRegistry circuitBreakerRegistry;/*** 带熔断的Redis查询*/public String getWithFallback(String key) {CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("redisGet");return Try.ofSupplier(CircuitBreaker.decorateSupplier(breaker, () -> redisTemplate.opsForValue().get(key))).recover(Exception.class, e -> {log.warn("Redis查询熔断,key={}", key, e);return null; // 熔断时返回null,触发后续降级逻辑}).get();}
}

实战效果:Redis集群单节点故障时,哨兵自动切换(30秒内),熔断机制确保故障期间接口不超时,系统可用性达99.99%。

雪崩防御总结

方案适用场景优点缺点实施成本
过期时间随机化批量缓存场景实现简单,无额外依赖无法解决集群故障问题
多级缓存核心业务保护多一层防护,性能好一致性维护复杂
更新策略优化缓存频繁更新场景减少更新窗口穿透需要版本号管理
高可用+熔断集群级故障防护兜底保障,可用性高运维成本高

实战总览:缓存故障防御决策树

面对缓存三大劫,需根据业务场景选择合适方案,以下决策树可快速定位防御策略:

  1. 是否为高频无效key?
    → 是 → 布隆过滤器+缓存空值
    → 否 → 进入下一步

  2. 是否存在热点key?
    → 是 → 逻辑永不过期/分布式锁
    → 否 → 进入下一步

  3. 是否有批量过期风险?
    → 是 → 过期时间随机化+多级缓存
    → 否 → 进入下一步

  4. 是否需极端场景保护?
    → 是 → 限流+熔断降级
    → 否 → 基础缓存策略

缓存防御的核心不是“消灭问题”,而是“控制风险”。通过多层防御体系,将故障影响控制在可接受范围,同时平衡性能、一致性和开发成本,才是实战中的最优解。记住:最好的防御方案,永远是最适合业务场景的方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96417.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96417.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96417.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决docker配置了镜像源但还会拉取官方镜像源的问题

&#x1f3d3;我们有时候虽然配置了Docker国内镜像源&#xff0c;但是还是会绕过去请求官方镜像源&#xff08;docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded&#xff09;&#xff0c;现在我们就来解决一…

R语言水文、水环境模型优化:从最速上升法、岭分析到贝叶斯优化与异方差处理,涵盖采样设计、代理模型与快速率定等

在水利工程、环境治理、生态保护、机械设计与航天航空等现代工业与科学领域&#xff0c;数学模型已成为不可或缺的核心分析、预测与决策工具。然而&#xff0c;随着系统复杂性的日益增长&#xff0c;模型构建的精确性、参数率定的效率以及不确定性量化的重要性被提到了前所未有…

关于数据采集与处理心得(一)

目前所实践的经验告知我&#xff01;1. 别企图妄想一个脚本解决所有问题要学会对问题分解&#xff0c;编写多个脚本一步步将问题解决&#xff0c;如果每一个步骤都为了下一个阶段的成果打地基&#xff0c;也是非常OK的。同时要尽可能将每一个编写的脚本都尽到最大的利用率2. 编…

IvorySQL 适配 LoongArch® 龙架构

IvorySQL 社区很高兴向您宣布&#xff0c;IvorySQL 已成功适配LoongArch 龙架构&#xff0c;为国产数据库与国产芯片的深度融合迈出了坚实一步。这一里程碑标志着 IvorySQL 在推动国产化生态建设、赋能信创产业方面取得了重大突破&#xff0c;为用户提供更高效、稳定、安全的数…

数据库分库分表是考虑ShardingSphere 还是Mycat?

http://www.mycat.org.cn/ https://shardingsphere.apache.org/ 这是一个非常核心且优秀的问题。在选择 ShardingSphere 和 Mycat 之间&#xff0c;对于游戏这种高性能、高复杂度的场景&#xff0c;目前行业内的主流选择和发展趋势毫无疑问是 ShardingSphere。 我会为你详细对…

mysql分库分表数据量核查问题

场景&#xff1a; 使用分库分表的业务有时分库数量几百甚至上千&#xff0c;当主管需要查询每个库中的数据&#xff0c;掌握数据分布情况。要你查看哪些库中的表数量大于某个量级的给找出来 &#xff0c;你会怎么做。 例子 &#xff1a; mysql库数量&#xff1a;db_xx_devicein…

python之socket网络编程

引言 在互联网时代&#xff0c;网络编程已经成为开发人员必备的技能之一。无论是Web开发、实时通信还是分布式计算&#xff0c;都离不开网络编程的支持。Python提供的socket模块为我们提供了简洁而强大的接口&#xff0c;可以轻松实现客户端和服务器之间的通信。 Socket编程是网…

WPF Telerik.Windows.Controls.Data.PropertyGrid 自定义属性编辑器

1.AI帮忙定义新用户控件 2.在属性上添加TelerikEditorAttribute特性 private ObservableCollection<string> _axisOrder;[Display(Description "点位", GroupName "通用", Name "轴&顺序", Order 1)][DataMember][TelerikEditorAt…

【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

43.shell脚本循环与函数

shell脚本循环与函数 for 循环 for 循环用于一次性读取多个信息&#xff0c;逐一对信息进行操作处理&#xff0c;特别适合处理有范围的数据 语法 for 变量名 in 取值列表 do命令序列 done批量创建用户 #!/bin/bashtouch /root/users.txt echo aka blues cloe dio foks > /ro…

模型部署:(四)安卓端部署Yolov8-v8.2.99实例分割项目全流程记录

模型部署&#xff1a;&#xff08;四&#xff09;安卓端部署Yolov8-v8.2.99实例分割项目全流程记录1、下载ncnn2、下载opencv-mobile3、文件拷贝4、andorid_studio相关配置5、文件内参数设置5、重构项目&#xff1a;6、打包apk7、部署自己训练的实例分割模型1、下载ncnn 地址&…

高并发、低延迟全球直播系统架构

一、 核心架构图 整个系统的数据流和工作流程如下图所示&#xff0c;它清晰地展示了从主播推流到观众观看的完整过程&#xff1a; #mermaid-svg-QzNpj0DWxd5FERPC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QzN…

AWS strands agents 当智能体作为独立服务/容器部署时,它们无法共享进程内状态

当智能体作为独立服务/容器部署时&#xff0c;它们无法共享进程内状态。 以下是针对分布式部署中动态内存库的生产就绪解决方案&#xff1a;1. 基于外部存储的内存库基于 DynamoDB 的共享内存import boto3 from strands import Agent, tool from typing import Dict, Any impor…

第五节 JavaScript——引用类型、DOM/BOM 与异步编程

JavaScript 的第五节课通常会深入探讨 ​​引用类型、DOM 操作、BOM 操作、事件处理以及异步编程​​ 等核心概念。这些知识能让你创建动态交互丰富的网页。下面我将详细讲解这些内容并提供示例。 🚀 JavaScript 第五节:引用类型、DOM/BOM 与异步编程 ⚡ 一、引用类型 引…

使用Pycharm进行远程ssh(以Featurize为例)

使用Pycharm进行远程ssh&#xff08;以Featurize为例&#xff09;文章目录介绍应用背景远程连接Python连接Jupyter介绍应用背景 在使用Pycharm 专业版的时候进行远程ssh连接服务器&#xff08;Featurize&#xff09;的Python解释器和Jupyter 远程连接Python 打开Pycharm点击…

深入研究:ClickHouse中arrayExists与hasAny在ORDER BY场景下的性能差异

最近公司大数据情况下ClickHouse查询性能极差&#xff0c;后来发现在大数据量ORDER BY场景下&#xff0c;arrayExists(x -> x in ...)比hasAny性能快10倍&#xff01;&#xff01;&#xff01;&#xff01; 一、问题重述与研究背景 在大数据量 ORDER BY场景下&#xff0c;…

Spring AI (二)结合Mysql做聊天信息存储

上文讲了&#xff0c;用Spring ai做简单的聊天功能&#xff0c;没看过的可以查看下 Spring AI结合豆包模型 这里简单结合下Jdbc做下聊天记录的存储和查询&#xff0c;让对话变的更智能。 首先是Pom的支持 <dependency><groupId>org.springframework.ai</grou…

【docker】data-root 数据迁移(防止无法加载镜像和容器问题)

操作系统&#xff1a;ubuntu 24.04 docker版本&#xff1a;docker-ce 28.1.1 目标&#xff1a;将/var/lib/docker 的数据迁移到/data/docker停止docker sudo systemctl stop docker.socket sudo systemctl stop docker这个步骤一定要做&#xff0c;否则容易导致数据不一致。 rs…

二、网页的“化妆师”:从零学习 CSS

一、CSS 是什么 1.1 CSS 的定义 CSS&#xff08;Cascading Style Sheets&#xff0c;层叠样式表&#xff09; 是一种用来给 HTML 页面 添加样式的语言。 简单来说&#xff1a; HTML 负责结构 —— 决定网页上有什么内容。 CSS 负责样式 —— 决定这些内容“长什么样”。 如果…

传统项目管理与敏捷的核心差异

在项目管理领域&#xff0c;传统方法与敏捷方法代表了两种不同的管理思维与实践路径。传统项目管理强调计划性、规范性和阶段性推进&#xff0c;而敏捷则注重灵活性、快速迭代和价值交付。 正如彼得德鲁克所说&#xff1a;“没有完美的计划&#xff0c;只有不断调整的行动。”理…