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

缓存穿透、击穿、雪崩的解决方案

一、缓存穿透(Cache Penetration)

定义:查询不存在的数据(如不存在的ID),绕过缓存直接穿透到数据库,导致数据库压力骤增。
解决方案

  1. 布隆过滤器(Bloom Filter)

    • 原理:通过位数组和哈希函数,快速判断数据是否可能存在。若布隆过滤器判定不存在,则直接拦截请求。
    • 实战示例:电商商品查询,拦截非法ID请求。
    • Java代码
      // 使用Guava实现布隆过滤器
      BloomFilter<Long> bloomFilter = BloomFilter.create(Funnels.longFunnel(), 1000000, 0.01);
      // 预热商品ID到布隆过滤器
      productIds.forEach(bloomFilter::put);public Product getProduct(Long id) {if (!bloomFilter.mightContain(id)) {return null; // 直接拦截非法ID}// 后续查询缓存和数据库...
      }
      
  2. 缓存空值

    • 原理:将查询结果为空的Key也缓存,避免重复穿透。
    • 代码示例
      public Product getProduct(String key) {Product product = redis.get(key);if (product == null) {// 查询数据库product = db.get(key);if (product == null) {redis.set(key, "NULL", 60); // 缓存空值,设置短过期时间} else {redis.set(key, product, 3600);}}return product;
      }
      
二、缓存击穿(Cache Breakdown)

定义:热点Key突然失效,大量并发请求直接击穿到数据库。
解决方案

  1. 互斥锁(Mutex Lock)

    • 原理:使用Redis的SETNX命令实现分布式锁,仅允许一个线程重建缓存。
    • 实战示例:秒杀活动中热门商品详情查询。
    • Java代码
      public Product getProduct(String key) {Product product = redis.get(key);if (product == null) {String lockKey = "LOCK:" + key;if (redis.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS)) {try {product = db.get(key); // 查询数据库redis.set(key, product, 3600);} finally {redis.delete(lockKey);}} else {Thread.sleep(100); // 等待锁释放后重试return getProduct(key);}}return product;
      }
      
  2. 逻辑过期(永不过期策略)

    • 原理:缓存不设置物理过期时间,后台异步更新数据。
    • 实战示例:新闻热点实时更新。
    • 代码示例
      public Product getProduct(String key) {Product product = redis.get(key);if (product.isExpired()) { // 检查逻辑过期时间// 异步线程更新缓存executor.submit(() -> {Product newProduct = db.get(key);redis.set(key, newProduct);});}return product;
      }
      
三、缓存雪崩(Cache Avalanche)

定义:大量Key同时失效,导致数据库瞬间压力过大。
解决方案

  1. 随机过期时间

    • 原理:为每个Key的TTL增加随机值,避免集中失效。
    • 实战示例:首页推荐商品列表缓存。
    • Java代码
      int baseTtl = 3600;
      int randomTtl = baseTtl + new Random().nextInt(600); // 增加0~10分钟随机值
      redis.opsForValue().set(key, value, randomTtl, TimeUnit.SECONDS);
      
  2. 多级缓存(本地缓存+Redis)

    • 原理:结合本地缓存(如Caffeine)和分布式缓存,降低雪崩风险。
    • 代码示例
      // 本地缓存
      Cache<Long, Product> localCache = Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();public Product getProduct(Long id) {Product product = localCache.get(id, k -> redis.get(k));if (product == null) {product = db.get(id);redis.set(id, product, 3600);localCache.put(id, product);}return product;
      }
      

总结对比

问题类型触发条件核心解决方案适用场景
穿透查询不存在的数据布隆过滤器+空值缓存防御恶意ID攻击
击穿热点Key失效互斥锁+逻辑过期秒杀、热点新闻
雪崩大量Key同时失效随机TTL+多级缓存大促活动首页数据

Tips

  • 布隆过滤器误判率:根据业务场景调整容量和哈希函数数量(Guava默认误判率0.01)[1]。
  • 热点Key预热:在大促前手动加载热点数据到缓存,如电商双11商品预热[2]。
http://www.xdnf.cn/news/10342.html

相关文章:

  • 开源版 PyMOL 如何绘制 Galidesivir 分子结构 ?
  • [LitCTF 2024]SAS - Serializing Authentication
  • 在Cesium中通过geojson和3d tiles分别加载楼宇白膜
  • 【深度学习】线性因子模型:数据降维与结构解析的数学透镜
  • 深入探讨redis:主从复制
  • 【鱼皮-用户中心】笔记
  • 优化的两极:凸优化与非凸优化的理论、应用与挑战
  • 雪花算法的实际应用
  • 6个月Python学习计划 Day 10 - 模块与标准库入门
  • 表单校验代码和树形结构值传递错误解决
  • 【Qt】Bug:findChildren找不到控件
  • 【C语言练习】074. 理解C语言中的多线程编程
  • MySQL 8.0:解析
  • Github 热点 Github 热点 Syncthing:多台设备,持续同步文件,安全同步,隐私无忧!
  • 79. 单词搜索-极致优化,可行性剪枝和顺序剪枝
  • LeetCode 1010. 总持续时间可被 60 整除的歌曲
  • leetcode hot100刷题日记——30.两数之和
  • 那些常用的运维工具
  • LeetCode 1524. 和为奇数的子数组数目
  • 【题解-洛谷】P9422 [蓝桥杯 2023 国 B] 合并数列
  • Flask-Login使用示例
  • R语言错误处理方法大全
  • Python 从入门到精通视频下载
  • Nacos实战——动态 IP 黑名单过滤
  • 【LLM】FastAPI入门教程
  • 无公网ip远程桌面连接不了怎么办?内网计算机让外网访问方法和问题分析
  • 2. 手写数字预测 gui版
  • VMvare 创建虚拟机 安装CentOS7,配置静态IP地址
  • Kubernetes架构与核心概念深度解析:Pod、Service与RBAC的奥秘
  • 算法训练第四天