Skip to content

Политика работы с Redis‑кэшем ​

Документ описывает, как мы именуем, наполняем и очищаем Redis в проекте MARV. Соблюдайте единые правила — это избавляет от конфликтов и непредсказуемых очисток.


1. Пространства ключей ​

ПрефиксНазначениеПримерОчищается при старте
marv:cache:*Волатильные данные, которые можно удалятьmarv:cache:users:1:12345Да, полностью
marv:persist:*Очереди/служебные флаги, которые должны жить долгоmarv:persist:updates:users:42Нет
  • cachekeys.Normalize переписывает только устаревшие cache:* ключи в marv:cache:*; ключи с префиксом marv: пропускаются как есть, любые другие строки остаются без изменений (функция не оборачивает произвольные строки в namespace).
  • Всё, что должно переживать рестарт, хранится под marv:persist:*.

2. Сборка ключей (pkg/cachekeys) ​

  • Build(parts ...any) — собирает ключ в marv:cache:<parts...> (разделитель :).
  • Normalize(key string) — нормализует legacy-ключи (см. ниже).
  • Паттерны для SCAN/KEYS собираются тем же Build, где последним сегментом идёт "*" (например Build("messages", "unread", "*")).
  • Для персистентных структур есть отдельные хелперы: UserUpdatesKey / UserUpdatesPattern, UserDataQuarantineKey / UserDataQuarantinePattern, UserDataQuarantineAlertKey, OnlineUsersKey, SessionsDayKey, LeaderElectionKey.

Правило: никаких ручных конкатенаций строк — только cachekeys.


3. Очистка при запуске ​

  • Конфиг app.cache_clear.enabled (по умолчанию true) включает/выключает очистку.
  • application/container.Container.clearVolatileCaches:
    1. Удаляет весь marv:cache:* (через cachekeys.Build("*")).
    2. Обрабатывает app.cache_clear.patterns. Строки без marv: автоматически оборачиваются в cachekeys.Build(...).
  • Пространство marv:persist:* не затрагивается.

Пример настройки:

yaml
app:
  cache_clear:
    enabled: true
    patterns:
      - "marv:cache:legacy_service:*"
      - "tmp:*" # станет marv:cache:tmp:*

4. Семейства кэшей ​

Пользователи ​

  • marv:cache:users:<api_type>:<api_uid>
  • marv:cache:users:by_operator_email:<email>
  • Инвалидация: все операции domain/services/users, плюс глобальная очистка.

Миры ​

  • marv:cache:worlds:<user_id>:<type> (<user_id> — внутренний числовой ID пользователя)
  • Очищается репозиторием миров и при рестарте.

Remote Configs ​

  • marv:cache:remote_configs:<api_type> (включая global)
  • Инвалидация при create/update/delete и на старте.

Сообщения ​

  • marv:cache:messages:unread:<user_id> (<user_id> — внутренний числовой ID пользователя)
  • marv:cache:messages:operator_stats — счётчики почты ACP по статусам и типам (полный проход по таблице). TTL 30 секунд; чистится при каждой записи сообщения из ACP. Игрок, открывший личное письмо, доходит до счётчика за TTL.
  • Чистятся при доставке сообщений и глобальной очисткой.

События / Event Results ​

  • marv:cache:events:active:<YYYYMMDD>
  • marv:cache:events:lookback:<YYYYMMDD>
  • marv:cache:events:starting:<YYYYMMDD>:<YYYYMMDD> (диапазон from:to)
  • marv:cache:event_results:table:<event_id>:<group>:<group_num>:<with_data>
  • Инвалидация в сервисах + при рестарте.

Потоки и live inputs ​

  • marv:cache:streams:list, marv:cache:streams:id:<id>
  • marv:cache:stream_inputs:<user_id>:<stream_id> (<user_id> — внутренний числовой ID пользователя)
  • marv:cache:stream_inputs:list:<user_id>
  • Очищаются сервисами Streams/Inputs и при старте.

Traffic Flow ​

  • marv:cache:traffic_flows:*
  • marv:cache:traffic_flow_entries:<user_id> (<user_id> — внутренний числовой ID пользователя)
  • Инвалидация при любых мутациях и при рестарте.

Rivals ​

  • marv:cache:rivals:<user_id> (<user_id> — внутренний числовой ID пользователя)
  • Чистится при справочных операциях и при запуске.

Transactions ​

  • marv:cache:transactions:<api_type>:<api_uid>
  • Удаляется после завершения транзакции и на старте.

Ads ​

  • marv:cache:ads:enabled
  • Инвалидация при любой операции над объявлениями + общий вайп.

Эксперименты (A/B) ​

  • marv:cache:experiments:list — полный список экспериментов.
  • marv:cache:experiments:<id> — эксперимент по ID.
  • Инвалидация при create/update/delete/toggle, изменении назначений и на старте. Оба ключа известны по имени и удаляются напрямую, без SCAN: путь вступления в эксперимент проходит по ним на каждом назначении.
  • Выборка включённых экспериментов, группы, счётчики и назначения не кэшируются: по ним под блокировкой строки принимается решение о вступлении, и устаревшая копия продолжала бы набирать в выключенный или отредактированный эксперимент.

