gpt4 book ai didi

java - Caffeine Expiry 中如何设置多个过期条件?

转载 作者:行者123 更新时间:2023-12-01 23:45:42 32 4
gpt4 key购买 nike

我使用的是 Caffeine v2.8.5,我想创建一个基于以下内容的可变到期缓存:

  • 值(value)的创造/更新
  • 最后一次访问(读取)此值。

无论先发生什么都应该触发该条目的删除。


缓存将成为三层值解析的一部分:

  1. key 存在于 Caffeine 缓存中
    • 使用这个值
    • 刷新访问权限/读取到期时间
  2. key 存在于 Redis 数据库中
    • 使用这个值
    • 将此值与剩余的 TTL (Time to live) 一起存储在 Caffeine 缓存中Redis key
  3. key 既不存在于内部缓存中,也不存在于 Redis 中
    • 从外部 REST API 请求值
    • 将此值存储在 Redis 数据库中,固定有效期为 30 天
    • 将此值存储在 Caffeine 缓存中,固定有效期为 30 天

Redis 用作全局缓存,以便多个应用程序/实例可以共享缓存数据,但这种解析经常发生,以至于它不能用于每个请求,因此需要另一个缓存层。

根据请求的时间,请求的数据具有不同的 TTL。因此,虽然当我们请求 REST API 时过期时间可能是固定的,并且过期时间是在 Redis 中设置的,但 Caffeine 中的时间将是动态的,因为过期时间基于 Redis key 的剩余 TTL。

案例 (2) 和 (3) 已经在我的 Caffeine 缓存的 CacheLoader 中解决了(我在通读模式下使用缓存)。为了控制我已经发现的过期时间,我必须使用 advanced Expiry API我也研究过类似的问题 (Specify expiry for an Entry)(Expire cached values after creation time) .所以我为我的键想出了一个包装器对象,如下所示:

import lombok.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.time.Instant;

@Value
public class ExpiringValue<ValueType> {

@Nullable
private final ValueType value;
@NotNull
private final Instant validUntil;
}

和一个Expiry像这样:

import com.github.benmanes.caffeine.cache.Expiry;
import org.jetbrains.annotations.NotNull;

import java.time.Duration;
import java.time.Instant;

public final class ValueBasedExpiry<KeyType, ValueType extends ExpiringValue<?>> implements Expiry<KeyType, ValueType> {

@Override
public long expireAfterCreate(
@NotNull final KeyType key,
@NotNull final ValueType value,
final long currentTime
) {
return Duration.between(Instant.now(), value.getValidUntil()).toNanos();
}

@Override
public long expireAfterUpdate(
@NotNull final KeyType key,
@NotNull final ValueType value,
final long currentTime,
final long currentDuration
) {
return currentDuration;
}

@Override
public long expireAfterRead(
@NotNull final KeyType key,
@NotNull final ValueType value,
final long currentTime,
final long currentDuration
) {
return currentDuration;
}
}

我的用例的不同之处在于,我希望有第二个基于值的最后访问的到期标准。所以我想尽早删除该条目,如果它在一个小时内没有被请求的话。并且如果被频繁访问,最终会在TTL归零后被移除。

我将如何实现第二个标准?我不知道我将如何获得上次访问条目的时间。该接口(interface)似乎没有提供这样的值。我也调查了this question .根据条目已分类到的调度程序桶,定期调用/重新评估这些方法是否正确?

最佳答案

我对 Expiries 的误解工作,是我认为,到期的方法将被定期触发和重新评估。我正在回答我自己的问题,以防有人从他们的研究中得到同样的印象。

Expiry 中的方法仅在执行了相应方法名称的操作后才调用(因此仅更新值)。因此,例如 expireAfterRead(K, V, long, long) 只会在每次缓存中读取此键值映射时调用。

因此,如果映射在创建后永远不会有任何操作(没有读取或更新),则只会调用 expireAfterCreate(K, V, long) 方法一次。这就是为什么所有方法都应始终返回 remaining 持续时间,但不必考虑上次读取条目的时间,因为那一刻就是现在(如 Instant. now()),调用 expireAfterRead(K, V, long, long)

正如@BenManes 在评论中指出的那样,我最初的问题的正确解决方案是返回

Math.min(TimeUnit.HOURS.toNanos(1), Duration.between(Instant.now(), value.getValidUntil()).toNanos())

在 Expiry 的所有三种方法中。


并在帖子中回答我的另外两个问题:

我如何获得上次访问条目的时间?expireAfterRead(K, V, long, long) 方法中调用(例如)Instant.now()。如果您还想在外部或其他过期方法中拥有该值,始终可以选择将此值存储在具有 volatile 字段的 ExpiringValue 中。

根据条目已分类到的调度程序桶,定期调用/重新评估这些方法是否正确?不会。正如上面所解释的,Expiry 中的方法只有在执行相应的操作后才会被调用。这些方法不会被定期触发或重新评估。

关于java - Caffeine Expiry 中如何设置多个过期条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64201136/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com