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

C. Real-time Antifraud

Walkthrough · Раздел 02

Тип материала: учебный архитектурный сценарий. Не описывает систему конкретной компании.

Границы и предпосылки

Kafka4.1 / Flink1.20 → Redis7.4; Redis — serving projection, Flink managed state — источник window computation. Версии Kafka/Flink взяты как reference contracts раздела 01, совместный deployment не проверен. Financial decisions с денежным эффектом требуют authoritative durable transaction. HYPOTHETICAL; модель не описывает систему конкретной компании.

Архитектура

Все узлы и связи — HYPOTHETICAL.

flowchart TB
  Kafka --> Flink[Keyed state and event-time windows]
  Flink --> Checkpoint[Checkpointed state and offsets]
  Flink --> FeatureLog[Versioned feature snapshots topic]
  FeatureLog --> Sink[Retryable Redis sink]
  Sink --> Redis[Versioned TTL feature projection]
  Redis --> Decision[Risk decision with completeness policy]
  Request[Online requests] --> Limiter[Separate atomic admission ZSET]

Последовательность операций

  1. Kafka events имеют stable event_id, event time и partition ordering contract. Flink keyBy по tenant/player/device строит окна, задавая watermarks, allowed lateness и duplicate policy. Kafka identity сама по себе не удаляет semantic duplicates producer.

  2. Flink state/checkpoints согласуют вычисления и source offsets при настроенном checkpointing. Счётчик не отправляется в Redis как слепой INCR: при повторном sink write это задвоило бы эффект.

  3. Сформировать полный feature snapshot с монотонной per-key version и absolute expires_at. Для надёжной публикации feature topic нужен поддерживаемый transactional Kafka sink с его checkpoint contract; иначе explicitly at-least-once и idempotent downstream. Версия не должна сбрасываться после restore.

  4. Redis sink вызывает feature-upsert.lua: старые/равные versions игнорируются, TTL задаётся абсолютным deadline. Version хранится как fixed-width decimal string, чтобы избежать потери UInt64 precision в Lua number. JSON payload schema проверяется upstream.

  5. Отдельный sliding-window.lua реализует online admission limit через ZSET score=Redis server time, member=request_id. Удаляет scores <= now-window, проверяет duplicate, count, добавляет admitted request и TTL. Все keys одного script здесь — один key, что упрощает Cluster slot scope.

  6. Это processing-time rate limit, а не восстановление historical event-time fraud windows. Нормальная работа предполагает контролируемые clock jumps; async failover может потерять admissions. Для hard financial limit использовать authoritative transaction.

  7. Decision service читает feature version/window/completeness. При miss/stale/warm-up применяет заранее выбранную policy: manual review, reject либо bounded fallback. Отсутствие key не означает нулевой риск.

Failure modes и recovery

Сбой Поведение и восстановление
Redis write принят, ACK утрачен Повтор того же version snapshot безопасен при сохранённом version key; INCR был бы опасен.
Redis потерял state Rebuild в новой generation из checkpoint/feature history; переключить readers после completeness barrier.
Flink restart/replay Restore state+offsets; сохранить per-key versions/generation и отфильтровать obsolete windows.
Key expired и пришёл stale snapshot Одна Lua version уже не защищает: version tombstone исчез. Upstream ordering/deadlines/generation policy обязаны не допустить воскрешение.
Late event / source retention gap Allowed lateness policy или quarantine/recompute; если истории нет, отметить UNKNOWN completeness и применить degrade policy.

Trade-offs и эксплуатация

Полный snapshot дороже increment по bytes, зато даёт retry-safe replacement в определённом scope. Redis cache warm-up требует bounded нагрузку и barrier; Cluster не распараллеливает один player key. Dedup admission IDs хранится только внутри окна, это не пожизненная идемпотентность. Lua isolation не rollback и не durable exactly-once.

Код и границы проверки

sliding-window.lua и feature-upsert.lua. Lua compiled и выполнены ограниченные model checks command semantics; Redis/Flink/Kafka runtime, Cluster routing и failover не запускались. Модель не доказывает Redis persistence behavior.

Типичные ошибки проектирования

Обещать exactly-once по одному компоненту; не хранить stable identity/version; путать ACK, visible state и восстановимость; не учитывать replay/retention horizon. Таблица отказов задаёт обязательные сценарии дальнейшего тестирования.

Вопросы на собеседовании

Где заканчивается транзакционная гарантия? На явно указанной local/engine boundary. Все последующие projections требуют собственного delivery/retry/version contract и контроля полноты.

Практические упражнения

Проверьте duplicate retry до/после окна, deny без продления TTL, expired snapshot, reorder versions и state loss. В полноценной среде добавьте checkpoint recovery, lost ACK, clock step и Redis promotion; зафиксируйте полноту feature windows до открытия трафика.

Дополнительные источники

Общий отчёт проверок (архив рабочего проекта). Ни статическая проверка, ни model test не подтверждают production reliability.