使用缓存编写器的咖啡因缓存基于时间的逐出

时间:2020-09-25 02:54:47

标签: java caching caffeine

我正在使用具有以下配置的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和{{1}中的代码被逐出(在每个请求中)? }每隔几毫秒执行一次,最终创建了25,000个线程,并消除了服务错误。

有人可以告诉我我是否犯了致命的错误?还是显而易见的痛苦是错误的?我觉得我对咖啡因有误解。

目标是让缓存中的记录每1小时刷新一次,刷新后,从后端API获取新值,并在满足某些条件的情况下将其持久保存在数据库中。

1 个答案:

答案 0 :(得分:0)

由于RemovalListener是异步的,因此缓存进入了无限循环,因此,在重负载下,RemovalListener之前,缓存值已被对过期密钥的请求所取代实际刷新缓存。

因此,这些值将:

  1. 通过REPLACED删除原因将其从缓存中删除
  2. 致电RemovalListener
  3. 再次刷新并替换,然后
  4. 回到#1。

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