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

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

相关推荐
短剑重铸之日6 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼191929 分钟前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王37 分钟前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)1 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
码农小卡拉1 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
向上的车轮1 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net
Dragon Wu1 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
跳动的梦想家h1 小时前
环境配置 + AI 提效双管齐下
java·vue.js·spring
坚持就完事了1 小时前
Java中的集合
java·开发语言
wjhx1 小时前
QT中对蓝牙权限的申请,整理一下
java·数据库·qt