Caffeine LoadingCache - 带自定义过期策略的驱逐
Caffeine LoadingCache - Eviction with Custom expiration policy
使用 Caffeine 2.8.1 和 Java 8.
我创建了 LoadingCache<String, Boolean>
。我正在使用 cache.putAll(getAllKeyValues())
加载缓存,其中 getAllKeyValues()
returns a Map<String, Boolean>
.
我指定了 CacheLoader 通过调用 keyExistsOnServer(key)
方法来计算值,该方法调用外部服务来获取值。
我指定了自定义过期策略,如果值设置为 false
而 creating/updating[=68=,我想在 10 分钟内从缓存中逐出条目] 缓存中的条目。如果值为 true
.
,则保持 Long.MAX_VALUE
的长度
private RemovalListener<String, Boolean> removeListener =
(key, value, cause) ->
logger.info(
"Entry for Key={} with value={} was removed ({}) from cache", key, value, cause);
private LoadingCache<String, Boolean> cache =
Caffeine.newBuilder()
.expireAfter(
new Expiry<String, Boolean>() {
private static final long EXPIRATION_TEN_MINS_IN_NANOSECONDS = 600000000000L;
@Override
public long expireAfterCreate(String key, Boolean value, long currentTime) {
// If value is false that means key does not exist, so set expiration to 10 mins
return value ? Long.MAX_VALUE : EXPIRATION_TEN_MINS_IN_NANOSECONDS;
}
@Override
public long expireAfterUpdate(
String key, Boolean value, long currentTime, long currentDuration) {
// If value is changed from true to false then set expiration to 10 mins
return value ? Long.MAX_VALUE : EXPIRATION_TEN_MINS_IN_NANOSECONDS;
}
@Override
public long expireAfterRead(
String key, Boolean value, long currentTime, long currentDuration) {
// Don't modify expiration time after read
return currentDuration;
}
})
.recordStats()
.removalListener(removeListener)
.build(key -> keyExistsOnServer(key));
问题 #1: 根据我想要实现的目标,我的过期政策看起来是否正确?
问题#2:
我没有看到 RemovalListener
根据驱逐政策被召唤。这可能是由于 github issue.
中所述的清理任务的累积
但是,我的代码的正确性依赖于这样一个事实,即一旦条目的到期持续时间(false
值的情况下为 10 分钟)已经过去,如果我们调用 cache.get(key)
那么它应该不是 return 来自缓存的过期值,而是调用 CacheLoader
即 keyExistsOnServer(key) 方法来获取值。有人可以断言这就是它的行为方式吗?
这是@Louis Wasserman 在 github 问题上的陈述,但我不清楚这是否说明了问题:
Actually, what happens is that the get call itself discovers that the entry is expired and adds it to the queue of entries to be cleaned up
问题#3: 如果 CacheLoader
抛出 RuntimeException
会发生什么,即 keyExistsOnServer(key) 方法调用 cache.get(key)
?
问题#4:cache.asMap()
是否会包含已过期但未因清除应计而被逐出的条目?
问题#5: 当我在 expireAfterRead()
方法中记录 currentDuration
时,它似乎与经过的时间不一致。也就是说,如果它被设置为 600000000000(10 分钟)并将值更新为 false
我预计 5 分钟后它应该是 300000000000 但事实并非如此。为什么会这样?
Question#1: Does my expiration policy looks correct based on what I want to achieve?
是的,这看起来不错。您可以将常量设置为 Duration
或使用 TimeUnit
进行计算,只是为了让它看起来更漂亮。
Question#2: I do not see the RemovalListener getting called as per the eviction policy.
当缓存 activity 足够时,就会发生这种情况。您可以指定一个 Scheduler
,它将根据下一个条目设置为过期的时间唤醒并为您调用 cache.cleanUp
。对于 Java 9+ 用户,Java 提供了一个内置的调度线程,您可以在构建缓存时通过添加 Caffeine.scheduler(Scheduler.systemScheduler)
来利用它。
Once the expiration duration has passed for an entry and if we call cache.get(key) then it should not return the expired value from cache, but rather call the CacheLoader.
正确。缓存将在查找时验证条目,如果过期,则重新加载它。它永远不会 return 过期条目。
Question#3: What happens if there is RuntimeException thrown by CacheLoader that is keyExistsOnServer(key) method on calling cache.get(key)?
映射将不会建立,异常将传播给调用者。下一次调用 get(key)
将重新尝试,这可能会再次失败。您可以选择如何对此保持弹性。通常不是这样是一个好的答案,或者有时缓存它失败是一个更好的答案。
Question#4: Would cache.asMap() contain the entries which are expired but were not evicted due to accrual for cleanup?
缓存将保留条目但禁止它们可见,例如通过查找或迭代。唯一的外部指示是 size()
,因为该计数器在删除过期条目之前不会更新。
Question#5: When I am logging the currentDuration in the expireAfterRead() method, it does not seem consistent with the elapsed time. i.e. if it was set to 600000000000 (10 mins) with an update for the value to false I am expecting that after 5 mins it should be 300000000000 but it was not. Why so?
请打开单元测试问题,我们可以诊断。
使用 Caffeine 2.8.1 和 Java 8.
我创建了 LoadingCache<String, Boolean>
。我正在使用 cache.putAll(getAllKeyValues())
加载缓存,其中 getAllKeyValues()
returns a Map<String, Boolean>
.
我指定了 CacheLoader 通过调用 keyExistsOnServer(key)
方法来计算值,该方法调用外部服务来获取值。
我指定了自定义过期策略,如果值设置为 false
而 creating/updating[=68=,我想在 10 分钟内从缓存中逐出条目] 缓存中的条目。如果值为 true
.
Long.MAX_VALUE
的长度
private RemovalListener<String, Boolean> removeListener =
(key, value, cause) ->
logger.info(
"Entry for Key={} with value={} was removed ({}) from cache", key, value, cause);
private LoadingCache<String, Boolean> cache =
Caffeine.newBuilder()
.expireAfter(
new Expiry<String, Boolean>() {
private static final long EXPIRATION_TEN_MINS_IN_NANOSECONDS = 600000000000L;
@Override
public long expireAfterCreate(String key, Boolean value, long currentTime) {
// If value is false that means key does not exist, so set expiration to 10 mins
return value ? Long.MAX_VALUE : EXPIRATION_TEN_MINS_IN_NANOSECONDS;
}
@Override
public long expireAfterUpdate(
String key, Boolean value, long currentTime, long currentDuration) {
// If value is changed from true to false then set expiration to 10 mins
return value ? Long.MAX_VALUE : EXPIRATION_TEN_MINS_IN_NANOSECONDS;
}
@Override
public long expireAfterRead(
String key, Boolean value, long currentTime, long currentDuration) {
// Don't modify expiration time after read
return currentDuration;
}
})
.recordStats()
.removalListener(removeListener)
.build(key -> keyExistsOnServer(key));
问题 #1: 根据我想要实现的目标,我的过期政策看起来是否正确?
问题#2:
我没有看到 RemovalListener
根据驱逐政策被召唤。这可能是由于 github issue.
但是,我的代码的正确性依赖于这样一个事实,即一旦条目的到期持续时间(false
值的情况下为 10 分钟)已经过去,如果我们调用 cache.get(key)
那么它应该不是 return 来自缓存的过期值,而是调用 CacheLoader
即 keyExistsOnServer(key) 方法来获取值。有人可以断言这就是它的行为方式吗?
这是@Louis Wasserman 在 github 问题上的陈述,但我不清楚这是否说明了问题:
Actually, what happens is that the get call itself discovers that the entry is expired and adds it to the queue of entries to be cleaned up
问题#3: 如果 CacheLoader
抛出 RuntimeException
会发生什么,即 keyExistsOnServer(key) 方法调用 cache.get(key)
?
问题#4:cache.asMap()
是否会包含已过期但未因清除应计而被逐出的条目?
问题#5: 当我在 expireAfterRead()
方法中记录 currentDuration
时,它似乎与经过的时间不一致。也就是说,如果它被设置为 600000000000(10 分钟)并将值更新为 false
我预计 5 分钟后它应该是 300000000000 但事实并非如此。为什么会这样?
Question#1: Does my expiration policy looks correct based on what I want to achieve?
是的,这看起来不错。您可以将常量设置为 Duration
或使用 TimeUnit
进行计算,只是为了让它看起来更漂亮。
Question#2: I do not see the RemovalListener getting called as per the eviction policy.
当缓存 activity 足够时,就会发生这种情况。您可以指定一个 Scheduler
,它将根据下一个条目设置为过期的时间唤醒并为您调用 cache.cleanUp
。对于 Java 9+ 用户,Java 提供了一个内置的调度线程,您可以在构建缓存时通过添加 Caffeine.scheduler(Scheduler.systemScheduler)
来利用它。
Once the expiration duration has passed for an entry and if we call cache.get(key) then it should not return the expired value from cache, but rather call the CacheLoader.
正确。缓存将在查找时验证条目,如果过期,则重新加载它。它永远不会 return 过期条目。
Question#3: What happens if there is RuntimeException thrown by CacheLoader that is keyExistsOnServer(key) method on calling cache.get(key)?
映射将不会建立,异常将传播给调用者。下一次调用 get(key)
将重新尝试,这可能会再次失败。您可以选择如何对此保持弹性。通常不是这样是一个好的答案,或者有时缓存它失败是一个更好的答案。
Question#4: Would cache.asMap() contain the entries which are expired but were not evicted due to accrual for cleanup?
缓存将保留条目但禁止它们可见,例如通过查找或迭代。唯一的外部指示是 size()
,因为该计数器在删除过期条目之前不会更新。
Question#5: When I am logging the currentDuration in the expireAfterRead() method, it does not seem consistent with the elapsed time. i.e. if it was set to 600000000000 (10 mins) with an update for the value to false I am expecting that after 5 mins it should be 300000000000 but it was not. Why so?
请打开单元测试问题,我们可以诊断。