【问题标题】:Google Guava's CacheLoader loadAll() vs reload() semanticsGoogle Guava 的 CacheLoader loadAll() vs reload() 语义
【发布时间】:2012-04-14 12:43:38
【问题描述】:

我非常喜欢 Guava 11 的 CacheLoader(感谢 Google!)的两件事是 loadAll(),它允许我一次加载多个密钥,以及 reload(),它允许我在密钥“陈旧”时异步重新加载密钥" 但存在一个旧值。我很好奇它们是如何一起玩的,因为 reload() 只在一个键上运行。

具体来说,扩展CachesExplained的例子:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .maximumSize(1000)
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public Map<Key, Graph> loadAll(Iterable<? extends K> keys) {
           return getAllGraphsFromDatabase(keys);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (neverNeedsRefresh(key)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             return ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
           }
         }
       });

...其中“getAllGraphsFromDatabase()”执行聚合数据库查询,而不是长度(键)单个查询。

LoadingCache 的这两个组件如何协同工作?如果我对 getAll() 的请求中的某些键不存在于缓存中,它们将作为一个组与 loadAll() 一起加载,但如果有些需要刷新,它们是否会通过 load() 单独重新加载?如果是这样,是否有计划支持 reloadAll()?

【问题讨论】:

标签: java caching guava


【解决方案1】:

以下是清爽的工作原理。

可以通过两种方式触发缓存条目的刷新:

  1. 明确表示,cache.refresh(key)
  2. 隐含地,如果缓存配置为refreshAfterWrite,并且条目在写入后的指定时间后查询

如果查询到符合重新加载条件的条目,则返回旧值,并触发(可能是异步的)刷新。在刷新过程中,缓存将继续返回键的旧值。 (因此,如果 getAll 请求中的某些键符合刷新条件,它们的旧值将被返回,但这些键的值将(可能异步)重新加载。)

CacheLoader.reload(key, oldValue)默认 实现只返回 Futures.immediateFuture(load(key)),它(同步)重新计算值。如果您希望进行缓存刷新,建议使用更复杂的异步实现。

我认为我们目前不倾向于提供reloadAll。我怀疑这是可能的,但事情已经够复杂了,我认为我们倾向于等到我们看到对这种东西的具体需求。

【讨论】:

  • 我知道你们都在溢出,这就是为什么我想我会在这里问。谢谢!因此,如果我进行 getAll() 调用,我可能拥有三种类型的键。那些在缓存中存在(并且是新鲜的)的,那些根本不在缓存中的,以及那些存在的(并且准备好刷新的)。那些存在的从缓存中返回,那些不存在的通过我的 loadAll() 函数拉入,而那些存在于缓存中但准备刷新的则返回旧值,然后一一重新加载,异步?对吗?
  • 嗯,“一个接一个”和“异步”不会是我使用的术语,但我很确定你说得对。 (虽然元素会单独刷新,但它们的刷新会并发。)
  • 谢谢!有没有办法控制发生多少并发刷新,所以我不拒绝我的数据库?如果我向我的缓存询问 100 个键,我想避免在单个查询就足够时发出 90 个并行的单个数据库请求来刷新陈旧的值。
  • 当您实现reload 时,在具有固定线程数的ListeningExecutorService 上创建返回的ListenableFuture。这将限制并发执行的查询数量。
  • 仅供参考,我将向 Guava 提出问题,以确保它得到讨论。
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 2013-07-13
  • 2017-04-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-01
  • 2010-11-29
  • 1970-01-01
相关资源
最近更新 更多