4. 本地缓存与分布式缓存:Caffeine、Redis、EhCache 选型对比与适用边界

在微服务与分布式架构中,缓存一致性问题的根源往往在于“本地缓存”与“分布式缓存”的混合使用。选错缓存组件或混淆其适用边界,会导致数据不一致、内存溢出、网络瓶颈等连锁问题。本章从架构视角出发,对 Caffeine、Redis、EhCache 三款主流缓存进行深度对比,并给出清晰的适用边界。

4.1 缓存分类与核心差异

缓存按部署位置可分为两类:

  • 本地缓存(进程内缓存):与应用运行在同一 JVM 进程中,如 Caffeine、EhCache、Guava Cache。访问速度极快(纳秒级),但受限于堆内存,且多实例间数据独立。
  • 分布式缓存(远程缓存):独立部署的缓存服务,如 Redis、Memcached。数据集中存储,所有应用实例共享,但存在网络 I/O 开销(毫秒级)。
架构原则:本地缓存适合“读多写少、一致性要求低”的热点数据;分布式缓存适合“共享、需持久化、一致性要求高”的全局数据。两者常组合为“多级缓存”架构。

4.2 三款缓存组件核心对比

对比维度 Caffeine Redis EhCache
类型 本地缓存(进程内) 分布式缓存(远程) 本地缓存(进程内)
数据存储 堆内存(Java 对象) 内存 + 磁盘持久化 堆/堆外内存 + 磁盘
访问延迟 纳秒级(< 1μs) 毫秒级(1-5ms) 微秒级(1-10μs)
淘汰策略 W-TinyLFU(近最优) LRU / LFU / TTL / 随机 LRU / LFU / FIFO / TTL
持久化 不支持 RDB / AOF 支持(磁盘存储)
分布式支持 无(单机) 原生集群 / 哨兵 / 分片 Terracotta 集群(复杂)
一致性模型 最终一致(单机强一致) 最终一致(主从异步) 最终一致(需集群协调)
Spring Boot 集成 spring-boot-starter-cache + caffeine spring-boot-starter-data-redis spring-boot-starter-cache + ehcache

4.3 选型决策树与适用边界

以下决策树可帮助团队快速确定缓存选型:

  1. 是否需要多实例共享数据?
    • 是 → 走分布式缓存(Redis)
    • 否 → 走本地缓存(Caffeine / EhCache)
  2. 本地缓存选哪个?
    • 追求极致性能、高并发、低内存开销 → Caffeine
    • 需要持久化、堆外内存、复杂配置 → EhCache
  3. 分布式缓存选哪个?
    • 标准场景、数据结构丰富、持久化需求 → Redis
    • 仅简单 KV、无持久化、极致简单 → Memcached(本章不展开)
推荐组合(Spring Boot 多级缓存):
Caffeine(L1 本地热点缓存)+ Redis(L2 分布式共享缓存)。
读操作:先查 Caffeine,未命中再查 Redis,回填 Caffeine。
写操作:更新 Redis,异步广播失效 Caffeine 中的对应 key。

4.4 架构示意图:多级缓存协作流程

多级缓存架构:Caffeine + Redis 协作流程 Spring Boot 应用 L1: Caffeine 本地热点缓存 L2: Redis 分布式共享缓存 数据库 (MySQL) 读请求(先查 L1) L1 未命中,查 L2 回填 / 失效广播 L2 未命中,回源 DB 💡 写操作:应用直接更新 Redis,并通过消息或定时任务失效 Caffeine 中的对应 key,保证最终一致性。

4.5 代码示例:Spring Boot 多级缓存配置

以下配置展示了如何同时启用 Caffeine 和 Redis,并自定义 CacheManager 实现多级缓存策略:

@Configuration
@EnableCaching
public class MultiLevelCacheConfig {

    // Caffeine 缓存管理器
    @Bean
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(500)
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .recordStats());
        return manager;
    }

    // Redis 缓存管理器
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30))
                .serializeKeysWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(
                    RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
    }

    // 自定义多级缓存实现(简化示意)
    @Bean
    public CacheManager multiLevelCacheManager(
            @Qualifier("caffeineCacheManager") CacheManager caffeine,
            @Qualifier("redisCacheManager") CacheManager redis) {
        return new CacheManager() {
            @Override
            public Cache getCache(String name) {
                return new MultiLevelCache(caffeine.getCache(name), redis.getCache(name));
            }
            @Override
            public Collection<String> getCacheNames() {
                return caffeine.getCacheNames();
            }
        };
    }
}
避坑提示:多级缓存中,本地缓存(Caffeine)的 TTL 应远小于 Redis 的 TTL(例如 60s vs 30min),避免本地缓存长期持有过期数据。同时,写操作必须保证 Redis 更新成功后再失效本地缓存,防止脏数据。

4.6 适用边界总结

场景 推荐方案 理由
单实例应用、高并发读 Caffeine 纳秒级访问,W-TinyLFU 淘汰策略命中率极高
多实例共享、数据需持久化 Redis 原生集群支持,RDB/AOF 持久化,数据结构丰富
需要堆外内存、磁盘存储 EhCache 支持堆外内存和磁盘溢出,适合大容量本地缓存
微服务多级缓存(标准架构) Caffeine + Redis 兼顾性能与一致性,业界主流实践
强一致性要求极高(如金融交易) 仅用 Redis(或 DB) 本地缓存无法保证多实例强一致,需避免使用

4.7 选型对比雷达图

三款缓存组件能力雷达对比 性能 分布式能力 持久化 一致性 易用性 Caffeine Redis EhCache 注:纵轴越高表示该维度能力越强。Caffeine 性能最优,Redis 分布式与持久化最强,EhCache 居中。

4.8 本章小结

  • Caffeine:本地缓存首选,性能极致,适合热点数据加速。
  • Redis:分布式缓存标准,共享数据与持久化场景不可替代。
  • EhCache:本地缓存备选,适合需要堆外内存或磁盘溢出的特殊场景。
  • 多级缓存:Caffeine + Redis 组合是 Spring Boot 微服务架构的主流实践,需通过 TTL 和失效机制保证最终一致性。