Arhitectura evenimentului
Arhitectura evenimentului (EDA)
1) Ce este un eveniment și de ce EDA
Eveniment - un fapt neschimbător care a avut loc deja în domeniu ("PlayerVerified", "PaymentCaptured'). EDA construiește integrări în jurul publicării acestor fapte și reacțiile la acestea:- conectivitatea slabă a serviciilor
- scalarea independentă a consumatorilor
- reluarea/rearanjarea proiecțiilor,
- audit transparent.
EDA nu anulează API-urile sincrone - le completează prin aducerea dependențelor transversale în stratul asincron.
2) Tipuri de evenimente
Domeniu: fapte semnificative de afaceri (ComandaPlasat, BonusAcordat).
Integrare: „instantanee „/modificări pentru sistemele externe (UserUpdate, WalletBalanceChanged).
Tehnic: ciclul de viață și telemetrie (Heartbeat, PipelineFailed).
Comenzi (nu evenimente, ci în apropiere): instrucțiuni „do X” (CapturePayment).
Recomandare: evenimentele de domeniu sunt primare; integrarea este formată din proiecții pentru consumatori specifici.
3) Contracte de evenimente și scheme
Схема: Avro/Protobuf/JSON Schema + Schema Registry; strategia de compatibilitate: „ÎNAPOI” pentru evoluția consumatorilor, „COMPLET” pe subiecte critice.
CloudEvents (id, sursă, tip, timp, subiect, tip datacontenttype) - antete uniforme.
Metadate necesare: 'event _ id' (ULID/UUID),' happened _ at ',' producer ',' schema _ version ',' corelation _ id'/' causation _ id', 'idempotency _ key'.
Versioning: campuri add-only, interzicerea redenumirii/pauzelor semantice; tipuri noi - teme/tipuri noi.
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) Livrare, comandă și consistență
Cel puțin o dată ca idempotență implicită → handler este necesară.
Comanda: garantat în cadrul unei părți (Kafka) sau coadă (RabbitMQ), dar poate fi rupt prin retrageri; cheia de eveniment trebuie să reflecte un domeniu granule de ordine (de exemplu, "player _ id').
Consecventa: pentru bani/imprumuturi - numai prin reviste/sagas/compensatii; evita LWW.
Modelul de lectură: Proiecțiile și cache-urile pot fi eventuale - arată „actualizarea în curs de desfășurare”... și utilizează strategii RNOT pentru căi stricte.
5) Outbox/Inbox и CDC
Outbox: serviciul scrie un fapt bazei sale de date și tabelului outbox într-o singură tranzacție pe → lucrătorul o publică la autobuz.
Inbox: event _ id' with Consumer Stores' event _ id' with processing result for deduplication.
CDC (Change Data Capture): fluxul de modificări din baza de date (binlog/WAL) la magistrală pentru a construi integrări fără modificări ale aplicației.
Idempotency: procesarea prin 'idempotency _ key '/' event _ id', nu schimba lumea exterioară până la fix.
6) CQRS и Event Sourcing
CQRS: model separat de scriere și proiecții de citire; proiecțiile sunt construite din evenimente și pot rămâne în urmă.
Event Sourcing: agregate state = rollup of its events. Pro: audit complet/reluare; contra: complexitatea migrațiilor/schemelor/instantaneelor.
Practică: ES - nu peste tot, ci acolo unde istoria și compensațiile sunt importante; CQRS - aproape întotdeauna în EDA.
7) Sagas: Orchestrație și coregrafie
Orchestrație: coordonatorul trimite comenzi și așteaptă evenimente de răspuns; convenabil pentru procese complexe (KYC→Deposit→Bonus).
Coregrafie: serviciile reacționează la evenimentele celuilalt; mai ușor, dar mai greu de urmărit.
Definiți întotdeauna compensațiile și termenele limită.
8) Proiectarea topologiei (Kafka/RabbitMQ)
Kafka
Subiect pentru fiecare eveniment de domeniu: 'plăți. capturat. v1 ',' jucători. verificat. v1 '.
Cheie de partiționare: 'player _ id'/' wallet _ id' - unde ordinea este importantă.
"reaplicare. factor = 3 ',' min. insync. replici = 2 ', producător' acks = toate '.
Retenţie: în funcţie de timp (ex. 7-90 zile) și/sau compactare (ultima stare după cheie).
Subiecte pentru încercați din nou și DLQ cu backoff.
RabbitMQ
Schimburi: 'topic '/' direct', cheia de rutare 'plăți. capturat. v1 '.
Pentru un fan-out larg - 'topic' + mai multe cozi; pentru RPC/comenzi - cozi separate.
Cozi de cvorum pentru HA; TTL + schimb de scrisori moarte pentru retroactive.
9) Observabilitate și SLO EDA
SLI/SLO:- Latență end-to-end (occurred_at → prelucrate): p50/p95/p99.
- Lag/vârstă: lag de consum (Kafka consumer lag, Rabbit restanțe de vârstă).
- Prin publicare/procesare.
- Rata DLQ și proporția repetărilor.
- Succesul tranzacțiilor comerciale (ex. „depozit confirmat ≤ 5c”).
- Corelarea evenimentelor prin „trace _ id'/” corelation _ id' (OTel).
- Cazuri de aliniere → măsurători.
- Tablouri de bord „Producer→Broker→Consumer” cu alerte burn-rate.
10) Reluare, reținere și rambursare
Replay pentru a reconstrui proiecții/repara bug-uri: unitate la o nouă proiecție/spațiu, apoi comutați citirea.
Păstrare: Cerințe juridice/de afaceri (GDPR/PCI); câmpuri sensibile - criptare și/sau tokenizare.
Backfill: teme/cozi unice, limite RPS clare pentru a evita înăbușirea prod.
11) Siguranță și conformitate
TLS in-transit, mTLS pentru clienții interni.
Autorizatie: per-topic/per-exchange ACL; multitenancy prin namespace/vhost.
PII: minimizați câmpurile în eveniment; metadate plic separat, sarcini utile criptate, dacă este necesar.
Audit acces la evenimente, interzice „atotputernic” chei.
Păstrarea și dreptul de a șterge (GDPR) politici: fie stoca referințe de date sau evenimente de piatră funerară și șterge în proiecții.
12) Testarea în EDA
Teste contractuale: consumatorii își validează așteptările privind sistemele (bazate pe consumatori).
Teste de replay: rulați eșantionarea istorică printr-o nouă versiune handler/schema.
Scenarii haos: întârziere/pierdere broker, cădere nod, lag de consum → SLO rămân în cadrul.
Fum în CI: o scurtă conductă end-to-end pe teme de timp.
13) Migrarea „integrărilor CRUD → EDA”
1. Identificarea faptelor de domeniu.
2. Încorporați outbox în serviciile sursă.
3. Publicați evenimente minime de domeniu și conectați 1-2 proiecții.
4. Dezactivați treptat integrările sincrone ale punctelor, înlocuindu-le cu abonamente.
5. Type Schema Registry și o politică de compatibilitate.
6. Extinderea evenimentelor add-only cu câmpuri; pauze - numai prin noi tipuri.
14) Anti-modele
Evenimente = „DTO API” (prea gras, depinde de modelul intern) - sparge consumatorii.
Lipsa registrului schemei și a compatibilității - integrări „fragile”.
Publicarea din cod și scrierea în baza de date nu sunt atomice (fără outbox) - pierdeți evenimente.
„Exact o dată peste tot” - preț ridicat fără beneficii; mai bine cel puțin o dată + idempotență.
O cheie de partiție „universală” → o partiție fierbinte.
Replay direct în proiecția de producție - sparge SLO-uri online.
15) Lista de verificare a implementării (0-45 zile)
0-10 zile
Identificați evenimentele de domeniu și cheile lor (granule de comandă).
Implementați Registrul Schema și aprobați strategia de compatibilitate.
Adăugați outbox/inbox la 1-2 servicii; minimal CloudEvents-plic.
11-25 zile
Introduceți din nou/DLQ, backoff, idempotency de handlers.
Tablouri de bord: lag/age/end-to-end; alerte arde-rata.
Documentația evenimentului (catalog), proprietarii și procesele de revizuire a schemei.
26-45 zile
Replay/rearanjarea primei proiecții; runbook reluare și umplere din spate.
Politici de securitate (TLS, ACL, PII), retenție, proceduri GDPR.
Haos regulat și zile de joc pentru broker și consumatori.
16) Valorile maturității
100% din evenimentele din domeniu sunt descrise de scheme și înregistrate.
Outbox/inbox acoperă toți producătorii/consumatorii Tier-0/1.
SLO: p95 latență end-to-end și întârzierea consumatorilor în cadrul obiectivelor ≥ 99%.
Replay/Backfill sunt fezabile fără downtime; există cărți verificate și.
Versioning: domenii noi - fără rupere; consumatorii vechi nu sunt în scădere.
Securitate: TLS + mTLS, ACL pe subiect, jurnalele de acces, politica PII/retenție.
17) Mini fragmente
Kafka Producator (publicatie de incredere, idei):properties acks=all enable.idempotence=true max.in.flight.requests.per.connection=1 compression.type=zstd linger.ms=5
Manipulator de consum (idempotență, pseudocod):
python if inbox.contains(event_id): return # дедуп process(event) # побочные эффекты детерминированы inbox.commit(event_id) # atomically with side-effect commit_offset()
RabbitMQ Încercați din nou prin DLX (idee):
- „queue: tasks' → pe sarcinile nack → DLX”. încercați din nou. 1m (TTL = 60s) → întoarcerea la 'tasks'; mai departe „5m/15m”.
18) Concluzie
EDA transformă integrările într-un flux de fapte de afaceri cu contracte clare și coerență gestionată. Construiți fundația: scheme + registry, outbox/inbox, chei de ordine, manipulatori idempotente, SLO și observabilitate, păstrarea în siguranță și reluarea. Apoi, evenimentele vor deveni „sursa adevărului” pentru scalare, analiză și noi caracteristici - fără conexiuni fragile și migrații nocturne.