Кланы ​

  • marv:cache:clan:id:<clan_id> — клан по ID.
  • marv:cache:clan:member_by_user:<user_id> — членство игрока (<user_id> — внутренний числовой ID).
  • marv:cache:clan:roster:<clan_id> — ростер клана.
  • marv:cache:clan:req_count:<clan_id> — число заявок на вступление.
  • marv:cache:clan:requests:<clan_id>:<status> — заявки клана по статусу.
  • marv:cache:clan:count:<side>:<world> — число кланов для лидерборда: <side> — сторона мобильного разделения (all, mobile, other), <world> — мир кланов (all, normal, shadow).
  • TTL 30 секунд: эти чтения делят кэш с мутационными путями, поэтому кэш намеренно короткоживущий.
  • Инвалидация — на каждой мутации ростера/заявок, плюс общая очистка на старте. Счётчик кланов не инвалидируется: создание, роспуск и смена мира клана доходят до него за TTL.

Клановый чат ​

  • marv:cache:clan_chat:cd:<user_id> — счётчик минимального интервала между сообщениями (TTL = domain.clan_chat.send_min_interval).
  • marv:cache:clan_chat:burst:<user_id>:<минута unix-времени> — окно burst-лимита за минуту (TTL 70 секунд).
  • Оба ключа ведёт рейт-лимитер ClanChatService; сами сообщения не кэшируются.

Клановые войны ​

  • marv:cache:war:active:<clan_id> — активная война клана.
  • marv:cache:war:id:<war_id> — война по ID.
  • marv:cache:war:member:<war_id>:<api_type>:<api_uid> — участник войны.
  • marv:cache:war:roster:<war_id>:<clan_id> — строки участников войны стороны (clan_war_members; строка появляется с первой атакой игрока).
  • marv:cache:war:phases:<war_id>, marv:cache:war:phase:<war_id>:<phase_index> — фазы войны.
  • marv:cache:war:beaten:<war_id>:<phase_index> — побеждённые цели в фазе.
  • marv:cache:war:rewards:<account_id> — награды игрока.
  • marv:cache:war:final:<war_id> — финал войны.
  • TTL 15 секунд. Статус боя (attack reserve/resolve) не кэшируется вообще — он меняется на каждой атаке.
  • Инвалидация — на продвижении фаз, атаках, начислении наград и роспуске клана. Уход игрока из клана сбрасывает только записи его удалённых строк участника (war:member и war:roster этих войн): вклады не кэшируются, тали фаз не меняются.

Ограничения аккаунта ​

  • marv:cache:restrictions:active:<user_id> — действующие ограничения аккаунта (кэшируется и пустой набор: глобальный бан проверяется на каждом запросе).
  • TTL 5 минут, но не дальше ближайшего until в наборе — истёкшее ограничение не переживает свой срок в кэше.
  • Инвалидация — на выдаче и снятии ограничения и при слиянии аккаунтов. Запись при этом ставит метку marv:cache:restrictions:active:<user_id>:chg на 10 секунд: чтение, начатое до записи, не кладёт в кэш набор, прочитанный до неё.

Планировщик ​

  • marv:cache:scheduler:manual_run:<tag> — очередь ручных запусков leader-only задач (нелидер кладёт тег, лидер вычитывает и выполняет). TTL 10 минут.

5. Персистентные ключи (не очищаются) ​

  • marv:persist:updates:users:<user_id> — очередь отложенных обновлений (читается задачей user_data_batch_update).
  • marv:persist:quarantine:user_data:<user_id> — сейв, который БД отказалась принять (невалидный UTF-8, NUL-байт, либо отбитая построчная запись). Хранит сам payload и диагностику: смещение и значение битого байта, окно вокруг него, текст ошибки БД. TTL — domain.user_updates.quarantine_ttl (по умолчанию 30 дней). Кладут UserService (на приёме) и задача user_data_batch_update; ключ из очереди при этом не удаляется.
  • marv:persist:quarantine:alerted:<user_id> — маркер дедупликации алертов по карантину, TTL domain.user_updates.quarantine_alert_window (по умолчанию 24 часа). Нужен, чтобы навсегда сломанный сейв не поднимал алерт на каждом прогоне крона.
  • marv:persist:leader[:suffix] — ключи выборов лидера (реализация — общий модуль shared/leader, ключ строит LeaderElectionKey из pkg/cachekeys; значение = app.server.id).
  • marv:persist:online_users — sorted set присутствия: member — id пользователя, score — время его последнего аутентифицированного запроса (V1 и V2) или логина в unix ms. Пользователь онлайн, пока это время моложе app.online_ttl (по умолчанию 5 мин). OnlineTracker считает онлайн одним ZCOUNT по score, без обхода ключей. Ушедших из набора убирает ZREMRANGEBYSCORE — каждый процесс не чаще раза в минуту, на очередной отметке; на счёт это не влияет, только на размер набора. Каждая отметка продлевает ключу PEXPIRE на TTL, так что у игры без запросов набор исчезает сам. Команд sorted set в CacheStore нет, поэтому трекер ходит через Eval однострочными Lua-скриптами.
  • marv:persist:sessions:<YYYY-MM-DD> — счётчик сессий за день. Инкрементируется (INCR) при каждом успешном /v2/login. TTL устанавливается до конца следующего дня при первом инкременте.
  • Любые другие долгоживущие структуры размещайте здесь, если их нельзя терять на рестарте.