Wiadomości transakcyjne
Transactional messaging to zestaw technik architektonicznych, które zapewniają spójność między lokalnymi zmianami stanu (bazy danych/pamięci podręcznej) a komunikatami w brokerze/autobusie. Przeznaczenie: "stan jest stały" komunikat nie jest utracony lub powielany "w przypadku awarii, retras, skalowania i wielozadaniowości.
1) Semantyka dostawy
Co najwyżej raz: Szybki i tani, straty możliwe, nie bierze.
Co najmniej raz: nie traci wiadomości, duplikaty są możliwe → wymagana jest idempotencja.
(Skuteczny) Dokładnie raz: brak strat i brak widocznych efektów biznesowych, osiągniętych poprzez połączenie technik (skrzynka odbiorcza/skrzynka odbiorcza, transakcje producenta/konsumenta, dedup).
2) Dlaczego „dwuliterowe” jest niebezpieczne
Naiwna logika „najpierw zapisz do bazy danych, a następnie wyślij do autobusu” (lub odwrotnie) przerywa się, gdy spadnie między krokami: dane są naprawione, a zdarzenie jest utracone; Albo zdarzenie przepadło, ale nie ma danych. Komunikatory transakcyjne niwelują tę lukę.
3) Podstawowe wzory
3. 1 Skrzynka odbiorcza (producent)
W jednej transakcji lokalnej zapisujemy zmianę firmy i wiersz do tabeli „outbox”; osobny wydawca czyta skrzynkę i publikuje w brokerze z retras i backoff. Wyłączone straty; dwoje osób ginie z powodu idempotencji wśród konsumentów.
3. 2 Skrzynka odbiorcza/Consumer Idempotent
Przed wykonaniem efektu konsument umieszcza 'INSERT' w 'skrzynce odbiorczej (konsument, event_id)' jako klucz podstawowy. Key conflict = event już przetworzone → skip. W ten sposób „skutecznie dokładnie raz” jest osiągane.
3. 3 Odczytywanie-zapisywanie z transakcją offsetową
Szablon dla autobusów zorientowanych na dziennik: konsument czyta partię, w tym samym rejestrze transakcji zmiana biznesu i "przeszedł offset. "Po popełnieniu zobowiązania broker rozważa zużyte wiadomości. Eliminuje to „read → fall → repeat” bez duplikatów w efekcie.
3. 4 TSS/Sagas dla efektów interservice
Jeśli potrzebujesz spójnego procesu wielostopniowego, użyj TCC lub sagi; komunikaty - transport poleceń/zdarzeń oraz transakcyjność - na poziomie kroków i kompensacji.
4) Idempotentni producenci i konsumenci
Producent: stabilny 'message _ id'/' idempotency _ key', resetujący ten sam klucz nie wywołuje nowych efektów dla abonentów; utrzymać sekwencję przez klucz.
Konsument: „skrzynka odbiorcza” + business idempotency (upsert/merge, sprawdź najnowszą wersję/wersję).
5) Porządek i przyczynowość
Weź udział przez klucz biznesowy (na przykład 'aggregate _ id',' tenant _ id'), aby zdarzenia jednego obiektu przyszły w kolejności.
Przechowywać kolejne numery/znaczniki czasu wewnątrz partii; podczas redrawing z DLQ, obserwować „przez klucz i kolejno”.
Jeśli globalny porządek nie jest krytyczny, należy zapewnić lokalne porządki za pomocą klucza i naprawić niezmienne domeny.
6) Kompensaty i efekty mocowania
Opcja A: „Offset in DB”
Napisz „last processed offset (partycja, offset)” do tej samej transakcji, w której zmieniasz dane domeny. Po ponownym uruchomieniu kontynuuj od następnego przesunięcia, unikając powtarzającego się efektu.
Opcja B: Transakcja brokerska
Niektórzy brokerzy wspierają nagrywanie wiadomości i kompensaty atomowe w jednej transakcji producenta/konsumenta. Użyj, jeśli jest dostępny, ale zawsze uzupełnić z idempotencją na konsumenta.
7) Retrai, backoff, DLQ
Powtarzaj tylko błędy retrable (timeouts, 5xx), z wykładniczym backoff i jitter.
Non-retrable (schemat/walidacja) - natychmiast w DLQ z metadanymi (najemca, klucz, przesunięcie, powód).
Dawkowanie redrave z DLQ (partia, limit szybkości), sprawdzić obwód przed powtórzeniem, przestrzegać kolejności przez klucz.
8) Wielopłata i regiony
W metadanych komunikatów i klawiszy partycji wpisz 'lokator _ id',' plan ',' region '.
Uczciwość dla jednego najemcy: Ograniczyć publikowanie/przetwarzanie, aby „hałaśliwy” klient nie odliczył budżetu od reszty.
Miejsce zamieszkania: przechowywanie wiadomości i skrzynek zewnętrznych w tym samym regionie co dane domeny; replikacje międzyregionalne - kruszywa asynchroniczne.
9) Obserwowalność i audyt
Odwzorowanie: korelacja 'event _ id'/' aggregate _ id'/' saga _ id', spans' read → process → write/commit '.
Metryki: publikowanie/przetwarzanie lag (p95/p99), wskaźnik sukcesu, wskaźnik DLQ, ponowny sukces, „duplikaty tłumione”.
Kłody: krótkie dla sukcesu; szczegóły dotyczące błędów (przyczyna, próba, klucz, offset).
Audyt: kto redrawn/rolled z powrotem, jaka partia i z jakim wynikiem.
10) Bezpieczeństwo i zgodność
Zminimalizować PII w ładunku użytkowym; Maska podczas przenoszenia do DLQ/dzienników.
Wiadomości podpisu/szyfrowania dla autobusów zewnętrznych; używać mTLS między usługami.
Zarządzanie trwałością i „prawo do zapomnienia” na najemcę/region.
11) Typowe systemy integracji
1. Źródło usługi (strona odpisowa)
Transakcja lokalna: rekord domeny + skrzynka odbiorcza.
Wydawca: partie, 'SKIP LOCKED', backoff, limity na najemcę.
Monitorowanie lag 'now − occurred_at'.
2. Usługa-konsument (po stronie odczytu)
Czytanie partii → próba 'INSERT inbox (konsument, event_id)' → Jeśli sukces, wykonujemy efekt.
W tej samej transakcji ustalamy „przeniesiony offset” (opcja A) lub polegamy na transakcji brokera (opcja B).
Na błędzie: retray lub DLQ według zasad.
3. Projekcja/zmaterializowany widok
Tylko idempotentne aktualizacje (upsert), kompaktowe klucze deduplikacji, okresowa weryfikacja kontrolna.
12) Szablony konfiguracji (przykład)
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 kontrolna przedsprzedaży
- Zlikwidowane „dwuliterowe”: skrzynka na producenta lub ustalenie potrącenia i skutku w jednej transakcji na konsumenta.
- Consumer idempotent: „inbox ”/dedup journal, business idempotence of operations.
- Podział według klucza biznesowego, lokalne zamówienie jest przestrzegane.
- Backoff + jitter retras, klasyfikacja błędów, metadane bogate DLQ.
- Przerobić dawkowane, bezpieczne; są playbooks.
- limity i priorytety dla wielu najemców; "najemca _ id/plan/region 'tagi.
- Telemetria: opóźnienia, wskaźnik sukcesu, „duplikaty stłumione”, wpisy przez p95/p99.
- Polityka PII/retencji/szyfrowania jest egzekwowana.
- Testy: spadek między etapami, duplikaty, kolejność kluczy, masa przerobiona.
14) Typowe błędy
Wysyłanie do magistrali i pisanie do bazy danych w oddzielnych krokach bez transakcji outbox/offset.
Konsument bez idempotencji → powiela skutki uboczne.
Globalny porządek „przyjść co może” jest drogie i rzadko uzasadnione; wystarczająco dużo kolejności według klucza.
Masywna przeróbka bez ograniczeń → incydent wtórny.
Brak mierników śledzenia/opóźnienia → „ukryta degradacja”.
Mieszanie PII w DLQ/dzienniki.
15) Szybkie przepisy kulinarne
Wydarzenia SaaS: Outbox + consumer idempotent (skrzynka odbiorcza), partycjonowanie przez 'lokator _ id: aggregate _ id'.
ETL/projections: Read-process-write with fixing offsets in one transaction, batches 500-1000, upsert.
Wysokie obciążenie: Odłamki wydawnicze, 'SKIP LOCKED', WFQ na najemcę, kontrola opóźnień.
Strefa ścisłej zgodności: regionalna skrzynka odbiorcza, szyfrowanie ładunku, zatrzymywanie i audyt redrives.
Wnioski
Komunikaty transakcyjne to dyscyplina łączenia danych i wiadomości. Poprzez połączenie skrzynki zewnętrznej/skrzynki odbiorczej, idempotencji, utrwalenia offsetów wraz z efektami i zarządzanych retras z DLQ, otrzymasz praktyczne zachowanie dokładnie raz bez globalnych blokad i zachować SLO nawet przy awariach, szczytach i złożonej eksploatacji wielu najemców.