Перейти к содержанию

ADR-0004 · Кэш схемы зала#

Статус:    принят · 2026-09-16
Метод:     D-03 v1.0 · шаблон ADR v1.1
Участники: команда разработки (4 человека)

Учебная запись: часть прогона E-01, система вымышлена. Форма и рассуждение настоящие.

Короткая запись#

Решение:     локальный кэш в процессе, TTL 1 с, без инвалидации,
             с защитой от лавины (single-flight на ключ)
Основание:   пик 8 000 чтений/с против 300 записей/с, один горячий ключ
             на событие, допустимая устарелость 5 с [расчёт W1]
Отклонения:  умолчание («cache-aside + удаление ключа при записи»)
             отвергнуто: 300 записей/с обнуляют ключ быстрее, чем он
             успевает использоваться
Вернуться:   hit ratio ниже 95 % на горячем ключе, доля устаревших
             ответов выше допустимого, p99 чтения выше 200 мс
Метод:       D-03 v1.0

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

Почему умолчание не подошло#

D-03 предлагает умолчание: cache-aside плюс удаление ключа при записи, короткий TTL как страховка. Для этого кэша оно неработоспособно.

Схема зала — один ключ на событие. В момент старта продаж по нему идёт 8 000 чтений/с и 300 записей в ту же схему [расчёт W1]. Удаление ключа при записи означает, что ключ живёт в среднем 3 мс: он инвалидируется быстрее, чем успевает быть использованным. Hit ratio стремится к нулю, а к нагрузке на БД добавляется лавина одновременных пересчётов.

Правильное отклонение — не инвалидировать вовсе, а положиться на короткий TTL и принять устарелость. Это допустимо, потому что интерфейс и так обязан обрабатывать «место только что заняли» как штатный исход (CASE-08): устаревшая схема не создаёт нового класса ошибок, она лишь делает уже существующий чуть более частым.

Такой строки в таблице отклонений D-03 нет. Её отклонения — про стратегии записи (write-through, write-behind, write-around, refresh-ahead) и про размещение (локальный, CDN). Развилки «инвалидация против короткого TTL», главной для читающего кэша над быстро меняющимися данными, в документе не оказалось.

Почему локальный, а не общий#

Ключ один и горячий — это худший случай для общего кэша (CACHE-04): весь пик приходит на один узел. Локальная копия в каждом экземпляре приложения снимает и сетевой участок, и перекос. Цена — расхождение между экземплярами в пределах TTL, то есть до секунды; при допустимых пяти это в бюджете.

Холодные события обслуживаются тем же механизмом: их читают редко, промах стоит один запрос к БД, отдельный общий кэш ради них заводить незачем.

Дисквалификатор сработал и выдавил наружу отдельное решение#

D-03 отсекает кэш, без которого система не переживает собственного отказа. Проверка: при пустом кэше 8 000 запросов/с уходят в PostgreSQL, который в этот момент обслуживает 300 конкурентных записей с блокировками строк. Не переживёт.

Значит кэш здесь — несущий элемент, и по правилу D-03 его нельзя вводить, пока не спроектирована деградация (REL-04). Форма деградации: при недоступности кэша отдавать схему грубо — «в этом секторе есть места» вместо поимённой занятости, — а точность проверять в момент резерва, где она и так проверяется транзакцией.

Само проектирование деградации — отдельное решение, которого в наборе нет. Оно продуктовое (меняет то, что видит пользователь), не обратимое одним коммитом и принимается на W7. Здесь оно только названо как обязательное условие; пока оно не принято, кэш вводить нельзя.

Что придётся построить#

  • Single-flight на пересчёт ключа: без него первое же истечение TTL на горячем событии даст 8 000 одновременных запросов к БД (CACHE-04).
  • Прогрев перед стартом продаж. Пики известны по расписанию — это редкая роскошь, и не пользоваться ею странно.
  • Метрика доли устаревших ответов: сверка выборкой, иначе устарелость станет неизмеримой.
  • Деградация до грубой схемы — по отдельному решению, до ввода кэша в строй.

Условия пересмотра#

Срок не назначается: решение обратимо, его пересматривает метрика.

Показатель Вернуться, когда
Hit ratio на горячем ключе Ниже 95 % — TTL слишком короткий или ключ не тот
Доля устаревших ответов Выше согласованного с продуктом порога
p99 чтения схемы Выше 200 мс — кэш не решает задачу
Нагрузка на БД при холодном кэше Показывает, что деградация не работает
Расхождение между экземплярами Стало заметно пользователю — TTL великоват

Связанные ADR#

Зависит от: ADR-0001 (источник истины), ADR-0002 (путь чтения оставлен внутри монолита и решается кэшем, а не границей). Блокирует: ввод кэша в строй до принятия решения о деградации.