咱们直接进入正文。这篇东西不是纸上谈兵,是我在真实项目里把缓存击穿这个问题从“线上告警”干到“压测全绿”的完整记录。如果你正在用 Spring Boot 做高并发接口,或者你在面试里被问到缓存三大难题,这篇文章应该能给你一个清晰的、可以直接照着做的方案。
1. 缓存击穿到底是怎么回事
先说点实际的。缓存穿透、缓存击穿、缓存雪崩这三个词经常被混着说,但它们是三件完全不同的事。
- 缓存穿透:查了一个根本不存在的数据,缓存和数据库里都没有,每次请求都直接打数据库。
- 缓存击穿:某一个热点 key 在缓存过期的瞬间,突然涌进来大量请求,这些请求发现缓存里没数据,于是一起冲到数据库。
- 缓存雪崩:大量 key 在同一时间失效,导致海量请求直接打到数据库。
咱们今天只聊缓存击穿。它的危害在于“热点”两个字。一个平时每天被调用几万次的商品详情接口,缓存 key 正好在零点过期,而零点恰好有一波活动流量进来——那一刻数据库可能瞬间收到几十倍的请求洪峰。我经历过一次,数据库连接池直接被打满,服务大面积超时,那种感觉真的很酸爽。
为什么缓存击穿这么难搞?因为无锁方案在极端并发下基本不可靠。你写 “先查缓存、查不到就查库、回填缓存” 这种逻辑,在 100 个并发同时发现缓存为 null 的时候,这 100 个请求全部会执行查库操作。虽然最终结果一致,但数据库那一刻承受的压力是你 QPS 的上百倍。
所以要解决缓存击穿,核心思路就一条:当一个线程发现缓存失效了,让其他线程等待这个线程把缓存重建好,而不是一股脑冲进数据库。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么我选了 Redisson 而不是自己写锁
解决缓存击穿,业内常见方案大概有这么几类。
2.1 方案对比:本地锁、SETNX 锁、Redisson
| 方案 | 实现难度 | 适用场景 | 核心痛点 |
|---|---|---|---|
| synchronized / JVM Lock | 低 | 单机部署 | 集群下多个节点各锁各的,等于没锁 |
| Redis SETNX 手动锁 | 中 | 中小项目 | 需要自己处理锁超时、锁续期、锁删除时的原子性 |
| Redisson 分布式锁 | 低 | 分布式环境 | 几乎没有明显短板,社区活跃,功能全 |
本地锁这个方案得展开说一下。如果你公司系统只部署了一台实例,那用 synchronized 确实能解决缓存击穿问题,因为 JVM 级别的锁对单个进程内的所有线程是互斥的。但现在的系统,哪个不是多实例部署?哪怕你用了 Nginx 做负载均衡,同一个用户的请求可能被分发到不同的实例上。你在实例 A 加了锁,实例 B 的线程照样能冲破锁直接打数据库。这就是本地锁在分布式场景下的先天缺陷。
SETNX 手动锁的问题在于锁的释放和续期。最经典的一个坑是:线程 A 拿到锁去查数据库,结果数据库查询比较慢,超过了锁的过期时间,锁自动释放了。这时候线程 B 拿到锁也去查数据库。更坑的是,线程 A 查完了,直接执行删除锁的操作,把线程 B 的锁给删了。线程 C 紧接着又拿到锁……这种方式不是不能用,但你需要自己写一套完整的“锁续期 + 锁标识 + Lua 脚本原子化删除”逻辑,工作量不小,而且很容易写漏。
2.2 Redisson 解决了什么问题
Redisson 这个库做了一件很漂亮的事:把分布式锁的复杂度全部封装掉了。你只需要拿锁、干活、放锁,剩下的看门狗续期、原子化释放锁、可重入特性,框架全部帮你处理好。
比如看门狗机制,这是 Redisson 锁最有价值的部分。默认情况下,锁的超时时间是 30 秒,但如果你的业务执行超过了 30 秒,看门狗会自动帮锁续期,每过 1/3 时间(也就是 10 秒)就续一次,直到业务执行完释放锁为止。这样就不会出现“锁提前过期,第二个线程趁虚而入”的尴尬局面。
当然,前提是你使用锁的时候没有自定义 leaseTime。如果你手动指定了锁的持有时间,看门狗就不会生效了,相当于你把控制权拿回来了,那续期的责任就得自己扛。
3. Spring Boot 集成 Redisson 的完整配置
这部分讲配置。我假设你已经有一个正常的 Spring Boot 项目了,版本在 2.x 或 3.x 都可以,核心逻辑没差别。
3.1 引入 Maven 依赖
用 redisson-spring-boot-starter 是最省事的方案,它自动帮你完成了自动配置:
xml复制
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.27.2</version>
</dependency>
注意版本号和 Spring Boot 版本的兼容性。Spring Boot 3.x 对应 JDK 17+,Redisson 3.27 完全支持。如果你在 Spring Boot 2.x 环境,建议用 3.20 或更早的稳定版本,大概率不会出兼容性问题。
3.2 配置 Redis 连接信息
在 application.yml 里加配置。单机环境:
yaml复制spring:
data:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
timeout: 3000ms
lettuce:
pool:
