1558 字
约 5 分钟
0
Caffeine 入门到二级缓存实战:Caffeine + Redis 多级缓存设计

上一篇介绍了 Caffeine 的淘汰算法(W-TinyLFU),这一篇我们聚焦怎么用:从 Caffeine 的基础用法入手,再到生产中最常见的高性能方案——Caffeine 本地缓存 + Redis 分布式缓存组成的二级缓存,最后梳理一下它和 Spring Cache、Ehcache、Guava Cache 等缓存生态的关系。

一、Caffeine 入门

Caffeine 是一个基于 Java 8 的高性能本地缓存库,是 Spring Boot 默认推荐的本地缓存实现,性能优于 Guava Cache。

1. 引入依赖

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.8</version>
</dependency>

2. 基本用法

Cache<String, User> cache = Caffeine.newBuilder()
        .maximumSize(10_000)                       // 容量上限,超出按 W-TinyLFU 淘汰
        .expireAfterWrite(Duration.ofMinutes(5))   // 写入 5 分钟后过期
        .recordStats()                             // 开启命中率统计
        .build();

// 读:缓存未命中时,通过 mappingFunction 自动加载并回填
User user = cache.get(userId, id -> userService.getById(id));

3. 三种加载方式

  • Cache(手动):get(key, mappingFunction) 手动控制,最灵活;
  • LoadingCache(同步加载):构造时传入 CacheLoader,未命中自动同步加载;
  • AsyncLoadingCache(异步加载):基于 CompletableFuture,未命中时异步加载,适合 IO 密集场景。

4. 常用配置

配置 作用
maximumSize(n) 按条目数淘汰
maximumWeight(n) 按权重淘汰
expireAfterWrite(d) 写入后过期
expireAfterAccess(d) 最后一次访问后过期
refreshAfterWrite(d) 写入后异步刷新,避免阻塞
recordStats() 记录命中率、加载耗时等指标
removalListener(...) 条目被淘汰/替换时回调

二、为什么要做"二级缓存"

单用 Redis 足够吗?在高并发读场景下,Redis 虽然是内存数据库,但仍有网络 I/O 开销,每次查询都要走一次网络往返;而且 Redis 宕机时缓存层就整体失效,流量瞬间打穿到数据库。

于是有了本地缓存 + 分布式缓存的组合:

请求 → Caffeine(本地,进程内,最快)
        ↓ 未命中
      Redis(分布式,跨进程共享)
        ↓ 未命中
      数据库(兜底,回填 Redis + Caffeine)
  • 第一级:Caffeine 本地缓存——零网络开销,微秒级响应,扛住超高并发读;
  • 第二级:Redis 分布式缓存——多实例共享,容量大、可扩展,命中率兜底;
  • 第三级:数据库——最后兜底,回填两级缓存。

好处是性能拉满(本地命中完全不走网络),坏处是一致性变难——同一个 key 在多个 JVM 进程里各有一份拷贝,更新时要保证各副本同步。

三、Caffeine + Redis 二级缓存实战

1. 基础流程

public User getUser(Long id) {
    // 1. 先查本地缓存
    User user = caffeineCache.getIfPresent(id);
    if (user != null) {
        return user;
    }
    // 2. 本地未命中,查 Redis
    String key = "user:" + id;
    String json = redisTemplate.opsForValue().get(key);
    if (json != null) {
        user = JSON.parseObject(json, User.class);
        caffeineCache.put(id, user);  // 回填本地
        return user;
    }
    // 3. 两级都未命中,查库并回填两级缓存
    user = userMapper.selectById(id);
    caffeineCache.put(id, user);
    redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 30, TimeUnit.MINUTES);
    return user;
}

2. 如何保证一致性(重点)

二级缓存最容易踩的坑是:更新数据库后,本地缓存和 Redis 没同步更新,读到旧数据。常用手段:

  • 延迟双删:更新数据库后,先删 Redis,再延迟一小段时间删一次(配合第二次删除兜底并发窗口);
  • 本地缓存用极短 TTL:本地缓存的过期时间设置得比 Redis 短得多(比如 Redis 30 分钟、本地 30 秒),让本地副本快速过期自愈,即使不一致也只在很短的窗口内发生;
  • 消息通知失效:更新方通过 MQ/Redis Pub-Sub 广播"某 key 已变更",各实例收到后主动清掉本地缓存;
  • 版本号比对:缓存里带上版本号,读取时校验,版本过期则重新加载。

业界更推荐"本地缓存短 TTL + 删除广播"组合:本地靠短 TTL 自愈兜底,广播负责主动快速失效,兼顾一致性与性能。

3. 监听淘汰回调

Caffeine.newBuilder()
        .removalListener((key, value, cause) -> {
            // cause: EXPIRED / SIZE / REPLACED / EXPLICIT
            log.info("本地缓存淘汰 key={}, cause={}", key, cause);
        })
        .build();

可用来在本地淘汰时回查 Redis,或做缓存击穿防护的兜底日志。

四、Caffeine 与其他缓存生态的关系

缓存 定位 与 Caffeine 的关系
Guava Cache 谷歌的本地缓存 Caffeine 是其高配升级版,API 几乎兼容
Ehcache 本地/分布式缓存,老牌 同为本地缓存,Caffeine 性能更高、更轻量
Redis 分布式缓存 Caffeine 与其组成二级缓存,Caffeine 管本地、Redis 管共享
Memcached 分布式缓存 与 Redis 同层,可被 Redis 替代,通常不直接与 Caffeine 组合
Spring Cache 缓存抽象层 统一 @Cacheable 注解,可配置 Caffeine 或 Redis 作为底层实现

Spring Cache + Caffeine 组合示例

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(Duration.ofMinutes(30)));
        return manager;
    }
}

之后在方法上加 @Cacheable(value = "user", key = "#id"),Spring 就会自动走 Caffeine。想切 Redis 时,换一个 RedisCacheManager 即可,业务代码零改动——这就是缓存抽象层的价值。

五、总结

  • Caffeine 是高性能本地缓存,适合放"单 JVM 内、超高频读"的数据;
  • 二级缓存用"本地 Caffeine + 分布式 Redis"组合,本地扛并发、Redis 兜底共享,能显著降低 Redis 与数据库压力;
  • 一致性是二级缓存的难点,推荐"本地短 TTL + 删除广播/延迟双删"组合;
  • Spring Cache 统一了缓存抽象,Caffeine、Redis、Ehcache 都可以作为它的底层实现,按需切换。

从淘汰算法(W-TinyLFU)到入门用法,再到二级缓存与生态关联,Caffeine 这条线就完整了。下一篇可以继续深入"二级缓存一致性的完整方案"或"Redis 生产级部署",需要的话随时说。

Caffeine 入门到二级缓存实战:Caffeine + Redis 多级缓存设计
https://www.clxhxhhr.top/posts/4592/
作者
clxstart
发布于
2026-10-10
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。