Кофеин AsyncLoadingCache и гремит стадо - PullRequest
0 голосов
/ 18 марта 2020

Предотвращает ли .get () в Caffeine AsyncLoadingCache параллельные загрузки, задерживая последующие потоки, вызывающие .get (), до завершения первого из них? Или что он может быть настроен на возврат устаревшего значения во время выполнения самонаполняющегося запроса на загрузку?

Это так, что с помощью кэша можно предотвратить гремящее стадо.

Я наблюдение за поведением, которое указывает на то, что громоподобное стадо не обрабатывается, даже если я использую кеш.

Я создаю кеш следующим образом:

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

И использую его вместе с кешем L2 в redis, например, так (kotlin оператор elvis):

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

Я понимаю, что getIfPresent является параллельным, но последующие вызовы, которые в конечном итоге вызывают fetchFromRedis () / get (), имеют проблемы. Я предполагаю, что перемещение fetchFromRedis в функцию asyncLoad() может быть лучше для допуска нагрузки.

1 Ответ

0 голосов
/ 19 марта 2020

При загрузке через кеш поддерживается паническое бегство кеша. В вашем примере, используя getIfPresent и загружая значение, я предполагаю, что вы явно поместили его в кеш внутри fetchFromRedis. В любом случае, вы гарантируете быстрое получение загрузки из-за обхода кэша, за исключением случаев отсутствия в Redis.

Если вы переместите логи c в asyncLoad, как вы и предполагали, это позволит кеш-дескриптор давки. Поиск redis, запрос базы данных и сохранение обратно в redis могут выполняться как цепочка асинхронных задач, в которых окончательное будущее возвращается к asyncLoad. Затем кэш будет вычислять будущее один раз и возвращать его всем последующим вызовам, пока запись не будет удалена.

...