Caffeine参数expireAfterWrite和refreshAfterWrite的区别和使用

805 阅读3分钟

Caffeine 的 expireAfterWriterefreshAfterWrite 用途和行为不同,需要结合业务场景合理配置。以下是两者的区别和联合使用的实践建议:


1. 核心区别

特性expireAfterWriterefreshAfterWrite
触发条件写入后固定时间强制过期,缓存条目被移除写入后固定时间触发异步刷新,保留旧值直到刷新完成
数据可用性过期后数据不可用,触发同步加载(可能阻塞请求)刷新期间旧数据仍然可用,新数据异步加载
适用场景强一致性场景(如敏感配置)高可用性场景(如频繁访问的热点数据)
对性能影响过期后同步加载可能导致瞬时压力异步刷新减少阻塞,但可能返回旧数据

2. 同时使用的场景

当需要同时满足以下需求时,可以联合使用两者:

  • 保证数据新鲜度:通过 expireAfterWrite 设置最终过期时间,防止因刷新失败导致数据长期不更新。
  • 减少阻塞和穿透:通过 refreshAfterWrite 提前异步刷新,避免过期后大量请求同步加载数据库。

示例配置

LoadingCache<Key, Value> cache = Caffeine.newBuilder()
    .expireAfterWrite(30, TimeUnit.MINUTES)   // 最终过期时间(兜底)
    .refreshAfterWrite(10, TimeUnit.MINUTES)  // 定期刷新(优化体验)
    .build(key -> loadDataFromDB(key));

3. 行为解析

  1. 写入后 10 分钟

    • 下一次访问该 Key 时触发异步刷新,后台加载新值,但立即返回旧值
    • 旧值仍然保留在缓存中,直到刷新完成或过期。
  2. 写入后 30 分钟

    • 缓存条目强制过期,后续访问会同步加载新值(阻塞请求直到加载完成)。
  3. 刷新失败时

    • 如果异步刷新过程中发生异常,旧值会保留,直到过期时间到达后强制重新加载。

4. 注意事项

  • 刷新与过期间隔
    通常设置 refreshAfterWrite < expireAfterWrite,确保在过期前有机会刷新数据。
    例如:refresh=10m + expire=30m

  • 资源消耗
    频繁刷新可能增加后台负载,需结合 executor 配置合理的线程池(默认使用 ForkJoinPool)。

  • 数据一致性
    刷新期间可能短暂返回旧值,不适用于强一致性场景。

  • 异常处理
    CacheLoader 中需捕获异常,避免刷新失败导致缓存条目直接过期。


5. 完整示例

LoadingCache<String, String> cache = Caffeine.newBuilder()
    .expireAfterWrite(30, TimeUnit.MINUTES)
    .refreshAfterWrite(10, TimeUnit.MINUTES)
    // 自定义线程池(可选)
    .executor(Executors.newFixedThreadPool(4))
    .build(new CacheLoader<>() {
        @Override
        public String load(String key) {
            return fetchFromDB(key); // 同步加载(用于初始化或过期后)
        }

        @Override
        public CompletableFuture<String> reload(String key, String oldValue) {
            return CompletableFuture.supplyAsync(() -> fetchFromDB(key));
        }
    });

// 使用缓存
String value = cache.get("key1"); // 触发加载或刷新

6. 适用场景

  • 高频访问的热点数据:通过定期刷新减少用户感知的延迟。
  • 容忍短暂不一致:如商品价格、库存等非强一致性数据。
  • 依赖外部服务:防止因外部服务抖动导致缓存雪崩。

总结

expireAfterWriterefreshAfterWrite 的联合使用能平衡数据的新鲜度可用性,但需注意:

  1. 设置合理的过期和刷新的时间间隔。
  2. 处理刷新时的异常和资源竞争。
  3. 根据业务容忍度选择是否接受短暂不一致。