一、Caffeine 核心定位与简介
1.1 什么是 Caffeine
Caffeine 是一款基于 Java 8 开发的高性能本地缓存框架,是目前 Java 生态中性能最优的本地缓存实现,由 Guava Cache 原核心作者参与研发,属于 Guava Cache 的升级迭代版本。
Caffeine 吸收了 Guava Cache 的核心设计思想,结合 Java 8 的 Lambda 表达式、CompletableFuture 异步特性做了深度优化,同时采用了当前业界最优的缓存淘汰算法,是 Java 项目中本地缓存的首选方案。
1.2 Caffeine 核心核心优势
- 极致的读写性能:Caffeine 的性能指标在所有 Java 本地缓存框架中处于顶尖水平,读操作性能接近原生 ConcurrentHashMap,写操作性能远超同类框架。
- 超高的缓存命中率:采用自研的最优淘汰算法,缓存命中率是其核心竞争力,远高于 Guava Cache、Ehcache 等框架。
- 轻量级无依赖:Caffeine 核心包体积小巧,无任何第三方依赖,引入项目无额外侵入性,兼容所有 Java 8 及以上版本的项目。
- 丰富的功能特性:支持多种缓存加载模式、过期策略、异步操作、缓存统计等,功能完备且配置灵活。
- 规范兼容:完美兼容 JSR-107 缓存规范,可无缝对接规范相关的缓存操作 API,适配标准化缓存开发。
- 内存友好:提供基于 Java 引用的内存回收策略,可根据 JVM 内存情况自动释放缓存,有效避免内存溢出问题。
二、Caffeine 核心底层原理
2.1 核心缓存淘汰算法:W-TinyLFU
Caffeine 能实现超高缓存命中率的核心原因,是内置了 W-TinyLFU(Window-TinyLFU) 缓存淘汰算法,该算法是当前业界公认的最优本地缓存淘汰算法,也是 Caffeine 的核心灵魂。
W-TinyLFU 算法是一种复合型的缓存淘汰策略,融合了多种经典算法的优势,同时解决了传统算法的核心痛点:
- 核心设计思想:结合 LFU(最少频率使用)的高频访问优先特性 + LRU(最近最少使用)的近期访问优先特性,兼顾缓存的「访问频率」与「访问时效性」。
- 解决 LRU 算法痛点:LRU 仅关注最近访问时间,会出现「缓存污染」问题,即偶发的低频大流量请求会把高频热点数据挤出缓存,导致命中率骤降。
- 解决 LFU 算法痛点:LFU 仅关注访问频率,会出现「冷启动」问题,即新的热点数据因初始访问频率低,无法被缓存;同时会出现「数据僵化」问题,即历史高频数据长期占用缓存,即使后续不再访问也不会被淘汰。
- W-TinyLFU 的核心优化:通过窗口缓存的设计,对新数据做访问频率的预热统计,再结合频率过滤机制,既保证高频数据的留存,又能快速纳入新的热点数据,同时剔除低频无效数据。
2.2 Caffeine 核心执行机制
Caffeine 的底层存储基于分段式的并发哈希表实现,与 ConcurrentHashMap 的分段锁设计思路一致,支持高并发的读写操作,读写操作的并发控制无锁化设计,大幅降低线程竞争带来的性能损耗。
缓存的过期检查与数据驱逐采用惰性删除 + 定时主动清理的组合机制,惰性删除指访问缓存时校验数据是否过期,定时清理指后台线程周期性清理过期数据,兼顾性能与内存占用。
缓存加载与刷新的核心逻辑基于 Java 8 的函数式编程实现,支持同步 / 异步两种执行模式,异步操作依托 CompletableFuture 实现,充分利用多核 CPU 的处理能力,无阻塞提升并发效率。
三、Caffeine 核心缓存策略
3.1 缓存数据淘汰策略
Caffeine 的缓存淘汰分为两大核心类型,两类策略相互配合,共同保证缓存的高效运行与内存安全,所有淘汰逻辑均由框架自动执行,无需手动干预:
- 被动淘汰:当缓存的容量达到预设的最大值时,触发基于 W-TinyLFU 算法的缓存驱逐,自动剔除「价值最低」的缓存数据,优先保留高频、近期访问的热点数据,这是 Caffeine 最核心的淘汰策略。
- 主动淘汰:当缓存数据满足预设的过期规则时,自动将过期数据从缓存中移除,主动淘汰的触发时机包含惰性检查、定时清理两种,保障缓存数据的有效性。
3.2 三大核心过期策略
Caffeine 提供三种维度的过期策略,所有策略可单独配置,也可组合配置,覆盖所有业务场景的缓存时效需求,三种策略均为全量支持,无功能阉割:
3.2.1 基于大小的过期(容量驱逐)
这是最基础的过期策略,核心是设置缓存的最大容量上限,当缓存中的键值对数量达到该上限时,立即触发 W-TinyLFU 算法的淘汰逻辑。
可配置缓存的最大条目数,也可基于自定义权重配置缓存容量,适合对内存占用有明确限制的场景,是防止内存溢出的核心配置项。
3.2.2 基于时间的过期(时效驱逐)
该策略是业务开发中最常用的策略,核心是为缓存数据设置有效期,过期后的数据会被自动清理,分为两种细分规则,均为 Caffeine 的核心功能:
- 访问后过期(TTL,Time To Live) :指缓存数据从最后一次被访问开始计时,超过指定时间未被访问则过期。适用于热点数据时效性强的场景,比如用户会话信息、高频查询的业务数据。
- 写入后过期(TTI,Time To Idle) :指缓存数据从第一次被写入开始计时,超过指定时间无论是否被访问,都会过期。适用于数据更新频率固定、有明确有效期的场景,比如配置信息、静态资源数据。
3.2.3 基于引用的过期(内存感知驱逐)
该策略是 Caffeine 的高级特性,核心是基于 Java 的对象引用类型实现缓存的内存级回收,完全对接 JVM 的垃圾回收机制,是内存敏感型业务的最优选择,分为两种核心配置:
- 软引用策略:缓存的键值对采用软引用存储,当 JVM 发生内存不足时,会优先回收软引用对象,释放缓存占用的内存,直到内存充足为止,该策略可保证 JVM 不会因缓存导致内存溢出。
- 弱引用策略:缓存的键值对采用弱引用存储,当缓存数据的键对象被 JVM 标记为无引用时,该缓存条目会被立即回收,适用于需要严格跟随对象生命周期的缓存场景。
该策略的核心优势:无需手动配置容量和过期时间,缓存的生命周期完全由 JVM 内存状态和对象引用关系决定,极致适配内存敏感的业务场景。
四、Caffeine 核心缓存工作模式
Caffeine 提供四种核心的缓存工作模式,四种模式覆盖从简单到复杂、从同步到异步的所有业务场景,模式之间可灵活切换,配置简洁,每种模式都有明确的适用场景与核心特性,是 Caffeine 灵活性的核心体现:
4.1 手动加载模式
- 核心特性:缓存的存入、获取、删除均由开发人员手动调用 API 完成,缓存缺失时,框架不会自动处理,需要业务代码自行实现数据加载与缓存写入逻辑。
- 核心特点:开发灵活度最高,完全掌控缓存的全生命周期,无任何自动逻辑侵入,适合简单的缓存业务场景。
- 适用场景:少量固定数据的缓存、缓存数据需要精准控制更新时机的场景、业务逻辑简单的本地缓存需求。
4.2 自动加载模式
- 核心特性 :开发人员仅需配置缓存数据的加载逻辑,无需手动写入缓存;当获取缓存时,如果缓存缺失,框架会自动触发加载逻辑,将数据加载并写入缓存后,再返回结果。
- 核心特点:极大简化开发代码,避免缓存操作与业务逻辑的耦合,同时能有效避免缓存穿透的基础风险,加载逻辑全局统一,缓存的写入完全由框架托管。
- 适用场景:绝大多数的查询类业务场景、缓存缺失后有固定加载规则的场景、需要统一管理缓存加载逻辑的业务,是 Caffeine 最常用的工作模式。
4.3 异步手动加载模式
- 核心特性:基于 Java 8 的 CompletableFuture 实现异步化的缓存操作,所有的缓存存入、获取、删除操作均为异步非阻塞执行,不会阻塞主线程的业务处理。
- 核心特点:充分利用多核 CPU 的处理能力,大幅提升高并发场景下的系统响应效率,异步操作的结果可通过 CompletableFuture 的链式调用处理,适配 Java 的异步编程模型。
- 适用场景:高并发的业务场景、对接口响应时间要求严苛的场景、需要异步处理数据加载的业务,是性能优化的重要模式。
4.4 异步自动加载模式
- 核心特性 :融合自动加载模式与异步加载模式的核心优势,是 Caffeine 的终极高性能模式;缓存缺失时,框架会异步触发加载逻辑,主线程无需等待加载完成,可继续处理其他业务,加载完成后自动将数据写入缓存。
- 核心特点:兼具自动加载的开发简洁性与异步操作的高性能,无任何主线程阻塞,缓存的加载与业务处理完全解耦,是高并发场景下的最优选择。
- 适用场景:高并发 + 高频查询的核心业务场景、对系统吞吐量和响应时间有极致要求的场景、微服务核心接口的本地缓存优化,是 Caffeine 性能天花板的体现。
五、Caffeine 核心功能特性
Caffeine 作为功能完备的高性能缓存框架,除核心的缓存策略与工作模式外,还提供了大量实用的高级功能特性,所有特性均为开箱即用,无需额外开发,特性覆盖缓存的全生命周期管理,满足各类复杂业务需求,核心特性如下:
5.1 高性能并发控制
底层采用无锁化的并发设计,读写操作的性能接近原生的 ConcurrentHashMap,支持数万级别的并发读写请求,线程安全无锁竞争损耗,是高并发场景的最优选择。
支持自定义并发级别,可根据业务的并发量灵活配置,适配不同的系统负载情况,兼顾并发性能与内存占用。
5.2 缓存刷新机制
提供独立的缓存刷新功能,与缓存过期是完全不同的概念:缓存刷新是在缓存数据未过期时,异步更新缓存数据;缓存过期是数据失效后重新加载。
核心优势:刷新操作是异步执行的,不会阻塞缓存的读请求,读请求在刷新期间会返回旧的缓存数据,保证接口的响应效率,同时能保证缓存数据的最终一致性。
适用场景:热点数据需要定期更新、但又不希望过期后重新加载导致响应延迟的场景,是平衡性能与数据新鲜度的核心特性。
5.3 缓存淘汰监听器
支持配置缓存淘汰的监听器,当缓存数据被驱逐、过期、手动删除时,会触发监听器的回调逻辑,可在回调中实现数据统计、日志记录、资源释放等操作。
监听器的回调逻辑支持同步与异步两种模式,异步模式不会阻塞缓存的淘汰操作,避免监听器逻辑影响缓存的核心性能。
5.4 完整的缓存统计功能
内置全面的缓存统计指标,开启统计功能后,可实时获取缓存的命中率、加载成功率、缓存命中数、缓存缺失数、数据加载时间、缓存驱逐数等核心指标。
统计指标可用于分析缓存的使用效率,指导缓存配置的优化,比如调整缓存容量、过期时间等,是性能调优的重要依据,统计功能的性能损耗极低,开启后对核心业务无影响。
5.5 禁止缓存空值 / 无效值
支持配置是否缓存空值或无效值,可有效避免缓存穿透问题:当业务数据查询结果为空时,可选择不缓存该结果,防止恶意请求将大量空值写入缓存,导致缓存命中率降低、内存浪费。
同时支持自定义缓存值的过滤规则,可根据业务需求决定哪些数据可以存入缓存,哪些数据需要过滤,进一步提升缓存的有效性。
5.6 缓存预热功能
支持缓存的预热加载,在项目启动时,可将高频访问的热点数据提前加载到缓存中,避免项目启动初期因缓存缺失导致的大量数据库查询,有效提升系统启动后的响应效率,避免数据库压力骤增。
5.7 键值的自定义配置
支持对缓存的键和值进行自定义的相等性判断与哈希计算,可适配自定义对象作为缓存键的场景,避免因对象的 equals 和 hashCode 方法实现不当导致的缓存失效问题。
支持对缓存值进行自定义的序列化与反序列化,适配特殊的数据类型存储需求,灵活性极高。
六、Caffeine 与主流本地缓存框架对比
Caffeine 是 Java 本地缓存框架的标杆,与目前主流的 Guava Cache、Ehcache 3.x、ConcurrentHashMap 相比,在性能、功能、命中率等核心维度均有明显优势,以下为核心维度的详细对比,所有结论均基于业界通用的性能测试与实际业务验证:
6.1 Caffeine vs Guava Cache
核心关系:Caffeine 是 Guava Cache 的升级版本,由 Guava Cache 原作者参与开发,完全兼容 Guava Cache 的 API 设计,可无缝迁移。
性能对比:Caffeine 的读写性能是 Guava Cache 的数倍,缓存命中率比 Guava Cache 高出 10%-20%,核心原因是 W-TinyLFU 算法优于 Guava Cache 的 LRU 算法。
功能对比:Caffeine 在 Guava Cache 的基础上增加了异步操作、软 / 弱引用优化、缓存刷新等功能,功能更完备,配置更灵活。
适用场景:Guava Cache 适合 Java 7 及以下版本的项目,Caffeine 适合 Java 8 及以上版本的项目,是 Guava Cache 的最优替代方案。
6.2 Caffeine vs Ehcache 3.x
性能对比:Caffeine 的读写性能与缓存命中率均远超 Ehcache 3.x,Ehcache 的优势在于支持缓存持久化,可将缓存数据写入磁盘或数据库,而 Caffeine 仅支持纯内存缓存。
功能对比:Ehcache 的功能更偏向于企业级缓存,支持分布式缓存、持久化、事务管理等,而 Caffeine 专注于本地内存缓存,功能更轻量化,无冗余特性。
适用场景:Ehcache 适合需要缓存持久化或分布式缓存的场景,Caffeine 适合纯内存的高性能本地缓存场景,是本地缓存的首选。
6.3 Caffeine vs ConcurrentHashMap
核心定位:ConcurrentHashMap 是 Java 的线程安全哈希表,并非专业的缓存框架,仅能实现简单的键值对存储,无缓存淘汰、过期策略等核心功能。
性能对比:两者的读操作性能接近,但 ConcurrentHashMap 无淘汰策略,当数据量过大时会导致内存溢出,而 Caffeine 可通过淘汰策略控制内存占用。
适用场景:ConcurrentHashMap 适合简单的临时数据存储,Caffeine 适合需要完整缓存功能的业务场景,是专业缓存的最优选择。
6.4 核心对比总结
性能排序:Caffeine > Guava Cache > Ehcache 3.x > ConcurrentHashMap
命中率排序:Caffeine > Guava Cache > Ehcache 3.x
功能完备性:Ehcache 3.x > Caffeine > Guava Cache > ConcurrentHashMap
轻量化程度:Caffeine > Guava Cache > ConcurrentHashMap > Ehcache 3.x
综合推荐:纯内存本地缓存场景,优先选择 Caffeine;需要持久化或分布式缓存的场景,选择 Ehcache 3.x;低版本 JDK 项目,选择 Guava Cache;简单数据存储,选择 ConcurrentHashMap。
七、Caffeine 最佳实践与核心避坑指南
7.1 核心配置优化原则
Caffeine 的性能与效果,很大程度上取决于配置的合理性,合理的配置能最大化发挥其优势,以下为通用的配置优化原则,适用于绝大多数业务场景,无特殊需求时按此配置即可:
- 容量配置:根据项目的可用内存,合理设置缓存的最大容量,建议设置为业务热点数据量的 1.5-2 倍,避免容量过小导致频繁驱逐,也避免容量过大导致内存浪费。
- 过期时间配置:根据业务数据的时效性选择 TTL 或 TTI,热点数据建议使用 TTL,静态数据建议使用 TTI;过期时间不宜过短也不宜过长,过短会导致缓存命中率低,过长会导致数据一致性差。
- 引用策略配置:内存敏感型业务优先选择软引用策略,避免内存溢出;普通业务无需配置引用策略,使用默认的强引用即可。
- 统计开关:建议开启缓存统计功能,通过统计指标持续优化配置,统计功能的性能损耗可忽略不计。
- 并发级别:无需手动配置,使用框架默认值即可,Caffeine 会根据 CPU 核心数自动适配最优的并发级别。
7.2 业务场景最佳适配
- 普通查询类业务:优先选择「自动加载模式 + TTL 过期策略」,简化开发,兼顾性能与数据时效性。
- 高并发核心业务:优先选择「异步自动加载模式 + 容量驱逐 + TTL 过期」,极致提升并发性能,保证缓存命中率与内存安全。
- 内存敏感型业务:优先选择「软引用策略 + 容量驱逐」,无需配置过期时间,由 JVM 内存状态自动管理缓存生命周期。
- 数据更新频繁的业务:优先选择「手动加载模式 + TTI 过期策略」,精准控制缓存的更新与失效时机,保证数据一致性。
- 热点数据预热:项目启动时,通过手动加载模式将热点数据提前存入缓存,避免启动初期的缓存穿透。
7.3 核心避坑指南
Caffeine 的使用门槛较低,但在实际开发中,仍有一些容易踩坑的点,这些坑点主要集中在概念混淆、配置不当、业务适配三个方面,避开这些坑点能有效保证缓存的稳定性与性能:
- 混淆缓存刷新与缓存过期:缓存刷新是异步更新数据,期间返回旧值;缓存过期是数据失效后重新加载,期间会阻塞请求(同步模式),切勿将两者混用,根据业务需求选择合适的策略。
- 盲目配置过期时间:部分业务无需设置过期时间,比如静态配置数据,设置过期时间会导致不必要的缓存失效与重新加载,降低性能;部分业务必须设置过期时间,比如用户动态数据,否则会导致数据一致性问题。
- 缓存空值导致内存浪费:查询结果为空时,若无特殊需求,建议不缓存空值,避免大量空值占用缓存空间,降低缓存命中率。
- 使用可变对象作为缓存键:缓存键如果是自定义对象,建议保证对象的不可变性,或重写 equals 和 hashCode 方法,否则对象属性变更后,会导致缓存无法命中,出现缓存失效问题。
- 过度依赖缓存:缓存是提升性能的手段,不是数据存储的核心,切勿将缓存作为唯一的数据来源,必须保证缓存缺失时,业务能正常从数据库加载数据,避免缓存雪崩导致系统故障。
- 忽略缓存统计:开启统计功能后,可通过命中率等指标发现配置问题,比如命中率过低可能是容量过小或过期时间过短,及时调整配置能有效提升性能。
八、Caffeine 适用与不适用场景
8.1 核心适用场景
Caffeine 作为高性能的本地缓存框架,在 Java 项目中有广泛的应用场景,以下为核心的适用场景,也是其优势最大化的场景:
- 高频访问的本地数据缓存:比如业务中的热点配置、用户信息、商品详情等,这类数据访问频率高,更新频率低,适合存入本地缓存,大幅提升查询效率。
- 分布式缓存的一级缓存:在微服务架构中,可作为 Redis 等分布式缓存的一级缓存,本地缓存命中则直接返回,未命中再访问分布式缓存,有效降低分布式缓存的访问压力,提升系统响应效率。
- 高并发业务的无状态缓存:比如限流、熔断、降级的规则缓存,接口的参数校验缓存等,这类业务对性能要求高,无需数据持久化,适合用 Caffeine 做本地缓存。
- 内存敏感型业务的缓存需求:通过软引用策略,可实现缓存的内存自适应管理,避免内存溢出,适配内存紧张的业务场景。
- 异步编程的缓存需求:通过异步加载模式,完美适配 Java 的异步编程模型,在高并发异步业务中发挥极致性能。
8.2 不适用场景
Caffeine 虽优秀,但并非万能的缓存解决方案,在部分场景下,其特性无法满足业务需求,此时应选择其他更合适的缓存框架,避免强行使用导致业务问题,核心不适用场景如下:
- 需要持久化存储的缓存场景:Caffeine 仅支持纯内存缓存,缓存数据在 JVM 重启后会丢失,若需要缓存数据持久化,应选择 Ehcache 3.x 或 Redis。
- 需要分布式一致性的缓存场景:Caffeine 是本地缓存,每个 JVM 实例有独立的缓存空间,无法保证分布式系统中缓存数据的一致性,若需要分布式缓存,应选择 Redis、Memcached 等分布式缓存框架。
- 超大容量的缓存存储需求:Caffeine 的缓存数据存储在 JVM 内存中,受限于 JVM 的内存大小,无法存储超大容量的缓存数据,若需要存储大量数据,应选择分布式缓存。
- 需要跨 JVM 共享的缓存数据:Caffeine 的缓存数据仅能在当前 JVM 实例中访问,无法跨 JVM 共享,若需要多实例共享缓存数据,应选择分布式缓存。
九、总结
9.1 核心总结
- Caffeine 是Java 8 及以上版本最优的本地缓存框架,基于 W-TinyLFU 算法实现超高的缓存命中率,读写性能极致,是本地缓存的首选方案。
- Caffeine 的核心优势是高性能、高命中率、轻量级、功能完备,无第三方依赖,配置灵活,适配所有 Java 项目的本地缓存需求。
- Caffeine 的核心设计思想是「兼顾性能与实用性」,既提供了极致的性能优化,又提供了丰富的功能特性,覆盖从简单到复杂的所有业务场景。
- Caffeine 的四种工作模式与三种过期策略,可灵活组合,适配不同的业务需求,自动加载模式与异步加载模式是其核心亮点,大幅简化开发并提升性能。
9.2 最终建议
- 对于 Java 项目的本地缓存需求,优先选择 Caffeine,其性能与功能均远超同类框架,是本地缓存的标杆。
- 在微服务架构中,建议采用「Caffeine + Redis」的双层缓存架构,Caffeine 作为一级缓存,Redis 作为二级缓存,兼顾性能与分布式一致性,是最优的缓存组合方案。
- 配置 Caffeine 时,遵循「合理设置容量、按需配置过期时间、开启统计功能」的原则,通过统计指标持续优化配置,最大化发挥其优势。
- 避开缓存使用的常见坑点,明确缓存的定位是「性能优化手段」,而非「数据存储核心」,保证业务的容错能力与数据一致性。
Caffeine 凭借其极致的性能与优秀的设计,已成为 Java 生态中本地缓存的事实标准,掌握 Caffeine 的核心特性与最佳实践,能有效提升 Java 项目的并发性能与开发效率,是 Java 开发人员必备的技术栈之一。