GH GambleHub

Событийная архитектура

Событийная архитектура (EDA)

1) Что такое событие и зачем EDA

Событие — неизменяемый факт, уже произошедший в домене (“PlayerVerified”, “PaymentCaptured”). EDA строит интеграции вокруг публикации этих фактов и реакций на них:
  • слабая связность сервисов,
  • масштабирование потребителей независимо,
  • реплей/перестройка проекций,
  • прозрачный аудит.

EDA не отменяет синхронные API — она дополняет их, вынося кросс-сервисные зависимости в асинхронный слой.


2) Типы событий

Доменные: значимые бизнес-факты (OrderPlaced, BonusGranted).
Интеграционные: “снимки”/изменения для внешних систем (UserUpdated, WalletBalanceChanged).
Технические: жизненный цикл и телеметрия (Heartbeat, PipelineFailed).
Команды (не события, но рядом): инструкции “сделай X” (CapturePayment).

Рекомендация: доменные события — первичны; интеграционные формируются проекциями для конкретных потребителей.


3) Контракты событий и схемы

Схема: Avro/Protobuf/JSON Schema + Schema Registry; стратегия совместимости: `BACKWARD` для эволюции потребителей, `FULL` на критичных темах.
CloudEvents (id, source, type, time, subject, datacontenttype) — единообразные заголовки.
Обязательные метаданные: `event_id` (ULID/UUID), `occurred_at`, `producer`, `schema_version`, `correlation_id`/`causation_id`, `idempotency_key`.
Версионирование: add-only поля, запрет переименований/семантических ломаний; новые типы — новые темы/типы.

Пример (Avro, фрагмент):
json
{
"type":"record","name":"PaymentCaptured","namespace":"events.v1",
"fields":[
{"name":"event_id","type":"string"},
{"name":"occurred_at","type":{"type":"long","logicalType":"timestamp-micros"}},
{"name":"payment_id","type":"string"},
{"name":"amount","type":{"type":"bytes","logicalType":"decimal","precision":18,"scale":2}},
{"name":"currency","type":"string"},
{"name":"player_id","type":"string"}
]
}

4) Доставка, порядок и согласованность

At-least-once как дефолт → необходима идемпотентность обработчиков.
Порядок: гарантируется внутри партиции (Kafka) или очереди (RabbitMQ), но может нарушаться при ретраях; ключ события должен отражать доменную гранулу порядка (например, `player_id`).
Согласованность: для денег/кредитов — только через журналы/саги/компенсации; избегайте LWW.

Модель чтения: проекции и кэши могут быть eventual — показывайте «идет обновление…» и используйте RNOT-стратегии для строгих путей.


5) Outbox/Inbox и CDC

Outbox: сервис пишет факт в свою БД и в таблицу outbox в одной транзакции → воркер публикует в шину.
Inbox: потребитель сохраняет `event_id` с результатом обработки для дедупа.
CDC (Change Data Capture): поток изменений из БД (binlog/WAL) в шину для построения интеграций без изменений приложения.
Idempotency: обработка по `idempotency_key`/`event_id`, не менять внешний мир до фиксации.


6) CQRS и Event Sourcing

CQRS: разделяем write-модель и read-проекции; проекции строятся из событий и могут отставать.
Event Sourcing: состояние агрегата = свертка его событий. Плюсы: полный аудит/реплей; минусы: сложность миграций/схем/снапшоты.
Практика: ES — не везде, а там, где важна история и компенсации; CQRS — почти всегда в EDA.


7) Саги: оркестрация и хореография

Оркестрация: координатор посылает команды и ждет событий-ответов; удобна для сложных процессов (KYC→Deposit→Bonus).
Хореография: сервисы реагируют на события друг друга; проще, но сложнее прослеживать.
Всегда определяйте компенсации и дедлайны шагов.


8) Проектирование топологий (Kafka/RabbitMQ)

Kafka

Топик per событие домена: `payments.captured.v1`, `players.verified.v1`.
Ключ партиционирования: `player_id`/`wallet_id` — там, где важен порядок.
`replication.factor=3`, `min.insync.replicas=2`, продьюсер `acks=all`.
Retention: по времени (напр. 7–90 дней) и/или compaction (последнее состояние по ключу).
Топики для retry и DLQ с backoff.

RabbitMQ

Exchanges: `topic`/`direct`, routing key `payments.captured.v1`.
Для широкого фан-аута — `topic`+несколько очередей; для RPC/команд — отдельные очереди.
Quorum Queues для HA; TTL + dead-letter exchange для ретраев.


9) Наблюдаемость и SLO EDA

SLI/SLO:
  • End-to-end latency (occurred_at → обработано): p50/p95/p99.
  • Lag/age: отставание потребителей (Kafka consumer lag, Rabbit backlog age).
  • Throughput публикации/обработки.
  • DLQ-rate и доля повторов.
  • Успех бизнес-операций (напр., «депозит подтвержден ≤ 5с»).
