Dog-pile эффект. Как отгонять стаи собак.
апреля 18, 2008 by ptchinkDog-pile эффект — ситуация когда кэш протухает, а большое количество запросов генерирует высокую нагрузку на источник данных, из которых строиться кэш.
Представьте, что вы кэшируете результат какого то тяжёлого запроса, например, список популярных статей. В какой-то момент времени кэш протухает, и его кто-то должен построить заново. В общем то пока все хорошо. Кроме случаев когда построение кэша тяжёлая операция, а запросов на него много. Например, запрос для генерации кэша занимает 1 секунду, а пользователи ломятся по 10 штуков в секунду. Соответственно, 9 пользователей (кроме первого) будут только зря нагружать базу. А при большом количестве запросов могут и полностью ее положить.
И пусть весь мир подождёт
Первое, что нужно решить — может ли пользователь ждать генерации кэша. Пример с популярными статьями это цветочки, ибо есть еще сложно рассчитываемые рейтинги, которые могут считаться оооочень долго.
Предположим, что у нас простой случай и пользователь не сломается, если подождёт секунду-другую.
Честные блокировки
Решение в лоб. Первый пришедший лочит кэш на запись и отправляется генерировать кэш. Остальные, увидев лок, понимают, что не успели, чешут репы и думают, что делать.
Как именно делать лок зависит только от вашей фантазии и имеющихся средств. Это может быть, что угодно:
- Лок файловой системы
- много косяков, но иногда работает :). Подробности в описании функции flock() .
- Мьютекс в хранилище
- Если мы используем memcache и генерируемый кэш имеет ключ «popular_articles», тогда наличие данных с ключем «popular_articles_lock», говорит о том, что наш кэш уже кто-то генерирует. Тоже самое спарведливо и для других хранилищ.
- IPC семафоры
- Настоящие пацанские семафоры ;) Ни разу не использовал — руки не доходят.
Плюсы локов в том, что клиент сам решает, что делать в ситуации, когда ему нужны данные, а их кто-то генерирует. Например, если есть старые данные, то мы можем их отдать, а если данных нет, то либо подождать, либо честно вывести пользователю, что данных нет. На самом деле висящие в течении секунды пользователи совсем не есть гуд, но иногда можно допустить и такое.
Так же не стоит забывать, что при генерации может возникнуть ошибка, и в этом случае лок может остаться висеть.
Организация «окна» для генерации
Способ был подсмотрен в исходниках какого-то фреймворка :)
Суть его в продлении ttl для генерируемого кэша. Т.е. приходит первый — продлевает ttl существующего кэша на какую-то заранее определённую величину, и начинает генерировать новое значение. Если писатель умирает, то кэш быстро снова протухнет и кто-нибудь подхватит знамя генерации с трупа павшего товарища. Если же все нормально, то будет записан новое значение кэша и установлен новый ttl.
Основной минус такого подхода — способ определения читателями момента, когда старых данных вообще не было, а новые кто-то уже генерирует. Если в подходе с локами этим признаком было отсутствие данных и наличие лока, то в данном подходе нужно что-то предопределённое запихивать в сам кэш.
Я хочу вас всех, я хочу вас сразу!
Случай у нас тяжёлый, и пользователю будет скучно коротать 20 секунд рисуя матом надписи на пыльном столе. Я знаю про кого будут эти надписи.
Главное откровение: чтобы избавиться от последствий многопоточности надо свести ее к одному потоку. Просто и со вкусом. Убираем всю генерацию кэша в оффлайн. ttl-ем в данном случае будет время перезапуска генерирующих кэш скриптов. Помимо быстрого ответа пользователю тут есть еще один плюс — наборы кэшей часто генерировать быстрее, чем каждый из них по отдельности, ибо можно хранить какие-то промежуточные данные.
Иcтoчник: Dog-pile эффект. Как отгонять стаи собак.
Posted in Новости |