Общий кеш позволяет отвечать быстрее. Но как только тысячи потоков начинают читать и менять одни и те же значения, кеш из помощника превращается в главную причину падения системы.
Проблема: Thundering Herd (Cache Stampede)
Представь, что у тебя есть горячий ключ (например, список товаров на главной странице). Ты закешировал его на 10 минут. Все 10 минут запросы летают, база отдыхает. Но наступает момент, когда TTL истекает.
Сотни или тысячи запросов, пришедших в эту миллисекунду, не находят данные в кеше (Cache Miss). Все они одновременно идут в БД, чтобы сгенерировать данные заново. База ловит лавину тяжелых запросов, упирается в таймауты и система падает.
Как лечить Thundering Herd?
- Разноска (Jitter) TTL: Не ставь всем ключам ровно 10 минут. Добавь рандомный диапазон (±10%). Тогда ключи будут протухать постепенно, сглаживая нагрузку на БД.
- Блокировка: Когда кеш истек, первый процесс берет блокировку (lock) в Redis на этот ключ и идет в БД. Остальные процессы видят лок и либо ждут, либо отдают юзеру слегка протухшие данные (stale data), пока первый не обновит кеш.
- Раннее обновление: Фоновый процесс обновляет горячий ключ за 30 секунд до его реального протухания.
Проблема: конкурентность и гонки
Если два клиента параллельно прочитают из кеша число 100, прибавят 1 и запишут обратно, в кеше будет 101, а не 102 (классический Read-Modify-Write конфликт). Как это решают в распределенных системах?
| Стратегия | Ключевая идея (Аналогия) | Где применять |
|---|---|---|
| Оптимистическая (CAS) | Самообслуживание: пишем данные, только если версия в кеше не изменилась с момента нашего чтения. Если конфликт — повторяем попытку. | Лайки в соцсетях, счетчики просмотров (конфликты редки, операции быстрые). |
| Пессимистическая | Туалет с табличкой: жестко блокируем ключ перед чтением. Никто другой не может его даже прочитать, пока мы не закончим запись. | Бронь билетов, финансовые списания (крайне важна консистентность). |
| Lease (Аренда) | Прокат велосипеда: воркер берет ключ в эксклюзивную обработку с таймером. Если воркер упал — лок сам спадет по таймеру. | Обработка тяжелых аналитических отчетов фоновыми джобами. |
Частая ошибка: Блокировка без таймаута. Если сервис взял пессимистичный лок на запись и упал с OOM — ключ останется заблокированным навсегда (Deadlock). Всегда используйте TTL для блокировок!