一文搞懂:Caffeine、Redis、MySQL 的区别与配合使用
📌 写在前面
初学的时候,我们的认知是线性的:先学 MySQL,知道它是最终数据归宿;然后学 Redis,知道它是高性能分布式缓存;再后来学 Caffeine,听说它是“本地缓存之王”,能扛超高并发。
但在实际项目中,我经常陷入一个困惑:既然 Redis 已经很快了,为什么还要加一层 Caffeine? 很多时候感觉 Caffeine 很多余——命中率不高、数据不一致、代码变复杂。直到我遇到一个 QPS 破万、热点数据极集中的场景,才发现 Caffeine 的价值:它能把 Redis 的网络开销和序列化开销都省掉,让响应时间从 5ms 降到 0.1ms 级别。
这篇笔记,我想把 MySQL、Redis、Caffeine 放在一起对比:它们各自解决什么问题?什么时候值得用 Caffeine?什么时候用 Redis 就够了?以及如何优雅地配合使用(多级缓存)。

1️⃣ 三种数据源的定位

形象比喻:
-
MySQL = 仓库,东西最全,但取货慢
-
Redis = 区域中转站,离多个工厂(服务实例)都近,但取货仍有交通时间
-
Caffeine = 工厂里的工具台,随手可取,但每个工厂自己有一套,可能不统一
2️⃣ 核心区别对比

3️⃣ 为什么感觉 Caffeine 很多余?
很多项目引入 Caffeine 后,发现收益不大,甚至带来麻烦。常见原因:
场景A:并发量不高(QPS < 1000)
-
Redis 单机能轻松抗住,延迟也在可接受范围(1~2ms)
-
加 Caffeine 后,代码复杂度增加,还要处理缓存一致性问题
-
结论:此时 Caffeine 确实多余。
场景B:热点数据分散,命中率低
-
Caffeine 是本地缓存,每个服务实例独立。如果热点数据随机分布,每个实例的缓存命中率很低(比如只有20%),大部分请求还是打到 Redis
-
结论:Caffeine 只适合“二八定律”极其明显的场景(20%的数据承担80%的请求)
场景C:数据更新频繁,一致性要求高
-
比如库存、余额。用 Caffeine 缓存后,一旦数据变更,需要通知所有实例失效缓存(例如用 Redis Pub/Sub 或消息队列),实现复杂且容易出错
-
结论:频繁更新的数据不要放 Caffeine
场景D:项目已经用了 Redis,且响应时间已满足业务需求
-
优化要适度。如果 Redis 已经够快,没必要为了“极致性能”引入 Caffeine
-
结论:过度优化是万恶之源
4️⃣ 什么时候该用 Caffeine?
Caffeine 不是银弹,但在以下场景能发挥巨大价值:

5️⃣ 多级缓存配合方案:Caffeine → Redis → MySQL
最经典的架构是多级缓存:请求优先走 Caffeine,未命中走 Redis,再未命中走 MySQL,并将结果逐层回填。
请求 → Caffeine (L1) → 未命中 → Redis (L2) → 未命中 → MySQL (L3)
↑ 回填 ↑ 回填 ↑ 回填
伪代码示例(使用 Spring Cache + 自定义实现):
public Object getProduct(Long id) {
// 1. 查 Caffeine
Object cached = caffeineCache.get(id);
if (cached != null) return cached;
// 2. 查 Redis
cached = redisTemplate.opsForValue().get(key);
if (cached != null) {
caffeineCache.put(id, cached);
return cached;
}
// 3. 查 MySQL
Object dbData = productMapper.selectById(id);
if (dbData != null) {
redisTemplate.opsForValue().set(key, dbData, 30, TimeUnit.MINUTES);
caffeineCache.put(id, dbData);
}
return dbData;
}
更优雅的方式:使用 Spring Cache 的 @Caching 或二级缓存框架(如 JetCache、Alibaba JetCache),声明式配置多级缓存。
6️⃣ 更好的实现方案:不手写,用框架
如果你觉得手写多级缓存又臭又长,可以考虑以下方案:
方案A:Spring Cache + 多 CacheManager
-
定义两个
CacheManager:caffeineCacheManager和redisCacheManager -
在
@Cacheable中指定cacheManager,或者用@Caching组合 -
缺点:无法自动联动(Caffeine 未命中后自动查 Redis),需要自己写逻辑
方案B:JetCache(阿里开源)
@Cached(name="product", expire = 3600, cacheType = CacheType.BOTH,
localLimit = 100, localExpire = 60)
public Product getProduct(long id) {
return productMapper.selectById(id);
}
-
CacheType.BOTH表示本地+远程两级缓存,自动处理未命中回填 -
支持自动刷新、异步加载、拦截器
方案C:Caffeine + Redis 手动封装
-
封装一个
MultiLevelCache类,内部逻辑统一 -
适合不想引入额外依赖的项目
个人推荐:新项目直接用 JetCache 或 Spring Cache + 自定义组合,不要重复造轮子。
7️⃣ 避坑指南

8️⃣ 总结:一张图看懂怎么选
QPS < 1000 且 数据一致性要求高 → 直连 MySQL + Redis(可选)
QPS 1000~1w 且 可接受 Redis 延迟 → Redis 单层缓存
QPS > 1w 且 热点数据高度集中 → Caffeine + Redis 多级缓存
数据极少变化且计算代价高 → Caffeine 本地缓存即可(无需 Redis)
数据更新频繁或需要跨实例实时同步 → 只用 Redis,不要用 Caffeine
一句话:Caffeine 是用来把 Redis 的延迟从毫秒级降到微秒级的“加速器”,只在超高并发+极热点的场景下有价值;普通项目用 Redis 足够,不要为了“技术栈完整”而引入复杂性。
📌 写在最后
回到最初的问题:为什么感觉 Caffeine 很多余?因为大多数项目的并发量和热点集中度还没到需要它的程度。Caffeine 不是银弹,它是一个极致场景的优化工具。就像你不会为了偶尔搬一次家而买一辆卡车一样,技术选型要匹配真实需求。
如果你正在做一个高并发项目,并且发现 Redis 的响应时间已经无法满足(比如超过5ms),或者 Redis 的网络开销成为瓶颈,不妨试试 Caffeine + Redis 的多级缓存方案。但请记住:多一级缓存,多一分复杂度,多一分一致性风险。
下一篇,我计划写一篇关于缓存一致性的终极方案,深入对比 Canal、双写、消息队列等方案,敬请期待
更多推荐



所有评论(0)