Saga Pattern
Distributed transactions bez 2PC — sekwencja lokalnych transakcji z kompensacją. Choreography przez eventy lub Orchestration przez Temporal.io.
Choreography vs Orchestration
Dwa fundamentalnie różne podejścia do koordynacji Sagi — decentralizacja przez eventy vs centralny koordynator.
| Aspekt | Choreography | Orchestration |
|---|---|---|
| Koordynacja | Zdecentralizowana (events) | Centralna (Saga Manager) |
| Coupling | Luźne (event bus) | Wyższe (orchestrator zna usługi) |
| Debugowanie | Trudne (rozproszone logi) | Łatwe (centralny log) |
| Widoczność stanu | Brak centralnego widoku | Pełny widok stanu |
| Dodawanie kroków | Proste (nowy subscriber) | Wymaga zmiany orchestratora |
| Narzędzia | Kafka, RabbitMQ, SNS/SQS | Temporal, Step Functions, Zeebe |
Często zadawane pytania
Co to jest wzorzec Saga i dlaczego zastępuje distributed transactions?
Problem: w mikrousługach nie ma jednej bazy danych dla całej transakcji. Distributed transactions (2PC — Two-Phase Commit) wymagają distributed lock — powolne, kruche, nie skalują się. Saga pattern: zamiast jednej ACID transakcji — sekwencja lokalnych transakcji powiązanych kompensacją. Każdy krok to lokalna transakcja w jednej usłudze. Jeśli krok się nie powiedzie — uruchom compensating transactions dla poprzednich kroków. Saga nie jest ACID: brak Isolation — inne usługi mogą widzieć częściowe rezultaty. Eventual Consistency — spójność osiągana po czasie. Bazedanowe 'BASE' zamiast 'ACID'. Przykład: Order Saga. 1. CreateOrder (PENDING). 2. ReserveInventory. 3. ProcessPayment. 4. ConfirmOrder. Jeśli payment fail: CancelReservation (compensate 2). CancelOrder (compensate 1). Dwie implementacje Saga: Choreography — zdarzenia (events) koordynują przepływ. Orchestration — centralny koordynator (Orchestrator/Saga Manager) steruje krokami. Brak Isolation powoduje anomalie: Lost Update. Dirty Read. Non-repeatable Read. Countermeasures: Semantic Lock — flaguj rekordy jako 'w trakcie przetwarzania'. Commutative Updates — kolejność nie ma znaczenia. Pessimistic View — re-read po zakończeniu.
Choreography Saga vs Orchestration Saga — co wybrać?
Choreography Saga: każda usługa reaguje na eventy i emituje własne eventy. Brak centralnego koordynatora. Przepływ: OrderService emituje 'OrderCreated' -> InventoryService reaguje, emituje 'InventoryReserved' -> PaymentService reaguje, emituje 'PaymentProcessed' -> OrderService reaguje, emituje 'OrderConfirmed'. Kompensacja: PaymentService emituje 'PaymentFailed' -> InventoryService reaguje 'InventoryReleased' -> OrderService emituje 'OrderCancelled'. Zalety choreography: brak single point of failure. Luźne powiązania. Łatwo dodać nową usługę (subscriber). Wady choreography: trudne debugowanie (gdzie jest błąd?). Brak centralnego widoku stanu. Ryzyko cyklicznych zależności. Spaghetti event flow. Orchestration Saga: centralny Orchestrator (Saga Manager) wysyła komendy do usług, czeka na odpowiedź. Orchestrator wie o wszystkich krokach i stanie. Zalety orchestration: łatwiejsze debugowanie. Jasny przepływ. Łatwe retry. Czytelna logika biznesowa w jednym miejscu. Wady orchestration: Orchestrator wie o wszystkich usługach (higher coupling). Single point of coordination. Kiedy co: prosta Saga (2-3 kroki) — choreography. Złożona logika, wiele kroków, retry — orchestration. Temporal.io — workflow engine dla orchestration Saga.
Temporal.io — durable workflow engine dla Saga i długotrwałych procesów?
Temporal.io: open-source durable workflow engine. Napędzany przez Netflix, Uber, Airbnb. Kluczowa idea: kod workflow jest deterministyczny i persystowany. Workflow może czekać dni/tygodnie bez utraty stanu. Crash i restart nie zrywają workflow. Koncepty: Workflow — kod który definiuje przepływ. Activity — pojedynczy krok (call do zewnętrznego API, DB write). Worker — serwis który wykonuje workflow i activities. Task Queue — kolejka zadań dla workerów. Signals — zewnętrzne zdarzenia które modyfikują workflow. Queries — odczyt stanu workflow. Jak działa: Temporal Server persystuje każdy krok. Při restart Worker — odtwarza historię eventów i kontynuuje. Automatyczne retry activities (z exponential backoff). Timeout per activity i per workflow. Saga z Temporal: każda Activity jest odwracalna (compensate function). Jeśli Activity fail — Temporal uruchamia compensation workflow. Języki: Go, Java, Python, TypeScript (SDK). Temporal Cloud: managed Temporal (pay per use). Self-hosted: Temporal Server + Cassandra/PostgreSQL. Alternatywy: Conductor (Netflix, open-source). Cadence (Uber, Temporal ancestor). AWS Step Functions (SaaS, state machines). Zeebe/Camunda 8 (BPMN-based). Apache Airflow (DAG-based, bardziej dla ETL).
Jak implementować Saga z Kafka i event store?
Event-driven Saga z Kafka: każdy krok emituje eventy na Kafka topic. Usługi konsumują eventy i emitują nowe. Compensating events publikowane w przypadku błędu. Saga State: gdzie trzymać stan sagi? Opcja 1: Saga State w osobnej tabeli DB per usługa. Opcja 2: Event Store — stan wynikający z historii eventów. Opcja 3: Redis — tymczasowy state dla in-flight sagas. Choreography z Kafka: topics per step/event-type. Idempotent consumers — ten sam event może przyjść wielokrotnie. Consumer groups — jedna instancja per partycja. Exactly-once semantics: Kafka transactions — producer i consumer jako atomowa operacja. Transactional Outbox — najpierw zapisz do DB, potem do Kafka (CDC przez Debezium). Saga correlation: Correlation ID — ten sam ID przez całą sagę. Propagowany w event headers lub payload. Używany do łączenia eventów w jedną sagę. Observability: distributed tracing (OpenTelemetry) z correlation ID. Metryki: saga duration, success rate, compensation rate. Alerting gdy saga stuck (brak postępu po X minutes). Testing Saga: unit test każdej usługi niezależnie. Contract tests (Pact) między usługami. Integration tests z testcontainers (Kafka + PostgreSQL). End-to-end saga test w staging environment.
Jakie są pułapki i anty-wzorce przy implementacji Saga?
Pułapka 1 — Missing compensation: każdy krok MUSI mieć compensating transaction. Jeśli krok nie może być cofnięty (np. email już wysłany) — użyj Pivot Transaction (ostatni krok który można cofnąć). Pułapka 2 — Dirty reads: usługa B czyta dane które usługa A jeszcze modyfikuje w ramach innej sagi. Countermeasure: Semantic Lock (flaga 'PENDING' w rekordzie). Pułapka 3 — Saga stuck: event zgubiony, usługa down — saga nigdy się nie kończy. Rozwiązanie: monitoring + alerting na długo trwające sagi. Dead letter queue. Manual intervention workflow. Pułapka 4 — Idempotency brak: event dostarczony dwukrotnie -> podwójna rezerwacja. Każdy krok musi być idempotentny. Pułapka 5 — Synchronous coordination: Saga przez synchroniczne HTTP zamiast events. Tworzy temporal coupling, traci odporność na awarie. Pułapka 6 — Zbyt dużo kroków: 10+ kroków Saga = koszmar debugowania. Rozbij na mniejsze sagas lub przemyśl granice serwisów. Best practices: Saga per business process (Order, Payment, Shipping oddzielne). Idempotent activities/handlers. Compensation zawsze implementowana. Monitoring i timeout per saga. Semantic Lock dla isolation. Testuj kompensację tak samo jak happy path.
Powiązane artykuły
Skontaktuj się z nami
Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.
Wyślij zapytanie
Telefon
+48 790 814 814
Pon-Pt: 9:00 - 18:00
adam@fotz.pl
Odpowiadamy w ciągu 24h
Adres
Plac Wolności 16
61-739 Poznań
Godziny pracy
Wolisz porozmawiać?
Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.
Zadzwoń teraz