Redis缓存穿透、缓存击穿与缓存雪崩实战指南

 更新时间:2026年05月07日 09:26:17   作者:河阿里  
本文介绍Redis在高并发分布式系统中的应用及可能引发的问题,包括缓存穿透、缓存击穿和缓存雪崩,针对这些问题,提出了布隆过滤器、分布式锁、随机过期时间、高可用集群、本地缓存和预热策略等多种解决方案,通过合理配置和组合使用这些方案,可以有效提升系统的稳定性和性能

在现代高并发的分布式系统架构中,Redis凭借其高性能的内存读写能力,已成为企业级应用不可或缺的缓存中间件。然而,缓存的引入虽然极大地提升了系统响应速度,降低了数据库负载,但也带来了一系列复杂的边缘风险。

一、缓存穿透(Cache Penetration)

1. 定义与问题
缓存穿透是指查询一个数据库根本不存在的数据。由于缓存中无对应key,请求直接穿透缓存层访问数据库。若大量此类请求存在(如恶意攻击或业务误操作),数据库将承受巨大压力,甚至崩溃。

2. 核心原因

  • 业务逻辑错误:前端未校验请求参数,导致无效key直达数据库。
  • 恶意攻击:黑客故意构造大量不存在的key进行请求。

3. 解决方案
(1)缓存空值

  • 思路:若数据库查询为空,仍将key存入缓存,值为null或特殊标记,并设置较短过期时间(如1分钟)。
  • 优点:简单高效,后续相同请求可直接命中缓存。
  • 缺点:需维护额外空值数据,可能占用空间。
  • 代码示例
public Object getData(String key) {
    Object value = redis.get(key);
    if (value == null) { // 缓存未命中
        value = db.queryData(key); // 查询数据库
        if (value == null) { // 数据不存在
            redis.set(key, "NULL", 60); // 缓存空值,过期时间1分钟
        } else {
            redis.set(key, value, 3600); // 缓存有效数据,过期时间1小时
        }
    }
    return value;
}

(2)布隆过滤器(Bloom Filter)[推荐]

  • 思路:使用高效概率型数据结构过滤不存在的请求。布隆过滤器通过多个哈希函数将key映射到位数组,若所有位均为1,则可能存在于数据库;若存在0,则一定不存在。
  • 优点:空间占用极低,过滤效率高。
  • 缺点:存在误判(可能将不存在的key误判为存在),不支持删除操作。
  • 代码示例(Guava布隆过滤器)
BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(), 1000000, 0.01); // 容量100万,误判率1%
// 初始化:将数据库所有key预加载到布隆过滤器
filter.putAll(db.getAllKeys());
public Object getData(String key) {
    if (!filter.mightContain(key)) { // 布隆过滤器判断不存在
        return null; // 直接返回,不访问数据库
    }
    Object value = redis.get(key);
    if (value == null) {
        value = db.queryData(key);
        redis.set(key, value, 3600);
    }
    return value;
}

二、缓存击穿(Cache Breakdown)

1. 定义与问题
缓存击穿又称热点Key问题,指一个访问极其频繁的热点key突然失效,大量并发请求同时穿透缓存,直接冲击数据库。例如,电商平台秒杀商品的缓存过期瞬间,大量用户抢购导致数据库崩溃。

2. 核心原因

  • 热点数据缓存过期时间设置不合理,或手动删除缓存。
  • 高并发请求集中在同一时间点。

3. 解决方案
(1)互斥锁(分布式锁)[推荐]

  • 思路:缓存失效时,仅允许第一个请求获取锁,查询数据库并重建缓存,其余请求等待或返回旧数据。
  • 优点:保证数据一致性,避免并发重建。
  • 缺点:锁竞争可能增加延迟,需防止死锁。
  • 代码示例(Redis分布式锁)
public Object getData(String key) {
    Object value = redis.get(key);
    if (value == null) { // 缓存未命中
        if (redis.setNX(key + "_lock", "1", 10)) { // 获取锁,过期时间10秒
            try {
                value = db.queryData(key); // 查询数据库
                redis.set(key, value, 3600); // 重建缓存
            } finally {
                redis.del(key + "_lock"); // 释放锁
            }
        } else { // 未获取锁,等待重试
            Thread.sleep(50);
            return getData(key); // 递归调用
        }
    }
    return value;
}

(2)逻辑过期(不设置物理过期)

  • 思路:缓存数据中增加逻辑过期时间字段,后台线程异步更新缓存,请求仍返回旧数据。
  • 优点:无锁竞争,保证高可用。
  • 缺点:数据短暂不一致,需接受旧数据。
  • 代码示例
public class CacheData {
    private Object data;
    private long expireTime; // 逻辑过期时间戳
}
public Object getData(String key) {
    CacheData data = redis.get(key);
    if (data == null) {
        data = db.queryData(key);
        redis.set(key, data, 3600);
    }
    if (data.expireTime < System.currentTimeMillis()) { // 逻辑过期
        Thread asyncThread = new Thread(() -> {
            // 异步更新缓存
            CacheData newData = db.queryData(key);
            redis.set(key, newData, 3600);
        });
        asyncThread.start();
    }
    return data.data;
}

三、缓存雪崩(Cache Avalanche)

1. 定义与问题
缓存雪崩指大量缓存key同时过期或Redis服务宕机,导致所有请求穿透缓存,直接压垮数据库,引发系统瘫痪。例如,电商平台商品缓存统一过期,凌晨用户访问高峰导致MySQL崩溃。

