Caffeine AsyncLoadingCache 和 thundering herd

Caffeine AsyncLoadingCache and thundering herd

Caffeine AsyncLoadingCache 上的 .get() 是否通过延迟调用 .get() 的后续线程直到第一个线程完成来防止并发加载?或者它可以配置为 return 一个过时的值,同时发生自填充加载请求?

这样可以通过使用缓存来防止雷群。

我看到的行为表明即使我正在使用缓存也没有处理雷鸣般的群。

我这样创建缓存:

val queryResponseCache: AsyncLoadingCache<Request, Response> = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .recordStats()
            .buildAsync(queryLoader)

并将它与 redis 中的 L2 缓存结合使用(kotlin elvis 运算符):

queryResponseCache.getIfPresent(key) ?: fetchFromRedis(key) ?: queryResponseCache.get(key)

我知道 getIfPresent 是并发的,但最终调用 fetchFromRedis() / get() 的后续调用似乎有问题。我想将 fetchFromRedis 移动到 asyncLoad() 函数中可能更适合负载容限。

通过缓存加载时支持缓存踩踏。在您使用 getIfPresent 并加载值的示例中,我假设您将它显式放入 fetchFromRedis 内的缓存中。无论哪种方式,由于绕过缓存,除非在 Redis 中不存在,否则您将确保一个活泼的 get-load-put。

如果您将逻辑移至 asyncLoad,如您所料,它会让缓存处理踩踏事件。 Redis 查找、数据库查询和存储回 Redis 都可以作为异步任务链执行,其中最终的未来是 returned 到 asyncLoad。然后缓存将计算一次未来,并return所有后续调用,直到条目被逐出。