当前位置: 代码迷 >> java >> 在Guava Cache对象上启用统计信息会有什么性能损失?
  详细解决方案

在Guava Cache对象上启用统计信息会有什么性能损失?

热度:22   发布时间:2023-07-25 19:25:30.0

显然,正确的答案是“基准测试并找出答案”,但本着互联网的精神,我希望有人能为我完成这项工作。

我非常喜欢Guava用于Web服务的缓存库。 然而,他们的文档在这一点上相当模糊。

recordStats
public CacheBuilder<K,V> recordStats()
在缓存操作期间启用的累积。 如果没有这个, Cache.stats()将为所有统计信息返回零。 请注意,记录统计信息需要对每个操作执行簿记,因此会对高速缓存操作造成性能损失。

以来:
12.0(之前,统计数据收集是自动的)

从JavaDocs for 。

我很好奇性能惩罚的严重程度是否由任何人记录,基准或停球。 我认为它应该是非常小的,每次操作的纳秒数量级。 缓存操作本身已经同步 - 读取不会锁定或阻塞,但写入会获取锁定 - 因此不需要额外的锁定或并发来修改统计信息。 这应该限制为每个缓存访问的一些额外的增量操作。

调用Cache.stats()时,它的另一面可能是一些惩罚。 我计划通过Codahale MetricsRegistry和Graphite服务器将统计信息暴露给持久记录。 净效应是定期检索统计数据,因此如果检索有任何阻塞行为,那可能会很糟糕。

让我们来看看 :

当我们调用CacheBuilder.recordStats()时会发生什么?

定义了一个无操作的实现 ,这是默认使用的。 如果你调用.recordStats() ,它将替换为 ,它有六个字段(通常是但如果它不能使用LongAdder回退到 ),用于它跟踪的每个统计数据。

那么当我们构造一个Cache时会发生什么?

对于标准 (这是从CacheBuilder.build()CacheBuilder.build(CacheLoader) ),它所需StatsCounter的实例。 Cache每个类似地获得的相同StatsCounter类型 。 其他Cache实现可以选择使用SimpleStatsCounter如果他们愿意,或提供他们自己的行为(例如,无操作实现)。

当我们使用Cache

LocalCache每次调用都会影响其中一个统计信息,调用相关的StatsCounter.record*()方法,这反过来会导致支持LongAddable的原子增量或添加。 LongAdderAtomicLong快得多,所以就像你说的那样,这应该是难以察觉的。 虽然在无操作的情况下StatsRecorder的JIT可以优化掉的record*()全部调用,这也许可以随着时间的推移明显。 但决定不在此基础上追踪统计数据肯定会 。

最后,当我们得到统计数据?

当您调用 , CacheStatsCounter及其所有Segments将在新的StatsCounter中 ,结果将返回给您。 这意味着将有最小的阻止; 每个字段只需要读取一次,并且没有外部同步或锁定。 这确实意味着技术上存在竞争条件(可以在聚合的中途访问一个分段),但实际上这是无关紧要的。

总结一下?

您应该在您感兴趣监视的任何Cache上使用CacheBuilder.recordStats() ,并尽可能频繁地调用Cache.stats() 内存开销大致保持不变,速度开销可以忽略不计(并且比您可能实现的任何类似监视更快), Cache.stats()的争用开销也是Cache.stats()

显然,一个专用线程除了在循环中调用Cache.stats()什么都不做会引起一些争用,但这很愚蠢。 任何类型的定期访问都将被忽视。

  相关解决方案