java - LoadingCache停止自动刷新并仅提供陈旧数据

标签 java scala caching guava

我正在使用 LoadingCache:

val cacheloader = 
new CacheLoader[Key, Value]() {
  override def load(key: Key): Value = loadKeyFunc(key, None)
  override def reload(key: Key, prevValue: Value): ListenableFuture[Value] = {
    val task = ListenableFutureTask.create(new Callable[Value]() {
                                              def call(): Value = {
                                                loadKeyFunc(key, Some(prevValue))
                                              }
                                           })
    executor.execute(task)
    return task
  }
}

val cache: LoadingCache[FirstPageSearch, Array[String]] =
                   CacheBuilder.newBuilder()
                               .maximumSize(10)
                               .refreshAfterWrite(5, TimeUnit.MINUTES)
                               .build(cacheLoader)

loadKeyFunc 只是一个 val loadKeyFunc: (Key, Option[Value]) => Value 形式的匿名函数。 cacheLoader 使用执行器 (Executors.newFixedThreadPool(6)) 来使刷新异步。 系统接收到的 HTTP 请求始终会经过此缓存(向缓存发出 get(key)),并始终从缓存中获取结果。当它太旧时,它会在后台重新计算并在下一个请求时提供它。

几天甚至几周内一切正常。但有时(通常是在非常低的使用时间内)缓存会停止刷新。新请求开始接收始终相同的旧数据。我在 loadKeyFunc 中有一个日志语句,我知道它没有被调用。

由于某种原因,LoadingCache 似乎没有看到数据早于 5 分钟。 当我重新启动系统(HTTP服务器)后,一切又恢复正常了。

有什么想法吗?

PS:我们使用的 loadKeyFunc 只是一个简单的日志语句,然后调用一个无状态对象,该对象查询我们的搜索后端系统,返回一个字符串数组(每个数组位置都是一个搜索页面)。

PS2:它是一个基于 Scalatra 的运行嵌入式 Jetty HTTP 服务器。 LoadingCacheScalatraServlet 对象内创建。

一个小的清理日志(/first_page是始终使用缓存的请求,“Executing...”是CacheLoader的(re)load方法内的日志语句) :

[INFO] [qtp48202314-8659] 2012-11-03 04:55:58 - Request(/first_page)
[INFO] [pool-2-thread-10] 2012-11-03 04:55:58 - Executing FirstPageSearch to put in cache
[INFO] [qtp48202314-8659] 2012-11-03 05:19:17 - Request(/first_page)
[INFO] [qtp48202314-8659] 2012-11-03 05:20:32 - Request(/first_page)
[INFO] [qtp48202314-8661] 2012-11-03 05:25:22 - Request(/first_page)
[INFO] [qtp48202314-8659] 2012-11-03 05:26:09 - Request(/first_page)
[INFO] [qtp48202314-8659] 2012-11-03 05:26:18 - Request(/first_page)
[INFO] [qtp48202314-8661] 2012-11-03 05:38:37 - Request(/first_page)
[INFO] [qtp48202314-8659] 2012-11-03 06:54:36 - Request(/first_page)
[INFO] [qtp48202314-26]   2012-11-03 11:31:37 - Request(/first_page)
[INFO] [pool-2-thread-1]  2012-11-03 11:31:37 - Executing FirstPageSearch to put in cache
[INFO] [qtp48202314-25]   2012-11-03 11:41:53 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 14:48:58 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 14:54:45 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:31:32 - Request(/first_page)
[INFO] [qtp48202314-26]   2012-11-03 15:31:48 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:32:05 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:44:44 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:44:44 - Request(/first_page)
[INFO] [qtp48202314-26]   2012-11-03 15:47:39 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:51:20 - Request(/first_page)
[INFO] [qtp48202314-26]   2012-11-03 15:52:59 - Request(/first_page)
[INFO] [qtp48202314-8674] 2012-11-03 15:54:18 - Request(/first_page)
[INFO] [qtp48202314-26]   2012-11-03 15:55:37 - Request(/first_page)

最佳答案

来自 CacheBuilder.refreshAfterWrite Javadoc:

Currently automatic refreshes are performed when the first stale request for an entry occurs. The request triggering refresh will make a blocking call to CacheLoader.reload(K, V) and immediately return the new value if the returned future is complete, and the old value otherwise.

因此,当某个值过时时,直到您实际查询该键时才会触发刷新,此时它将返回旧值并异步触发刷新。一旦该值完成刷新,它将开始从缓存返回。

您确定这不是您看到此行为的原因吗?

想到的另一种可能性是,由于某种原因,您的 loadKeyFunc 没有终止。在固定大小的线程池中,如果您有六个查询因任何原因而锁定,则可能会完全阻止新查询进入线程池,这似乎会导致您观察到的问题。也许您应该使用 Executors.newCachedThreadPool,这可以避免该问题 - 尽管您仍然会遇到由锁定线程引起的内存泄漏。 =/

关于java - LoadingCache停止自动刷新并仅提供陈旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13212153/

相关文章:

javax.resource.spi.work.ExecutionContext

java - 如何在 Java 中读取字符串化的 JSON 字符串

java - 如何在 Java 中执行命令并将其输出重定向到文件

java - 如何更新小程序的缓存?

Spring、Infinispan 和 JBoss 7 集成

node.js - Express + Request 中途更改 header

java - 我想将我的 jar 文件放入 html 代码中

java - 在 ORMLite 中为一个类创建多个表

scala - 编译 for 循环时出现奇怪的错误

Scala:将值写入类型安全的配置对象