⚡️Cache stampede



Представим, код метода getData() выглядит так



def getData():

dataFromCache = getFromCache()

if dataFromCache:

return dataFromCache

dataFromDb = getFromDb()

updateCache(dataFromDb)

return dataFromDb




Что произойдет если два потока почти одновременно не найдут данные в кеше? Пойдут загружать из БД



А если 100 потоков?



Понять масштабы можно на таком примере:

- В кеш может поступать до 300 запросов в секунду

- Время загрузки из бд — 2 секунды



И получается, если ключ в кеше протухнет, то за первые две секунды в базу попрутся 600 параллельных тяжелых запросов. Учитывая, что из-за этих запросов БД может деградировать, запросы могут начать выполняться еще дольше



---



Что с этим делать?



1. Локи



В примере выше хорошо бы зашел double-checked locking



def getData():

dataFromCache = getFromCache()

if dataFromCache:

return dataFromCache

withLock {

dataFromCache = getFromCache()

if dataFromCache:

return dataFromCache

dataFromDb = getFromDb()

updateCache(dataFromDb)

return dataFromDb

}




Можно конечно сразу лочить, но тогда для подавляющего большинства запросов добавится лишний оверхед. А в случае дабл чека будет лочиться только когда кеш протух



2. Прогрев кеша / фоновые апдейты



Если уверены, что значение скорее всего понадобится, то просто заранее его туда положите и в фоне обновляйте. Если будет всплеск нагрузки, в кеше уже будет все что нужно



3. Вероятностные рефреши



Есть еще техника, когда кеш обновляется с некоторой вероятностью, даже если значение еще не протухло. Это может быть полезно, если полностью прогреть кеш невозможно, но вероятность cache stampede хочется снизить



---



Пишите в комментах, что из этого используете)