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

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

相关推荐
快乐肚皮29 分钟前
fencing token机制
java·fencing token
叶落阁主38 分钟前
Neovim 插件 i18n.nvim 介绍
java·vue.js·vim
渣哥39 分钟前
让集合线程安全的几种靠谱方法
java
dylan_QAQ41 分钟前
Java转Go全过程06-工程管理
java·后端·go
a587691 小时前
消息队列(MQ)初级入门:详解RabbitMQ与Kafka
java·分布式·microsoft·面试·kafka·rabbitmq
千里码aicood2 小时前
【springboot+vue】党员党建活动管理平台(源码+文档+调试+基础修改+答疑)
java·数据库·spring boot
Chan162 小时前
【智能协同云图库】基于统一接口架构构建多维度分析功能、结合 ECharts 可视化与权限校验实现用户 / 管理员图库统计、通过 SQL 优化与流式处理提升数据
java·spring boot·后端·sql·spring·intellij-idea·echarts
先做个垃圾出来………2 小时前
差分数组(Difference Array)
java·数据结构·算法
BillKu2 小时前
Java核心概念详解:JVM、JRE、JDK、Java SE、Java EE (Jakarta EE)
java·jvm·jdk·java ee·jre·java se·jakarta ee
刘婉晴3 小时前
【Java】NIO 简单介绍
java·nio