2. 核心原因

  • 缓存过期时间设置集中(如批量数据同一时间过期)。
  • Redis单点故障或集群不可用。
  • 系统启动时未预热缓存。

3. 解决方案(分层防御)
(1)过期时间错开

  • 思路:为每个key增加随机过期时间(如基础过期时间 + 随机值),分散失效时间点。
  • 代码示例
redis.set(key, value, 3600 + new Random().nextInt(300)); // 基础1小时 + 0-5分钟随机

(2)Redis高可用集群

  • 部署哨兵(Sentinel)或集群模式:主从自动切换,避免单点故障。
  • 配置限流/熔断:如使用Hystrix或Sentinel,当Redis请求超限时自动降级。

(3)本地缓存兜底

  • 思路:使用Caffeine或Guava Cache作为本地二级缓存,Redis宕机时可返回本地数据。
  • 代码示例(Caffeine)
LoadingCache<String, Object> localCache = Caffeine.newBuilder()
    .expireAfterWrite(30, TimeUnit.MINUTES) // 本地缓存过期30分钟
    .build(key -> redis.get(key));
public Object getData(String key) {
    Object value = localCache.get(key);
    if (value == null) {
        value = redis.get(key);
        localCache.put(key, value);
    }
    return value;
}

(4)缓存预热

  • 系统启动时加载热点数据:通过定时任务或启动脚本,提前将高频访问数据加载到Redis。
  • 代码示例(伪代码)
public void warmUpCache() {
    List<String> hotKeys = db.getTopNKeys(); // 获取Top N热点key
    for (String key : hotKeys) {
        redis.set(key, db.queryData(key), 3600);
    }
}

四、总结

  1. 缓存穿透:使用布隆过滤器前置拦截无效请求,或缓存空值兜底。
  2. 缓存击穿分布式锁控制并发重建,或逻辑过期异步更新。
  3. 缓存雪崩分层防御策略,过期时间随机化 + 高可用集群 + 本地缓存兜底 + 缓存预热。
  4. 监控与预警:实时监控Redis命中率、数据库QPS等指标,异常时自动报警或熔断。

通过以上方案组合使用,可大幅提升系统稳定性,避免因缓存问题导致的服务崩溃。架构设计时需根据实际业务场景权衡性能与一致性,选择最适合的解决方案。

到此这篇关于Redis:缓存穿透、缓存击穿与缓存雪崩的文章就介绍到这了,更多相关Redis缓存穿透、缓存击穿与缓存雪崩内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis实现订单自动过期功能的示例代码

    Redis实现订单自动过期功能的示例代码

    这篇文章主要介绍了Redis实现订单自动过期功能的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 浅谈redis采用不同内存分配器tcmalloc和jemalloc

    浅谈redis采用不同内存分配器tcmalloc和jemalloc

    下面小编就为大家带来一篇浅谈redis采用不同内存分配器tcmalloc和jemalloc。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • 解读Redis的持久化方式(RDB、AOF)

    解读Redis的持久化方式(RDB、AOF)

    文章主要介绍了Redis的RDB和AOF两种持久化机制的区别、工作原理和优点,并详细讲解了Redis 4.0+版本中RDB+AOF混合持久化的实现方式、配置建议和实际应用,强调了混合持久化在生产环境中的重要性和配置要点,以及在不同场景下的推荐配置策略
    2026-04-04
  • Redis持久化使用及说明(RDB&AOF)

    Redis持久化使用及说明(RDB&AOF)

    Redis通过RDB(定期快照)和AOF(日志记录)实现持久化,兼顾内存性能与数据安全,RDB文件紧凑,适合冷备;AOF实时性强,但体积较大,两者结合使用(混合持久化)可平衡效率与可靠性,确保数据在异常重启时恢复
    2025-08-08
  • 如何使用Redis保存用户会话Session详解

    如何使用Redis保存用户会话Session详解

    这篇文章主要给大家介绍了关于如何使用Redis保存用户会话Session的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Redis内存回收用法及说明

    Redis内存回收用法及说明

    Redis通过配置文件设置最大内存空间,当达到上限时,会使用过期策略和淘汰策略来管理内存,过期策略包括惰性删除和周期删除,而淘汰策略则根据内存使用情况主动删除部分key以释放空间
    2025-12-12
  • Redis消息队列实现秒杀教程

    Redis消息队列实现秒杀教程

    这篇文章主要介绍了Redis消息队列实现秒杀教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • Redis使用ZSET实现消息队列的项目实践

    Redis使用ZSET实现消息队列的项目实践

    本文主要介绍了Redis使用ZSET实现消息队列的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 基于Redis实现抢红包和发红包功能

    基于Redis实现抢红包和发红包功能

    抢红包是我们生活常用的社交功能, 这个功能最主要的特点就是用户的并发请求高, 在系统设计上, 可以使用非常多的办法来扛住用户的高并发请求, 在本文中简要介绍使用Redis缓存中间件来实现抢红包算法,需要的朋友可以参考下
    2024-04-04
  • 浅谈Redis中的内存淘汰策略和过期键删除策略

    浅谈Redis中的内存淘汰策略和过期键删除策略

    本文主要介绍了浅谈Redis中的内存淘汰策略和过期键删除策略,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论