Практики:
  • Корреляция событий через `trace_id`/`correlation_id` (OTel).
  • Экземпляры (exemplars) из метрик → трассы.
  • Дашборды “Producer→Broker→Consumer” с burn-rate алертами.

10) Реплей, ретеншн и backfill

Реплей для перестроения проекций/исправления багов: гоняйте в новую проекцию/неймспейс, затем переключайте чтение.
Ретеншн: юридические/бизнес-требования (GDPR/PCI); чувствительные поля — шифруйте и/или токенизируйте.
Backfill: одноразовые темы/очереди, четкие лимиты RPS, чтобы не задушить прод.


11) Безопасность и комплаенс

TLS in-transit, mTLS для внутренних клиентов.
Авторизация: per-topic/per-exchange ACL; multitenancy через namespace/vhost.
PII: минимизировать поля в событии; envelope метаданные отдельно, полезные нагрузки шифровать при необходимости.
Аудит доступа к событиям, запрет «все-могущих» ключей.
Политики ретеншна и право на удаление (GDPR): либо храните ссылки на данные, либо tombstone-события и удаление в проекциях.


12) Тестирование в EDA

Contract tests: потребители валидируют свои ожидания схем (consumer-driven).
Replay-тесты: прогон исторической выборки через новый обработчик/версию схемы.
Chaos-сценарии: задержка/потери брокера, падение узлов, отставание потребителя → SLO остаются в рамках.
Smoke в CI: короткий end-to-end пайплайн на временных темах.


13) Миграция «CRUD-интеграций → EDA»

1. Идентифицируйте доменные факты.
2. Внедрите outbox в исходные сервисы.
3. Опубликуйте минимальные доменные события и подключите 1–2 проекции.
4. Постепенно отключайте точечные синхронные интеграции, заменяя их подписками.
5. Введите Schema Registry и политику совместимости.
6. Расширяйте события add-only полями; ломки — только через новые типы.


14) Анти-паттерны

События = “DTO API” (слишком жирные, зависят от внутренней модели) — ломают потребителей.
Отсутствие Schema Registry и совместимости — «хрупкие» интеграции.
Публикация из кода и запись в БД не атомарны (нет outbox) — теряете события.
“Exactly-once везде” — высокая цена без выгоды; лучше at-least-once + идемпотентность.
Один «универсальный» ключ партиционирования → горячая партиция.
Реплей прямо в прод-проекцию — ломает онлайновые SLO.


15) Чек-лист внедрения (0–45 дней)

0–10 дней

Определить доменные события и их ключи (гранулы порядка).
Развернуть Schema Registry и утвердить стратегию совместимости.
Добавить outbox/inbox в 1–2 сервиса; минимальный CloudEvents-envelope.

11–25 дней

Ввести retry/DLQ, backoff, идемпотентность обработчиков.
Дашборды: lag/age/end-to-end; burn-rate алерты.
Документация событий (каталог), owner’ы и процессы ревью схем.

26–45 дней

Реплей/перестройка первой проекции; runbook реплея и backfill.
Политики безопасности (TLS, ACL, PII), ретеншн, GDPR-процедуры.
Регулярные chaos-и game-days для брокера и потребителей.


16) Метрики зрелости

100% доменных событий описаны схемами и зарегистрированы.
Outbox/inbox покрывают все продьюсеры/консьюмеры Tier-0/1.
SLO: p95 end-to-end latency и consumer lag в пределах целей ≥ 99%.
Реплей/Backfill осуществимы без даунтайма; есть проверенные runbook’и.
Версионирование: новые поля — без ломок; старые потребители не падают.
Безопасность: TLS+mTLS, ACL per topic, журналы доступа, политика PII/ретеншн.


17) Мини-сниппеты

Kafka Producer (надежная публикация, идеи):
properties acks=all enable.idempotence=true max.in.flight.requests.per.connection=1 compression.type=zstd linger.ms=5
Consumer-обработчик (идемпотентность, псевдокод):
python if inbox.contains(event_id): return # дедуп process(event)            # побочные эффекты детерминированы inbox.commit(event_id)        # atomically with side-effect commit_offset()
RabbitMQ Retry через DLX (идея):
  • `queue: tasks` → on nack → DLX `tasks.retry.1m` (TTL=60s) → возврат в `tasks`; далее `5m/15m`.

18) Заключение

EDA превращает интеграции в поток бизнес-фактов с четкими контрактами и управляемой согласованностью. Постройте фундамент: схемы+реестр, outbox/inbox, ключи порядка, идемпотентные обработчики, SLO и наблюдаемость, безопасный ретеншн и реплей. Тогда события станут вашим «источником истины» для масштабирования, аналитики и новых фич — без хрупких связей и ночных миграций.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.