архитектурное решениеобновлено 2026-08-20

Кэш коэффициентов: версии и безопасное обновление

TTL не знает, что рынок изменился секунду назад. Разбираем version fence, ключи snapshot-кэша, suspend-first и роль TTL как страховки, а не как основного механизма актуальности.

Иллюстрация к материалу: Кэш коэффициентов: версии, ключи и безопасная инвалидация
Derrick Coetzee / Wikimedia CommonsCC0 1.0

срок жизни не знает, что рынок уже изменился

Для быстро меняющихся коэффициентов истечение времени — плохая основная стратегия. Кеш должен обновляться событием с версией. TTL остаётся предохранителем на случай, если запись больше не получает обновлений, но не определяет актуальность.

Ключ — часть модели данных

Ключ snapshot должен включать область уникальности provider/internal event и market. Ошибка scope опаснее маленького TTL: данные одного варианта начинают перетирать другой. Формат ключа фиксируется как контракт и тестируется на коллизии на наборах реальных идентификаторов.

Одна запись на рынок или на событие

Event-level snapshot удобен для чтения одной страницы, но каждое изменение переписывает большой объект. Market-level уменьшает write amplification, зато сборка страницы делает больше reads. Выбор зависит от формы доступа; общий ответ без профиля чтения здесь бесполезен.

Барьер версии против запоздавшей записи

Каждое обновление несёт monotonically comparable version в рамках market. Cache writer меняет snapshot только если incoming version новее. Suspend имеет тот же versioning и не обходится отдельной «быстрой» веткой, иначе поздний price update может снова активировать уже закрытый рынок.

Старое значение, которое выглядит свежим

Если updated_at ставится временем записи в кеш, повтор старого события делает stale data «свежей». В snapshot нужно различать provider/event version time и local written_at. Диагностика должна видеть оба значения.

Проверка ключа кэша до рабочей среде

Cache key стоит рассматривать как часть доменной модели. Если в нём потерян provider, market type, segment или другая значимая размерность, разные snapshots могут попасть в одну ячейку и выглядеть абсолютно валидно по TTL. Это опаснее обычного cache miss, потому что система отдаёт правдоподобно свежие, но чужие данные.

До запуска полезно выписать все измерения, которые влияют на identity объекта, и проверить cardinality на реальном каталоге. Version fence добавляет вторую защиту: запоздавшая запись с меньшей версией не должна перетирать более новый snapshot даже при корректном ключе.

  • Покрыть ключ unit-тестами на соседних рынках и provider-сценариях.
  • Логировать version и generated_at вместе с cache hit.
  • Использовать TTL как страховку, а не как основной сигнал актуальности.

Проверка ключ кэша начинается с вопроса «что может измениться независимо?»

Если один market может suspend, пока соседний остаётся live, общий cache key на всё событие увеличивает blast radius. Если данные всегда читаются комплектом и обновляются одной версией, слишком мелкий key, наоборот, создаёт лишнюю координацию. Граница кэша должна следовать модели изменений, а не удобству сериализации.

Главный guardrail — version fence. Запоздавшая запись не получает право перезаписать более новую только потому, что пришла позже в wall-clock времени. Для LiveOddsTile это означает простое правило: компонент читает market state с версией и freshness, а внутреннее устройство cache остаётся за API.

Перед production полезен тест с переставленными ответами: сначала записать version 42, затем искусственно задержать version 41 и убедиться, что старая запись отвергнута.

Распределение возраста данных по активным рынкам

Полезно контролировать не средний age всех ключей, а распределение по активным live-market и отдельный count ключей без изменений дольше ожидаемого. На дежурстве это быстро показывает остановку конкретного сегмента потока.

Схема решения: Кэш коэффициентов: версии, ключи и безопасная инвалидация
Диаграмма к разбору: Кэш коэффициентов: версии, ключи и безопасная инвалидация.
Следующий слой

Связанные разборы по той же архитектурной цепочке

Букмекерская логика

Поток коэффициентов и событий: путь данных от поставщика до экрана

Из каких участков складывается доставка коэффициента в реальном времени и где появляются очереди, рассинхронизация и устаревшие данные.

Перейти к разбору →
Надёжность

Как искать узкие места в потоковой спортивной системе

Как сравнивать участки потоковой системы по задержке, очередям и потерям данных, чтобы не оптимизировать участок, который не влияет на пользователя.

Перейти к разбору →
Архитектура

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

Как связать счёт, таймер и фазы матча в модель состояний, обрабатывать поздние сообщения поставщика и не допускать невозможных переходов.

Перейти к разбору →
Букмекерская логика

Кнопка коэффициента: доступность, изменение цены и приостановка

Как проектировать кнопку коэффициента: изменение цены, приостановка, фокус, клавиатурное управление и понятные состояния после выбора пользователя.

Перейти к разбору →