Redis 缓存穿透、击穿、雪崩的 出现场景 与 解决方案

news/2025/3/10 22:17:55/
一、缓存穿透(Cache Penetration)
问题描述

请求 数据库中不存在的数据(如非法ID),导致请求绕过缓存直接击穿到数据库
典型场景

  • 恶意攻击:频繁请求 id=-1 或随机不存在的用户ID。

  • 业务逻辑缺陷:未校验参数合法性(如非数字ID查询)。

解决方案
  • 空值缓存

    将查询结果为 null 的请求也缓存,设置较短的过期时间(如 5分钟)。
public Object getData(String key) {Object value = redis.get(key);if (value != null) {return value;  // 命中缓存}// 查数据库value = db.query(key);if (value == null) {redis.setex(key, 300, "NULL");  // 缓存空值} else {redis.setex(key, 3600, value);  // 缓存真实值}return value;
}

布隆过滤器(Bloom Filter)

  • 缓存层前加布隆过滤器,判断请求的 key 是否可能存在:

    • 存在 → 查缓存数据库

    • 不存在 → 直接返回,避免查库。

接口层校验

  • 对请求参数进行合法性校验(如ID范围、格式)。
二、缓存击穿(Cache Breakdown)
问题描述

热点数据过期瞬间,大量并发请求直接涌入数据库
典型场景

  • 明星爆款商品详情页缓存过期。

  • 秒杀活动中核心商品信息缓存失效。

解决方案
  1. 互斥锁(分布式锁)

    • 只允许一个线程重建缓存,其他线程等待。

public Object getData(String key) {Object value = redis.get(key);if (value == null) {String lockKey = key + "_LOCK";if (redis.setnx(lockKey, "1", 10)) {  // 获取锁try {value = db.query(key);        // 查数据库redis.setex(key, 3600, value); } finally {redis.del(lockKey);           // 释放锁}} else {Thread.sleep(100);                // 等待后重试return getData(key);              // 递归调用}}return value;
}

逻辑过期时间(永不过期 + 异步更新)

  • 缓存不设置物理过期时间,但存储逻辑过期字段。

  • 后台线程定期检测并更新缓存

// 缓存数据结构
class CacheData {Object data;long expireTime;  // 逻辑过期时间
}public Object getData(String key) {CacheData cacheData = redis.get(key);if (cacheData == null) {return db.query(key);  // 首次加载}if (System.currentTimeMillis() > cacheData.expireTime) {// 提交异步任务更新缓存executor.submit(() -> {Object newData = db.query(key);redis.set(key, new CacheData(newData, System.currentTimeMillis() + 3600000));});}return cacheData.data;
}

热点数据永不过期

  • 对极热点数据不设置过期时间,通过异步线程定期更新。

三、缓存雪崩(Cache Avalanche)
问题描述

大量缓存同时过期 或 缓存服务宕机,导致请求全部涌入数据库
典型场景

  • 缓存服务器重启后所有数据丢失。

  • 批量缓存设置相同过期时间(如每日零点统一过期)。

解决方案
  • 随机过期时间

        在基础过期时间上增加随机值(如 基础时间 + 随机0~300秒)。

int baseExpire = 3600;
int randomExpire = baseExpire + new Random().nextInt(300);
redis.setex(key, randomExpire, value);
  • 集群高可用

    • 使用 Redis 集群(Cluster)或哨兵模式(Sentinel)避免单点故障。

  • 熔断降级

    • 数据库压力过大时,启用熔断机制(如返回默认值、限流)。

// 使用 Hystrix 实现熔断
@HystrixCommand(fallbackMethod = "fallbackGetData")
public Object getData(String key) {return redis.get(key);
}public Object fallbackGetData(String key) {return "系统繁忙,请稍后重试";  // 降级响应
}

对比总结

问题类型触发条件核心解决思路典型方案
穿透查询不存在的数据拦截非法请求、缓存空值布隆过滤器、空值缓存
击穿热点数据过期限制并发重建、异步更新互斥锁、逻辑过期时间
雪崩大量缓存同时失效或服务宕机分散过期时间、服务高可用随机过期、集群部署、熔断降级

实战建议

  1. 组合使用方案

    • 布隆过滤器 + 空值缓存 → 解决穿透。

    • 互斥锁 + 随机过期 → 解决击穿和雪崩。

  2. 监控与预警

  3. 压测验证

    • 模拟高并发场景,验证方案的可靠性。

通过合理设计缓存策略,可显著提升系统在高并发场景下的稳定性和性能。


http://www.ppmy.cn/news/1578188.html

相关文章

避免魔法值和多层if的关键:编程范式和设计模式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、案例分析二、技术手段函数式接口在枚举中 三、优化后完整代码总结 前言 提示:避免魔法值和多层if的关键:编程范式和设计模式&#…

爬虫案例十一js逆向数位观察网

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、网站分析二、代码总结 前言 提示:这里可以添加本文要记录的大概内容: 爬虫案例十一js逆向数位观察网 提示:以下是本篇…

【音视频】ffmpeg音视频处理基本流程

一、ffmpeg音视频处理基本流程 首先先看两条命令 ffmpeg -i 1.mp4 -acodec copy -vcodec libx264 -s 1280x720 2.flv ffmpeg -i 1.mp4 -acodec copy -vcodec libx265 -s 1280x720 3.mkv-i :表示输入源,这里是1.mp4,是当前路径下的视频文件-acodec copy…

springboot项目中一个类的构造方法什么时候调用

在 Spring Boot 中,如果一个类没有默认的无参构造方法,但定义了一个带参数的构造方法,Spring 会自动调用这个带参数的构造方法来完成依赖注入。这是 Spring 的构造器注入机制的一部分。 对于 public HelloworldController(ChatClient.Builde…

20250307确认荣品PRO-RK3566开发板在Android13下的以太网络共享功能

20250307确认荣品PRO-RK3566开发板在Android13下的以太网络共享功能 2025/3/7 13:56 缘起:我司地面站需要实现“太网络共享功能”功能。电脑PC要像连接WIFI热点一样连接在Android设备/平板电脑上来实现上网功能/数据传输。 Android设备/平板电脑通过4G/WIFI来上网。…

095:vue+cesium 使用Cesium3DTileset加载3D瓦片数据

作者: 还是大剑师兰特 ,曾为美国某知名大学计算机专业研究生,现为国内GIS领域高级前端工程师,CSDN知名博主,深耕openlayers、leaflet、mapbox、cesium,canvas,echarts等技术开发,欢迎加微信(gis-dajianshi),一起交流。 查看本专栏目录 - 本文是第 095篇文章 文章目录…

Windows 图形显示驱动开发-WDDM 3.2-用户模式工作提交(二)

用户模式工作提交 API 添加了以下用户模式 API,以支持用户模式工作提交。 D3DKMTCreateDoorbell 为 D3D HWQueue 创建一个Ring,用于用户模式工作提交。D3DKMTConnectDoorbell 将先前创建的Ring连接到 D3D HWQueue,用于用户模式工作提交。D3…

小米安全攻防工程师面试题解析

前言: 本文将分享一些小米安全攻防工程师面试中的经典题目和答案解析,帮助大家更好地准备面试。以下内容涵盖了SQL注入、PHP与Java的预编译区别、SSRF攻击、防御方法等。 1. SQL注入怎么预防,预编译为什么能防? SQL注入是攻击者…