主题
概念卡片:缓存技术选型与多级缓存
一句话机制:缓存分本地缓存(进程内,无网络开销、受 JVM 内存限制)和分布式缓存(跨进程,支持大数据量、有网络损耗);工程上通常「本地 Caffeine + 分布式 Redis」构成多级缓存,本地缓存扛热点、分布式缓存扛容量,通过一致性和过期策略协同。
本地缓存四大方案
| 方案 | 特点 | 淘汰算法 | 结论 |
|---|---|---|---|
| HashMap 自实现 | 简单,需自己处理并发/容量 | LRU(LinkedHashMap) | 简单场景用 |
| Guava Cache | 功能丰富、线程安全 | LRU | 可用,但已被 Caffeine 替代 |
| Caffeine | 性能接近最优(SpringBoot2 默认) | W-TinyLFU(LRU+LFU 结合) | 推荐 |
| Ehcache | 功能最强(堆内/堆外/磁盘 + 集群) | LRU/LFU/FIFO | 需持久化/集群时用 |
关键代码示例(Caffeine)
java
Cache<String, String> cache = Caffeine.newBuilder()
.maximumSize(10) // 最大容量
.expireAfterWrite(17, TimeUnit.SECONDS) // 写后过期
.build();
String v = cache.get(key, this::getValueFromDB); // 未命中回调加载本地 vs 分布式缓存
| 维度 | 本地缓存 | 分布式缓存 |
|---|---|---|
| 进程 | 与应用同进程 | 独立进程,跨网络通信 |
| 性能 | 无网络开销,极快 | 有网络损耗 |
| 容量 | 受 JVM 内存限制 | 可扩展大数据量 |
| 一致性 | 各实例各自缓存,难一致 | 集中存储,天然一致 |
| 代表 | Caffeine/Guava/Ehcache | Redis/Memcached |
多级缓存的一致性
多级缓存(L1 本地 + L2 Redis + DB)的一致性是难点,常见策略:
- 主动失效:写 DB 后删除/更新缓存,靠短过期兜底
- 过期时间错峰:本地缓存短 TTL、分布式缓存长 TTL,减小不一致窗口
- 消息通知:数据变更发 MQ,各实例失效本地缓存
不变量(必须成立的约束)
- 本地缓存不放大数据(受 JVM 内存限制),分布式缓存才承担容量。
- 多级缓存一致性靠「短 TTL + 主动失效」,不要追求强一致。
- 选型默认 Caffeine(性能最优,SpringBoot2 已内置),除非要持久化/集群才考虑 Ehcache。
踩坑案例
- 现象:本地缓存 + Redis 多级缓存,数据更新后本地缓存迟迟不失效,读到旧数据。 原因:本地缓存只靠 TTL 过期,没主动失效。解决:写操作后通过 MQ/事件通知各实例失效本地缓存,或本地缓存设极短 TTL。
常见误解
- 以为缓存就是 Redis → 还有进程内本地缓存(Caffeine),扛热点更快,两者常组合成多级缓存。
- 以为 Caffeine 和 Guava 差不多 → Caffeine 用 W-TinyLFU 算法,性能明显优于 Guava 的 LRU。
关联
- Redis 缓存细节(穿透/击穿/雪崩/一致性):概念卡片:Redis缓存异常三件套-穿透击穿雪崩
- 源:
B40-资源/语雀-Code-Summary/Middleware/Cache&HighAvailability/CacheTheory(3 篇)+ Caffeine/Guava 目录