Mesagerie tranzactionala
Mesageria tranzactionala este un set de tehnici arhitecturale care asigura coerenta intre schimbarile locale de stat (baza de date/cache) si mesajele de pe broker/autobuz. Scop: „starea este fixă ↔ mesajul nu este pierdut sau duplicat” în caz de eșecuri, retroys, scalare și multi-chirie.
1) Semantica de livrare
At-most-once: Rapid și ieftin, pierderi posibile, nu ia.
Cel puțin o dată: nu pierde mesajele, duplicatele sunt posibile → este necesară idempotența.
(Eficace) Exact o dată: nici o pierdere și nici o ia vizibile pentru efecte de afaceri, realizate printr-o combinație de tehnici (outbox/inbox, producător/tranzacții de consum, dedup).
2) De ce „două litere” este periculos
Logica naivă „scrie mai întâi la baza de date, apoi trimite la autobuz” (sau invers) pauze atunci când se încadrează între pași: datele sunt fixe, iar evenimentul este pierdut; fie evenimentul a dispărut, dar nu există date. Mesageria tranzactionala aduce acest decalaj.
3) Modele de bază
3. 1 Outbox (producător)
Într-o tranzacție locală, vom scrie schimbarea de afaceri și rândul la tabelul „outbox”; un editor separat citește outbox și publică într-un broker cu retras și backoff. Pierderi excluse; dublurile sunt stinse prin idempotență în rândul consumatorilor.
3. 2 Inbox/Consumator Idempotent
Înainte de executarea efectului, consumatorul face „INSERT” în „inbox (consumator, event_id)” ca cheie principală. Conflict cheie = eveniment deja procesat → săriți. Acesta este modul în care se realizează „exact-o dată”.
3. 3 Read-Process-Write cu tranzacția Offset
Șablon pentru autobuze orientate spre jurnal: consumatorul citește lotul, în aceeași tranzacție înregistrează schimbarea de afaceri și "offset trecut. "După comiterea, brokerul consideră mesajele consumate. Aceasta elimină „citire → cădere → repetare” fără duplicate în efect.
3. 4 TSS/Sagas pentru efecte interservicii
Când aveți nevoie de un proces consistent multi-pas, utilizați TCC sau sagas; mesaje - transportul comenzilor/evenimentelor şi tranzacţionalităţii - la nivelul etapelor şi compensaţiilor.
4) Producători și consumatori idempotenți
Producator: stabil 'message _ id'/' idempotency _ key', retrimiterea cu aceeasi cheie nu creeaza efecte noi pentru abonati; menține secvența de cheie.
Consumator: „inbox” + idempotenta afacerii (upsert/fuziune, verificare ultima versiune/revizuire).
5) Ordinea și cauzalitatea
Participați prin cheie de afaceri (de exemplu, 'agregate _ id',' tenant _ id'), astfel încât evenimentele unui obiect să sosească în ordine.
Păstrați numere consecutive/marcaje de timp în interiorul lotului; atunci când redesenarea de la DLQ, observați „prin cheie și secvențial”.
Dacă ordinea globală nu este critică, asigurați ordinea locală prin cheie și fixați invarianții de domeniu.
6) Compensări și efecte de fixare
Opțiunea A: „Offset în DB”
Scrieți „ultimul offset procesat (partiție, offset)” la aceeași tranzacție în care schimbați datele de domeniu. La repornire, continuați de la următorul decalaj, evitând un efect repetat.
Opțiunea B: Tranzacție broker
Unii brokeri sprijină înregistrarea atomică a mesajelor și compensează într-o singură tranzacție producător/consumator. Utilizați dacă este disponibil, dar întotdeauna completați cu idempotență asupra consumatorului.
7) Retrai, backoff, DLQ
Repetați numai erori retractabile (timeout, 5xx), cu backoff exponențial și jitter.
Neretractabil (schemă/validare) - imediat în DLQ cu metadate (chiriaș, cheie, offset, motiv).
Dozați redrava din DLQ (lot, limita vitezei), verificați circuitul înainte de a repeta, respectați ordinea prin cheie.
8) Multi-chirie și regiuni
Includeți 'tenant _ id',' plan ',' regiune 'în metadatele mesajelor și cheile de partiție.
Echitatea per chiriaș: Limitați publicarea/procesarea, astfel încât clientul „zgomotos” să nu deducă bugetul din restul.
Rezidență: stocați mesaje și outbox în aceeași regiune cu datele de domeniu; replici interregionale - agregate asincrone.
9) Observabilitate și audit
Urmărire: corelație 'event _ id'/' agregate _ id'/' saga _ id', se întinde pe „citire → proces → scriere/angajare”.
Valori: publicarea/procesarea decalajului (p95/p99), rata de succes, rata DLQ, redrive succesul, „duplicate suprimate”.
Jurnale: prescurtare pentru succes; detalii despre erori (motiv, încercare, cheie, offset).
Audit: cine a redesenat/rulat înapoi, ce lot și cu ce rezultat.
10) Siguranță și conformitate
Minimizați PII în sarcină utilă; Mască atunci când transferați la DLQ/jurnale.
Semnarea/criptarea mesajelor pentru autobuze externe; utilizarea mTLS între servicii.
Gestionați termenul de valabilitate și „dreptul de a uita” pe chiriaș/regiune.
11) Scheme tipice de integrare
1. Sursă de servicii (write-side)
Tranzacție locală: înregistrare domenii + outbox.
Distribuitor: loturi, „SKIP LOCKED”, backoff, limite per chiriaș.
Monitorizarea lag 'now − occurred_at'.
2. Consumatorul de servicii (read-side)
Citind lotul → încercând să „INSERT inbox (consumator, event_id)” → dacă reușim, executăm efectul.
În aceeași tranzacție, fixăm „offset-ul trecut” (opțiunea A) sau ne bazăm pe tranzacția brokerului (opțiunea B).
Pe eroare: retray sau DLQ de politică.
3. Proiecţie/Vizualizare materializată
Numai actualizări idempotente (upsert), chei compacte de eliminare a duplicatelor, verificare periodică a sumei de control.
12) Șabloane de configurare (exemplu)
yaml producer:
idempotency_key: event_id partition_key: "{tenant_id}:{aggregate_id}"
retry:
max_attempts: 8 initial_ms: 200 max_ms: 8000 strategy: exponential_full_jitter
consumer:
batch: 500 offset_commit: "with_domain_tx" # или "broker_tx"
inbox_enabled: true concurrency_per_partition: 4 dlq:
enabled: true batch_redrive: 200 rate_limit_per_sec: 50 order_by_key: true
observability:
metrics:
- processing_lag_ms
- publish_success_ratio
- dlq_rate
- redrive_success_ratio tracing_tags: [event_id, tenant_id, aggregate_id, partition, offset]
13) Lista de verificare pre-vânzare
- Eliminat „două litere”: outbox pe producător sau fixarea offset și efectul într-o singură tranzacție la consumator.
- Consumator idempotent: „inbox ”/jurnal dedup, idempotența de afaceri a operațiunilor.
- Partiționarea prin cheie de afaceri, ordinea locală este urmată.
- Backoff + jitter retraces, clasificare eroare, metadate bogat DLQ.
- Redrave dozate, în condiții de siguranță; Sunt cărţi de joacă.
- Limitele și prioritățile multi-chiriașilor; 'tenant _ id/plan/region' tags.
- Telemetrie: lag-uri, rata de succes, „duplicate suprimate”, alerte de p95/p99.
- Politicile PII/retenție/criptare sunt aplicate.
- Teste: picătură între pași, duplicate, ordine cheie, redesenare în masă.
14) Erori tipice
Trimiterea la autobuz și scrierea la baza de date în pași separați, fără o tranzacție outbox/offset.
Un consumator fără idempotență → duplicează efectele secundare.
Ordinea globală „vin ceea ce poate” este costisitoare și rareori justificată; suficientă comandă cu cheia.
O redesenare masivă fără limite → un incident secundar.
Lipsa măsurătorilor de urmărire/lag → „degradarea ascunsă”.
PII amestecare în DLQ/busteni.
15) Rețete rapide
Evenimente SaaS: Outbox + consumator idempotent (inbox), partiționarea prin 'chiriaș _ id: agregate _ id'.
ETL/proiecții: Citire-proces-scriere cu compensări de fixare într-o singură tranzacție, loturi 500-1000, upsert.
Încărcare mare: Editarea cioburilor, „SKIP LOCKED”, WFQ per chiriaș, controlul decalajului.
Zona de conformitate strictă: outbox regional, criptarea sarcinii utile, păstrarea și auditarea redrive-urilor.
Concluzie
Mesageria tranzactionala este disciplina de conectare a datelor si mesajelor. Prin combinarea outbox/inbox, idempotency, compensează fixarea împreună cu efectele și retraiele gestionate cu DLQ, obțineți un comportament practic exact o dată fără încuietori globale și păstrați SLO chiar și cu accidente, vârfuri și exploatare complexă multi-chiriaș.