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逻辑过期

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

相关推荐
两年半的个人练习生^_^13 小时前
JMM 进阶:彻底理解 synchronized 实现原理
java·开发语言
戳代码的新星13 小时前
论小白如何学会使用Maven
java·maven
wyhwust13 小时前
maven的安装和配置
java
plainGeekDev14 小时前
HttpURLConnection → OkHttp + Kotlin
android·java·kotlin
swordbob14 小时前
Spring Boot 2.0 改 CGLIB 后,接口实现是否有影响
java·开发语言·spring
AI人工智能+电脑小能手14 小时前
【大白话说Java面试题 第106题】【并发篇】第6题:synchronized 锁的锁对象可以是什么?
java·开发语言·面试
小当家.10514 小时前
AIGrader:一个 AI 作业批改平台的 Java EE 课设实战
java·人工智能·java-ee
devilnumber14 小时前
Lambda|行为参数化 完整精讲
java·lambda·行为参数化
garmin Chen14 小时前
Prompt工程入门:让AI按你的要求工作(3)--Prompt工程与提示词安全评测概述
java·人工智能·python·安全·prompt