Redis 和 Caffeine 的区别是什么?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...,查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 缓存体系认知:面试官想看的不只是你能不能区分这两个组件,更想看你脑子里的缓存体系立不立体,本地缓存、分布式缓存各解决什么问题,什么场景选谁。

  2. 架构视角:两者不是竞品,是不同层面的组件。能不能讲清楚 “进程内” 和 “独立中间件” 的架构差异,考的就是你的架构功底。

  3. 实战经验:加分项是多级缓存。如果你能主动聊到 “Caffeine + Redis 组合拳” 以及本地缓存的一致性难题,面试官眼睛会亮。

核心答案

先甩结论:Redis 是独立部署的分布式缓存中间件,Caffeine 是嵌入 JVM 进程的本地缓存库。一个是跨网络的公共服务,一个是揣在应用自己兜里的口袋。两者不是二选一的关系,生产上更多是搭档。

对比维度 Redis Caffeine
部署形态 独立进程,网络访问 嵌入应用 JVM,进程内调用
访问开销 毫秒级,有网络 RTT 纳秒级,方法调用直达
数据结构 String、Hash、List、Set、ZSet 等丰富类型 纯 key-value,类似 ConcurrentMap
容量上限 独立机器内存,可以很大 受 JVM 堆内存限制
多实例共享 天然共享,数据一致 各实例独立一份,有一致性问题
附加能力 持久化、主从、集群、发布订阅、Lua 淘汰算法、过期策略、命中率统计
典型场景 分布式系统共享缓存 单实例热点数据加速

记一句话:Redis 强在 “共享”,Caffeine 强在 “快”。

深度解析

一、架构形态的根本差异

Redis 与 Caffeine 架构区别
Redis 与 Caffeine 架构区别

上图是两者最本质的区别,分两层来看:

  • Redis 是独立进程:应用和 Redis 之间隔着网络,每次读写都是一次网络往返(单机 Redis 轻松 10 万 QPS,但网络 RTT 躲不掉)。好处是三个应用实例访问的是同一份数据,天然共享。
  • Caffeine 是一个 Jar 包:编译进你的应用,缓存就在自家 JVM 堆里,读写就是一次方法调用,连序列化都省了。代价是每个实例各存一份,谁也看不见谁。

本地缓存与共享缓存
本地缓存与共享缓存

二、性能差距不在一个量级

本地缓存读一次是纳秒到微秒级,Redis 再快也得算上网络往返,局域网内一次往返通常 0.5ms 起步。别小看这个差距,高并发热点场景下 QPS 一上来,网络 IO 的开销会被放大一千倍,直接成为瓶颈。

不过 Caffeine 快归快,有个硬伤:数据在 JVM 堆里,容量和 GC 都有压力。塞太多对象,Full GC 会教你做人。所以本地缓存一般只放少量极热点数据,容量上限一定得设。

三、淘汰算法:W-TinyLFU 是 Caffeine 的招牌

面试官听到你聊淘汰算法,就知道你真用过。

  • Redis 默认策略下靠过期删除(惰性 + 定期),内存满时触发淘汰,支持 8 种策略(noeviction、allkeys-lru、allkeys-lfu 等,LFU 是 4.0 引入的)。
  • Caffeine 用的是自研的 W-TinyLFU 算法。简单说,新数据先进一个小的 LRU 窗口,窗口满了往主区域挤的时候,TinyLFU 拿 Count-Min Sketch 统计的访问频率做门槛——新数据的频率高过被淘汰的候选者,才准进;频率统计还会周期性减半,让老热度慢慢褪去。这样既防得住偶发的批量扫描把热点全冲掉,又留得住长期热点,命中率比传统 LRU 高不少。

Caffeine 热点缓存淘汰
Caffeine 热点缓存淘汰

四、分布式环境下的经典难题:本地缓存一致性

Caffeine 单机用着爽,但服务一旦多实例部署,问题就来了:实例 A 更新了自己的本地缓存,实例 B 还揣着旧数据,用户两次请求打到不同实例,看到的数据来回跳。

常见解法:

  1. 消息广播失效:数据变更时通过 Redis 的发布订阅、或者 MQ 广播一条失效消息,各实例收到后清掉对应 key;
  2. 短过期时间兜底:本地缓存 TTL 设得很短(比如几秒),就算广播丢了,最多脏一小会儿;
  3. 只缓存几乎不变的数据:配置、字典类数据,变更频率低,问题自然小。

Caffeine 本地缓存一致性
Caffeine 本地缓存一致性

五、生产最佳实践:多级缓存

真实项目里这俩经常搭档出场,经典链路长这样:

多级缓存命中与回填流程
多级缓存命中与回填流程

流程说明:

  • L1 用 Caffeine 扛住最热的那部分流量,纳秒级响应,把绝大多数请求拦在本地;
  • L2 用 Redis 做共享缓存,未命中 DB 才放行;
  • 两层容量和 TTL 要拉开梯度:L1 容量小、TTL 短;L2 容量大、TTL 长。

Caffeine Redis 多级缓存
Caffeine Redis 多级缓存

Spring 侧落地很省事,spring-cache 两个都适配,@Cacheable 注解切个实现就行:

// 手动方式更直观,感受一下 Caffeine 的 API
Cache<String, User> cache = Caffeine.newBuilder()
        .maximumSize(10_000)          // 容量上限,防止撑爆堆
        .expireAfterWrite(5, TimeUnit.SECONDS)  // 短 TTL 兜底一致性
        .recordStats()                // 开启命中率统计
        .build();

User user = cache.get(userId, id -> queryFromRedis(id));  // 未命中自动加载

面试高频追问

  1. 本地缓存更新了,其他节点怎么感知? —— 上文第四节的广播失效 + 短 TTL 组合拳,这是标准答案。
  2. Caffeine 的 W-TinyLFU 比 LRU 好在哪? —— 防扫描污染:一次性批量访问不会把真正的热点挤出去。
  3. 什么数据适合放本地缓存? —— 读多写少、体量小、一致性要求不苛刻的热点数据(如首页配置、商品类目)。
  4. Guava Cache 和 Caffeine 什么关系? —— 同一作者,Caffeine 是 Guava Cache 的精神续作,性能和命中率全面胜出,新项目无脑选 Caffeine。

常见面试变体

  • “本地缓存和分布式缓存的区别?”(本质同题,换了个问法)
  • “为什么有了 Redis 还要本地缓存?”
  • “设计一个多级缓存架构,怎么保证缓存一致性?”

记忆口诀

Redis 共享跨网络,Caffeine 进程快如电;热点本地兜,共享 Redis 管,两级一组合,DB 压力减一半。

总结

一句话:Redis 是独立部署的分布式缓存,赢在共享和大容量;Caffeine 是 JVM 进程内本地缓存,赢在纳秒级速度和 W-TinyLFU 的高命中率。生产环境两者不是单选题,经典的 “Caffeine + Redis” 多级缓存才是标准答案,配上广播失效和短 TTL 解决一致性问题,这套组合讲出来,这道题就稳稳拿下了。