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).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.