咖啡因缓存基于时间的逐出缓存写入器

Caffeine cache time-based eviction with cache writer

我正在使用具有以下配置的 Caffeine 缓存:

datesCache = Caffeine.newBuilder()
                .maximumSize(1000L)
                .expireAfterWrite(1, TimeUnit.HOURS)
                .writer(new CacheWriter<String, Map<String, List<ZonedDateTime>>>() {
                    @Override
                    public void write(@NonNull final String key, @NonNull final Map<String, List<ZonedDateTime>> datesList) {
                        CompletableFuture.runAsync(() -> copyToDatabase(key, datesList), Executors.newCachedThreadPool());
                    }

                    @Override
                    public void delete(@NonNull final String key, @Nullable final Map<String, List<ZonedDateTime>> datesList,
                            @NonNull final RemovalCause removalCause) {
                        System.out.println("Cache key " + key + " got evicted from due to " + removalCause);
                    }
                })
                .scheduler(Scheduler.forScheduledExecutorService(Executors.newSingleThreadScheduledExecutor()))
                .removalListener((key, dateList, removalCause) -> {
                    LOG.info("Refreshing cache key {}.", key);
                    restoreKeys(key);
                })
                .build();

如果值满足某些条件,我正在使用 CacheWriter 在写入缓存时将记录复制到分布式数据库。此外,在驱逐时,我正在使用 RemovalListener 使用驱逐的密钥调用后端服务,以保持记录是最新的。

为了完成这项工作,我还必须在启动服务时初始化缓存,并使用 put 方法将值插入缓存。我使用 datesCache.get(key, datesList -> callBackendService(key)) 从缓存中检索值,以防请求是针对我在初始化时未获得的密钥。

利用此缓存的 API 有一段时间使用非常频繁,而且似乎由于某种原因记录被逐出(在每个请求中?)因为 RemovalListener 中的代码CacheWriter 每隔几毫秒执行一次,最终创建了超过 25,000 个线程并排除了服务错误。

谁能告诉我我是否做错了什么致命的错误?还是明显错误的痛苦的事情?我觉得我对咖啡因的误解很深。

目标是让缓存中的记录每 1 小时刷新一次,并在刷新时从后端获取新值 API 并在满足特定条件时将它们保存在数据库中。

缓存进入无限循环,因为 RemovalListener 是异步的,因此,在重负载时,缓存值在 RemovalListener 可以 实际刷新缓存。

因此值将:

  1. REPLACED 删除原因从缓存中删除
  2. 调用RemovalListener
  3. 再次刷新被替换,然后
  4. 返回#1。

解法: 计算 RemovalListener 中的 RemovalCause 以忽略 REPLACED 键。可以使用方法 wasEvicted() 或比较枚举值本身。