Redis 缓存雪崩、穿透、击穿面试题深度解析与 Spring Boot 实战代码示例

本文面向准备面试、或希望梳理缓存机制及防护方案的开发者,结合 Spring Boot 提供可直接落地的代码方案。


✅ 一、缓存雪崩

1.1 什么是缓存雪崩?

大量缓存同时过期,大量请求打到数据库,造成雪崩效应。

1.2 场景模拟

例如你设置所有缓存 TTL 为 30 分钟,恰好同时失效。

1.3 解决方案

✅ 方案1:过期时间加随机

java 复制代码
redisTemplate.opsForValue().set("key", value, 30 + new Random().nextInt(30), TimeUnit.MINUTES);

✅ 方案2:提前预热、定时刷新

使用定时任务刷新热点数据:

java 复制代码
@Scheduled(cron = "0 0/10 * * * ?")
public void preloadHotData() {
    List<Data> hotData = dbService.getHotData();
    hotData.forEach(data -> redisTemplate.opsForValue().set("hot:" + data.getId(), data, 1, TimeUnit.HOURS));
}

🚧 二、缓存穿透

2.1 什么是缓存穿透?

用户查询的数据缓存没有,数据库也没有,每次都打到数据库。攻击者可借此发起攻击。

2.2 防御方案

✅ 方案1:缓存空对象

java 复制代码
Object data = redisTemplate.opsForValue().get(key);
if (data == null) {
    data = dbService.queryById(id);
    redisTemplate.opsForValue().set(key, data == null ? "null" : data, 5, TimeUnit.MINUTES);
}

✅ 方案2:布隆过滤器

java 复制代码
BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), 50000);

@PostConstruct
public void init() {
    List<Integer> ids = dbService.getAllIds();
    ids.forEach(filter::put);
}

// 查询前判断是否存在
if (!filter.mightContain(id)) return null;

⚡ 三、缓存击穿

3.1 什么是缓存击穿?

某个热点数据刚好失效,大量并发请求直接打到数据库。

3.2 防御方案

✅ 方案1:本地锁(简单粗暴)

java 复制代码
synchronized (key.intern()) {
    data = redisTemplate.opsForValue().get(key);
    if (data == null) {
        data = dbService.query(id);
        redisTemplate.opsForValue().set(key, data, 10, TimeUnit.MINUTES);
    }
}

✅ 方案2:Redisson + 逻辑过期 + 异步更新

java 复制代码
@Data
public class CacheData<T> {
    private T data;
    private long expireTime; // 时间戳
}

public void setWithLogicExpire(String key, Object value, long time, TimeUnit unit) {
    CacheData<Object> cd = new CacheData<>();
    cd.setData(value);
    cd.setExpireTime(System.currentTimeMillis() + unit.toMillis(time));
    redisTemplate.opsForValue().set(key, cd);
}

// 异步刷新
if (System.currentTimeMillis() > cache.getExpireTime()) {
    if (lock.tryLock()) {
        executor.submit(() -> {
            Object newData = dbService.query(id);
            setWithLogicExpire(key, newData, 10, TimeUnit.MINUTES);
            lock.unlock();
        });
    }
}

🎯 四、面试问答锦集

  • 缓存雪崩、穿透、击穿的区别?
  • 如何判断线上是雪崩还是击穿?
  • Redisson 的异步刷新能解决哪些问题?
  • 缓存预热策略有哪些?

✅ 总结

场景 特征 防御策略
雪崩 大量缓存同时过期 过期时间加随机、定时预热
穿透 缓存 & DB 都没有 布隆过滤器、空对象缓存
击穿 某热点失效 本地锁、Redisson逻辑过期

🧠 推荐将缓存封装为统一服务类,便于复用和维护。

相关推荐
★YUI★5 分钟前
学习游戏制作记录(玩家掉落系统,删除物品功能和独特物品)8.17
java·学习·游戏·unity·c#
微小的xx7 分钟前
java + html 图片点击文字验证码
java·python·html
mask哥20 分钟前
详解flink java基础(一)
java·大数据·微服务·flink·实时计算·领域驱动
克拉克盖博38 分钟前
chapter03_Bean的实例化与策略模式
java·spring·策略模式
DashVector1 小时前
如何通过Java SDK分组检索Doc
java·数据库·面试
程序员清风1 小时前
跳表的原理和时间复杂度,为什么还需要字典结构配合?
java·后端·面试
渣哥1 小时前
Kafka消息丢失的3种场景,生产环境千万要注意
java
渣哥1 小时前
ElasticSearch深度分页的致命缺陷,千万数据查询秒变蜗牛
java
Olrookie1 小时前
XXL-JOB GLUE模式动态数据源实践:Spring AOP + MyBatis 解耦多库查询
java·数据库·spring boot
柯南二号2 小时前
【Java后端】MyBatis-Plus 原理解析
java·开发语言·mybatis