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

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

一、缓存穿透(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 "系统繁忙,请稍后重试";  // 降级响应
}
  • 多级缓存

    • 本地缓存(如 Caffeine) + Redis 缓存,降低 Redis 压力。

对比总结

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

实战建议

  1. 组合使用方案

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

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

  2. 监控与预警

    • 监控缓存命中率、数据库 QPS,及时发现问题。

  3. 压测验证

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

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


http://www.kler.cn/a/579553.html

相关文章:

  • 数据库基础以及基本建库建表的简单操作
  • Linux下安装elasticsearch(Elasticsearch 7.17.23)
  • 基于Python的电商销售数据分析与可视化系统实
  • 开发环境搭建-06.后端环境搭建-前后端联调-Nginx反向代理和负载均衡概念
  • 升级到Android Studio 2024.2.2 版本遇到的坑
  • Linux安装升级docker
  • Mybatis操作数据库----小白基础入门
  • 【开源免费】基于SpringBoot+Vue.JS青年公寓服务平台(JAVA毕业设计)
  • [项目]基于FreeRTOS的STM32四轴飞行器: 五.Motor驱动
  • 关于Springboot 应配置外移和Maven个性化打包一些做法
  • 使用 QML 和 QtSql 实现 SQLite 数据库操作
  • NebulaGraph学习笔记-SessionPool之getSession
  • 【数据结构与算法】Java描述:第二节:LinkedList 链表
  • 【YOLOv12改进trick】三重注意力TripletAttention引入YOLOv12中,实现遮挡目标检测涨点,含创新点Python代码,方便发论文
  • OSPF报文分析
  • MySQL环境搭建和基本操作
  • 【大模型】WPS 接入 DeepSeek-R1详解,打造全能AI办公助手
  • vivado 充分利用 IP 核
  • 实时数据驱动的RAG应用
  • Python如何制作并查询sql数据库