Bài toán: microservices không chia sẻ DB → không dùng được distributed transaction (2PC quá phức tạp) → làm sao đảm bảo consistency khi 1 operation cần update nhiều service?
Saga pattern: chuỗi local transaction, mỗi bước publish event → service tiếp theo xử lý. Nếu bước N fail → thực thi compensating transaction từ N-1 ngược về.
Ví dụ Order flow:
1. OrderService: CREATE order (status=PENDING) → publish OrderCreated
2. InventoryService: RESERVE items → publish ItemsReserved
3. PaymentService: CHARGE payment → publish PaymentCompleted
4. OrderService: UPDATE order (status=CONFIRMED)
// Nếu bước 3 fail:
3. PaymentService: FAIL → publish PaymentFailed
2c. InventoryService: RELEASE items (compensate)
1c. OrderService: CANCEL order2 loại Saga:
Choreography — mỗi service nghe event và phản ứng:
@KafkaListener(topics = "order-events")
void onOrderCreated(OrderCreatedEvent event) {
inventoryService.reserve(event.getItems());
kafkaTemplate.send("inventory-events", new ItemsReservedEvent(...));
}Pros: loose coupling. Cons: khó debug, cyclic dependency ngầm.
Orchestration — 1 Saga orchestrator điều phối:
- Dùng Axon Framework, Temporal, hoặc AWS Step Functions.
Pros: dễ debug, flow rõ ràng. Cons: thêm component.
Idempotency là bắt buộc: mỗi step phải idempotent vì message có thể deliver nhiều lần (Kafka at-least-once).
Problem: microservices do not share a DB → cannot use distributed transactions (2PC is too complex) → how to ensure consistency when one operation needs to update multiple services?
Saga pattern: a sequence of local transactions, each publishing an event → the next service handles it. If step N fails → execute compensating transactions from N-1 backwards.
Order flow example:
1. OrderService: CREATE order (status=PENDING) → publish OrderCreated
2. InventoryService: RESERVE items → publish ItemsReserved
3. PaymentService: CHARGE payment → publish PaymentCompleted
4. OrderService: UPDATE order (status=CONFIRMED)
// If step 3 fails:
3. PaymentService: FAIL → publish PaymentFailed
2c. InventoryService: RELEASE items (compensate)
1c. OrderService: CANCEL orderTwo types of Saga:
Choreography — each service listens for events and reacts:
@KafkaListener(topics = "order-events")
void onOrderCreated(OrderCreatedEvent event) {
inventoryService.reserve(event.getItems());
kafkaTemplate.send("inventory-events", new ItemsReservedEvent(...));
}Pros: loose coupling. Cons: hard to debug, hidden cyclic dependencies.
Orchestration — a central Saga orchestrator coordinates:
- Use Axon Framework, Temporal, or AWS Step Functions.
Pros: easy to debug, clear flow. Cons: extra component.
Idempotency is mandatory: every step must be idempotent since messages may be delivered more than once (Kafka at-least-once delivery).