Caffeine Expiry 中如何设置多个过期条件?
How are multiple expiration criteria set in Caffeine Expiry?
我使用的是 Caffeine v2.8.5,我想创建一个具有基于变量到期时间的缓存:
- 值的creation/update和
- 该值的最后一次访问(读取)。
无论先到什么都应该触发该条目的删除。
缓存将成为三层值解析的一部分:
- 密钥存在于 Caffeine 缓存中
- 使用这个值
- 刷新access/read过期
- 密钥存在于 Redis 数据库中
- 使用这个值
- 将此值与 Redis 键的剩余 TTL (Time to live) 一起存储在 Caffeine 缓存中
- 密钥既不存在于内部缓存中,也不存在于 Redis 中
- 从外部 REST 请求值 API
- 将此值存储在 Redis 数据库中,固定有效期为 30 天
- 将此值存储在 Caffeine 缓存中,固定有效期为 30 天
Redis用作全局缓存,这样多个applications/instances可以共享缓存的数据,但是这种解析经常发生,不能用于每个请求,所以另一个缓存层是必要的。
根据请求的时间,请求的数据具有不同的 TTL。因此,当我们请求 REST API 并且在 Redis 中设置到期时间时,虽然到期时间可能是固定的,但 Caffeine 中的时间将是动态的,因为到期时间基于 Redis 密钥的剩余 TTL。
案例 (2) 和 (3) 已经在我的 Caffeine 缓存的 CacheLoader 中解决了(我在通读模式下使用缓存)。为了控制我已经发现的过期时间,我将不得不使用 advanced Expiry API and I've also looked into similar issues like and 。所以我为我的键想出了一个包装器对象,如下所示:
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归零后被移除。
我将如何实施第二个标准? 我不知道我将如何获得最后一次访问条目的时间。该接口似乎没有提供这样的值。我还调查了 。这些方法将根据条目已分类到的调度程序存储桶 called/re-evaluated 定期
是否正确?
我对 Expiries 工作原理的最大误解是,我认为 Expiry 的方法会定期触发 re-evaluated。我正在回答我自己的问题,以防有人从他们的研究中得到同样的印象。
Expiry 中的方法只有在执行了相应方法名称的操作后才会被调用(因此值只会更新)。因此,例如 expireAfterRead(K, V, long, long)
只会在每次缓存中读取此 key-value-mapping 时调用。
因此,如果映射在创建后永远不会有任何操作(没有读取或更新),则只会调用一次 expireAfterCreate(K, V, long)
方法。这就是为什么所有方法都应始终 return 剩余 持续时间,但不必考虑上次读取条目的时间,因为那一刻就是现在(如 Instant.now()
),expireAfterRead(K, V, long, long)
被调用。
正如@BenManes 在评论中指出的那样,我最初的问题的正确解决方案是 returning
Math.min(TimeUnit.HOURS.toNanos(1), Duration.between(Instant.now(), value.getValidUntil()).toNanos())
在 Expiry 的所有三种方法中。
并回答我在 post 中的另外两个问题:
如何获取条目的最后一次访问时间?
在 expireAfterRead(K, V, long, long)
方法中调用(例如)Instant.now()
。如果您还想在外部或另一个 expire-methods 中拥有该值,始终可以选择将此值存储在具有易失性字段的 ExpiringValue 中。
方法将根据调度程序桶定期 called/re-evaluated 条目分类是否正确?
不会。正如上面所解释的,Expiry 中的方法只有在执行相应的操作后才会被调用。这些方法不会被触发或 re-evalutated 定期。
我使用的是 Caffeine v2.8.5,我想创建一个具有基于变量到期时间的缓存:
- 值的creation/update和
- 该值的最后一次访问(读取)。
无论先到什么都应该触发该条目的删除。
缓存将成为三层值解析的一部分:
- 密钥存在于 Caffeine 缓存中
- 使用这个值
- 刷新access/read过期
- 密钥存在于 Redis 数据库中
- 使用这个值
- 将此值与 Redis 键的剩余 TTL (Time to live) 一起存储在 Caffeine 缓存中
- 密钥既不存在于内部缓存中,也不存在于 Redis 中
- 从外部 REST 请求值 API
- 将此值存储在 Redis 数据库中,固定有效期为 30 天
- 将此值存储在 Caffeine 缓存中,固定有效期为 30 天
Redis用作全局缓存,这样多个applications/instances可以共享缓存的数据,但是这种解析经常发生,不能用于每个请求,所以另一个缓存层是必要的。
根据请求的时间,请求的数据具有不同的 TTL。因此,当我们请求 REST API 并且在 Redis 中设置到期时间时,虽然到期时间可能是固定的,但 Caffeine 中的时间将是动态的,因为到期时间基于 Redis 密钥的剩余 TTL。
案例 (2) 和 (3) 已经在我的 Caffeine 缓存的 CacheLoader 中解决了(我在通读模式下使用缓存)。为了控制我已经发现的过期时间,我将不得不使用 advanced Expiry API and I've also looked into similar issues like
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归零后被移除。
我将如何实施第二个标准? 我不知道我将如何获得最后一次访问条目的时间。该接口似乎没有提供这样的值。我还调查了
我对 Expiries 工作原理的最大误解是,我认为 Expiry 的方法会定期触发 re-evaluated。我正在回答我自己的问题,以防有人从他们的研究中得到同样的印象。
Expiry 中的方法只有在执行了相应方法名称的操作后才会被调用(因此值只会更新)。因此,例如 expireAfterRead(K, V, long, long)
只会在每次缓存中读取此 key-value-mapping 时调用。
因此,如果映射在创建后永远不会有任何操作(没有读取或更新),则只会调用一次 expireAfterCreate(K, V, long)
方法。这就是为什么所有方法都应始终 return 剩余 持续时间,但不必考虑上次读取条目的时间,因为那一刻就是现在(如 Instant.now()
),expireAfterRead(K, V, long, long)
被调用。
正如@BenManes 在评论中指出的那样,我最初的问题的正确解决方案是 returning
Math.min(TimeUnit.HOURS.toNanos(1), Duration.between(Instant.now(), value.getValidUntil()).toNanos())
在 Expiry 的所有三种方法中。
并回答我在 post 中的另外两个问题:
如何获取条目的最后一次访问时间?
在 expireAfterRead(K, V, long, long)
方法中调用(例如)Instant.now()
。如果您还想在外部或另一个 expire-methods 中拥有该值,始终可以选择将此值存储在具有易失性字段的 ExpiringValue 中。
方法将根据调度程序桶定期 called/re-evaluated 条目分类是否正确? 不会。正如上面所解释的,Expiry 中的方法只有在执行相应的操作后才会被调用。这些方法不会被触发或 re-evalutated 定期。