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

ops/2025/3/6 17:02:47/
一、缓存穿透(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/ops/163648.html

相关文章

网络安全防护指南:筑牢网络安全防线(510)

一、网络安全的基本概念 (一)网络的定义 网络是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息收集、存储、传输、交换、处理的系统。在当今数字化时代,网络已经成为人们生活和工作中不可或缺的一部分。它连接了世…

ADB 和 Monkey 进行 Android 应用的测试和调试

ADB(Android Debug Bridge)和 Monkey 是 Android 开发和测试中常用的工具。ADB 用于与 Android 设备通信,而 Monkey 是一个压力测试工具,可以模拟用户随机操作。以下是它们的高级用法,帮助您更高效地进行 Android 应用测试和调试。 一、ADB 的高级用法 1. 设备管理 查看连…

每日十个计算机专有名词 (7)

Metasploit 词源:Meta(超越,超出) exploit(漏洞利用) Metasploit 是一个安全测试框架,用来帮助安全专家(也叫渗透测试人员)发现和利用计算机系统中的漏洞。你可以把它想…

【SpringBoot】一文讲懂什么是scanBasePackages

文章目录 一、作用流程说明 二、使用场景三、配置方式四、默认行为五、注意事项六、示例1. 单模块项目2. 多模块项目 七、与ComponentScan的关系八、总结 scanBasePackages是SpringBoot中用于指定主件扫描(Component Scanning)的包路径的配置属性。它通常用于Spring…

ubuntu20.04 安装离线版docker-20.10.0

1. 安装步骤 步骤一:官网下载 docker 安装包 wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.0.tgz步骤二:解压安装包; tar -zxvf docker-20.10.0.tgz 步骤三:将解压之后的docker文件移到 /usr/bin目录下; c…

微信小程序接入DeepSeek模型(火山方舟),并在视图中流式输出

引言: DeepSeek,作为一款先进的自然语言处理模型,以其强大的文本理解和生成能力著称。它能够处理复杂的文本信息,进行深度推理,并快速给出准确的回应。DeepSeek模型支持流式处理,这意味着它可以边计算边输…

Github 2025-03-05 C开源项目日报 Top10

根据Github Trendings的统计,今日(2025-03-05统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C++项目1Python项目1Tcl项目1Redis - 内存数据库和数据结构服务器 创建周期:5411 天开发语言:C协议类型:BSD 3-Clause “New” or “…

std::sort 排序算法本质

使用了内省排序(Introsort) 现代标准库实现中,std::sort 通常使用 内省排序(Introsort),它是一种混合排序算法,结合了以下三种算法的优点: 快速排序 作为主要算法,平均…