Кеширование
Cache stampede: собрать и укротить стадо
Читать про stampede — не то же, что смотреть, как падает твоя БД, а потом возвращать её к жизни. Соберите небольшой cache-aside сервис, специально загоните горячий ключ в stampede и добавляйте митигации юнита слой за слоем — измеряя стадо до и после каждого.
Превратите ментальную модель юнита в воспроизводимый цикл: воспроизведите всплеск, инструментируйте отпечаток, затем наслоите single-flight, distributed lock, SWR, TTL-джиттер и negative caching — доказывая метриками, что каждый слой ограничивает то стадо, которое должен.
Соберите cache-aside HTTP-сервис на Redis и нарочито медленном origin, воспроизведите cache stampede на горячем ключе, затем наслаивайте митигации юнита, пока всплеск на границе TTL не достигнет origin как единственный rebuild — доказывая каждый шаг измерениями до/после, а не оценками.
- Таблица до/после на каждую митигацию: origin-запросы на границу TTL, p99 латентность запроса и rate промахов кеша — всё измерено под идентичным нагрузочным тестом, а не оценено.
- С включённым полным стеком граница TTL под устойчивой нагрузкой на горячий ключ даёт не более одного origin-rebuild, а пилообразный отпечаток origin-запросов исчез из метрик.
- Демонстрация, что single-flight в одиночку оставляет один rebuild на инстанс, и только добавление межнодового lock (или фонового обновления SWR) сворачивает его к одному на весь флот — доказывая, что вы понимаете область действия каждого слоя.
- Короткое описание: для каждого слоя назвать, какое именно стадо он ограничил (внутри процесса, всего флота, время ожидания, многоключевое, негативное) и почему этот слой понадобился поверх предыдущего.
- Реализуйте XFetch probabilistic early expiration на горячем ключе и покажите, что он обновляет до границы с ~1 ранним rebuild на окно и нулём промахов при истечении; затем покажите, что он проигрывает на холодном ключе, читаемом раз в TTL.
- Добавьте проверку fencing-token (или монотонной версии) на запись rebuild и сконструируйте тест, где EX lock'а короче медленного rebuild, доказав, что guard отвергает устаревшую дублирующую запись.
- Воспроизведите metastable failure: добавьте клиентские ретраи с коротким backoff, доведите origin до насыщения и покажите, что он остаётся прибитым после снятия нагрузки; затем разорвите цикл шлюзом 503-on-overload и измерьте время восстановления.
- Добавьте minimum-viable dashboard с алертами (всплеск rate промахов, пилообразный rate origin, lock-wait выше rebuild p99) и одностраничный on-call runbook: триаж по панелям, лестница митигаций и gate 'прогреть кеш до переключения трафика'.
Это цикл, который вы будете прогонять на любом реальном слое кеша: воспроизведите всплеск, прежде чем доверять фиксу, инструментируйте отпечаток, затем добавляйте митигации в порядке областей — single-flight для стада процесса, lock для стада флота, SWR для ожидания, джиттер для синхронного многоключевого истечения, negative caching для miss-storm — и проверяйте каждый числами до/после под идентичной нагрузкой. Сделать это раз на игрушечном сервисе — вот что превращает продакшен-версию и инцидент в 3 ночи в мышечную память.