Saga Pattern là gì? Quản lý Transaction trong kiến trúc Microservices
1. Saga Pattern là gì?
Saga Pattern là một mẫu thiết kế được sử dụng để quản lý các nghiệp vụ phân tán gồm nhiều bước xử lý, trong đó mỗi bước có thể thực hiện một local transaction tại một service hoặc Database riêng biệt.
Trong kiến trúc Microservices, mỗi service thường chịu trách nhiệm cho một phần nghiệp vụ và có thể sở hữu Database riêng. Vì vậy, một nghiệp vụ lớn có thể cần phối hợp nhiều service để hoàn thành.
Saga giải quyết vấn đề này bằng cách chia nghiệp vụ thành nhiều local transaction được thực hiện theo một quy trình xác định. Nếu một bước thất bại sau khi những bước trước đã hoàn thành, hệ thống có thể thực hiện các Compensating Transaction (transaction bù) để bù đắp những thay đổi nghiệp vụ đã xảy ra.
Ý tưởng cốt lõi của Saga là quản lý tính nhất quán của một nghiệp vụ xuyên suốt nhiều transaction độc lập, thay vì phụ thuộc vào một transaction ACID duy nhất bao trùm tất cả service.
2. Tại sao cần Saga Pattern?
Để hiểu lý do cần Saga, hãy xem xét một hệ thống thương mại điện tử có các service:
- Order Service: Quản lý đơn hàng.
- Inventory Service: Quản lý tồn kho.
- Payment Service: Xử lý thanh toán.
- Shipping Service: Quản lý vận chuyển.
Khi khách hàng đặt hàng, hệ thống có thể cần thực hiện lần lượt các thao tác sau:
- Tạo đơn hàng.
- Giữ sản phẩm trong kho.
- Thanh toán.
- Tạo yêu cầu vận chuyển.
Nếu các thao tác này nằm trong cùng một Database, một transaction cục bộ có thể quản lý nhiều thay đổi dữ liệu phù hợp.
Tuy nhiên, trong kiến trúc Microservices, mỗi service có thể sử dụng một Database độc lập. Một transaction PostgreSQL thông thường không thể tự động bao trùm toàn bộ các Database này.
Giả sử đơn hàng đã được tạo và hàng đã được giữ thành công, nhưng thanh toán thất bại. Hệ thống cần giải phóng hàng đã giữ và cập nhật trạng thái đơn hàng phù hợp.
Nếu không có cơ chế quản lý tiến trình và xử lý thất bại, dữ liệu giữa các service có thể rơi vào trạng thái không phù hợp với nghiệp vụ.
Saga cung cấp một cách tổ chức các bước xử lý và xác định cách hệ thống phản ứng khi một bước không thể hoàn thành.
3. Saga Pattern hoạt động như thế nào?
Một Saga gồm một chuỗi local transaction:
T1 → T2 → T3 → T4
Trong đó, mỗi transaction xử lý một phần nghiệp vụ. Sau khi một bước hoàn thành, hệ thống tiếp tục bước tiếp theo theo quy trình đã thiết kế.
Ví dụ:
T1: Tạo đơn hàng.T2: Giữ hàng trong kho.T3: Thực hiện thanh toán.T4: Tạo yêu cầu vận chuyển.
Nếu T3 thất bại sau khi T1 và T2 đã hoàn thành, hệ thống có thể thực hiện các transaction bù tương ứng:
C2 → C1
Trong đó:
C2: Giải phóng hàng đã giữ.C1: Hủy hoặc đánh dấu đơn hàng không thể tiếp tục.
Không phải mọi bước đều cần được bù theo cùng một cách. Các thao tác bù phụ thuộc vào trạng thái thực tế và quy tắc nghiệp vụ của từng service.
Ví dụ quy trình đặt hàng
| Bước | Thao tác | Kết quả |
|---|---|---|
| 1 | Order Service tạo đơn hàng | Thành công |
| 2 | Inventory Service giữ hàng | Thành công |
| 3 | Payment Service xử lý thanh toán | Thất bại |
| 4 | Inventory Service giải phóng hàng | Transaction bù |
| 5 | Order Service cập nhật trạng thái đơn | Đơn hàng bị hủy hoặc thất bại |
Điểm quan trọng là Saga không nhất thiết xóa mọi dữ liệu đã tạo. Ví dụ, đơn hàng có thể vẫn được lưu trong Database để phục vụ lịch sử, kiểm toán và hỗ trợ khách hàng.
Thay vào đó, các transaction bù thực hiện những thay đổi nghiệp vụ cần thiết để đưa hệ thống về trạng thái phù hợp.
4. Compensating Transaction là gì?
Compensating Transaction (transaction bù) là một thao tác nghiệp vụ được thực hiện nhằm bù đắp tác động của một local transaction đã hoàn thành khi Saga không thể tiếp tục theo kế hoạch.
Ví dụ:
| Local transaction | Transaction bù |
|---|---|
| Tạo đơn hàng | Đánh dấu đơn hàng đã hủy |
| Giữ hàng trong kho | Giải phóng hàng đã giữ |
| Trừ tiền khách hàng | Hoàn tiền hoặc yêu cầu hoàn tiền |
| Tạo yêu cầu vận chuyển | Hủy yêu cầu nếu đơn vị vận chuyển hỗ trợ |
Cần phân biệt transaction bù với rollback thông thường.
Rollback của một transaction Database có thể hủy những thay đổi chưa được commit trong phạm vi transaction đó. Trong khi đó, transaction bù thường là một thao tác mới được thực hiện sau khi transaction trước đã commit.
Ví dụ, nếu hàng đã được giữ thành công trong Inventory Database, sau đó thanh toán thất bại, hệ thống không thể đơn giản rollback transaction của Inventory từ một transaction khác đã kết thúc. Nó cần gọi nghiệp vụ giải phóng hàng để bù lại thay đổi trước đó.
Transaction bù cũng không nhất thiết đảo ngược hoàn toàn tác động ban đầu. Một email đã gửi không thể được thu hồi như thể chưa từng gửi; một khoản thanh toán có thể cần quy trình hoàn tiền riêng.
Vì vậy, việc thiết kế transaction bù phải dựa trên khả năng thực tế của từng nghiệp vụ.
5. Hai mô hình triển khai Saga phổ biến
Có hai cách tổ chức luồng xử lý Saga thường gặp: Choreography và Orchestration.

5.1. Choreography — Điều phối bằng sự kiện
Trong mô hình Choreography, không có một thành phần trung tâm trực tiếp điều khiển tất cả các bước. Thay vào đó, mỗi service thực hiện phần việc của mình rồi phát ra sự kiện để service tiếp theo phản ứng.
Ví dụ:
- Order Service tạo đơn và phát sự kiện
OrderCreated. - Inventory Service nhận sự kiện, giữ hàng và phát
InventoryReserved. - Payment Service nhận sự kiện, xử lý thanh toán và phát kết quả.
- Shipping Service tiếp tục khi thanh toán thành công.
Nếu thanh toán thất bại, sự kiện thất bại có thể kích hoạt các bước giải phóng hàng và cập nhật trạng thái đơn hàng.
Ưu điểm:
- Không cần một bộ điều phối trung tâm.
- Các service có thể phối hợp tương đối độc lập.
- Phù hợp với luồng nghiệp vụ sự kiện đơn giản.
Nhược điểm:
- Luồng nghiệp vụ khó theo dõi khi có nhiều service.
- Logic xử lý thất bại và bù trừ có thể bị phân tán.
- Khó quan sát toàn bộ trạng thái Saga nếu thiếu cơ chế theo dõi phù hợp.
5.2. Orchestration — Điều phối tập trung
Trong mô hình Orchestration, một thành phần gọi là Saga Orchestrator chịu trách nhiệm quản lý tiến trình nghiệp vụ. Nó quyết định service nào cần thực hiện bước tiếp theo và cần xử lý thế nào khi một bước thất bại.
Ví dụ, Orchestrator quản lý quy trình đặt hàng như sau:
- Yêu cầu Order Service tạo đơn.
- Yêu cầu Inventory Service giữ hàng.
- Yêu cầu Payment Service thanh toán.
- Nếu thanh toán thành công, yêu cầu Shipping Service tạo yêu cầu vận chuyển.
- Nếu thanh toán thất bại, điều phối việc giải phóng hàng và cập nhật trạng thái đơn hàng.
Ưu điểm:
- Luồng nghiệp vụ được thể hiện rõ ràng.
- Dễ quản lý trạng thái, timeout và logic bù trừ.
- Thuận tiện khi Saga có nhiều bước hoặc nhánh xử lý.
Nhược điểm:
- Cần xây dựng hoặc sử dụng một thành phần điều phối.
- Orchestrator phải được thiết kế để phục hồi sau sự cố.
- Nếu thiết kế không tốt, logic nghiệp vụ có thể tập trung quá nhiều vào thành phần điều phối.
Không có mô hình nào luôn tốt hơn mô hình còn lại. Việc lựa chọn phụ thuộc vào độ phức tạp của nghiệp vụ, số lượng service và khả năng vận hành hệ thống.
6. Saga có đảm bảo ACID không?
Saga không cung cấp một transaction ACID duy nhất cho toàn bộ nghiệp vụ phân tán.
Mỗi local transaction vẫn có thể đảm bảo các thuộc tính ACID trong phạm vi Database của service tương ứng. Tuy nhiên, trạng thái giữa các service có thể tạm thời chưa nhất quán trong thời gian Saga đang thực thi.
Ví dụ, đơn hàng đã được tạo và hàng đã được giữ, nhưng thanh toán vẫn đang xử lý. Trong khoảng thời gian này, nghiệp vụ chưa hoàn tất.
Saga thường hướng đến Eventual Consistency (tính nhất quán cuối cùng): sau khi các bước xử lý hoặc bù trừ hoàn tất, trạng thái của các service sẽ phù hợp với kết quả cuối cùng của nghiệp vụ.
Tuy nhiên, eventual consistency không có nghĩa là hệ thống tự động nhất quán trong mọi tình huống. Nếu một service ngừng hoạt động, thông điệp bị mất hoặc transaction bù thất bại, Saga có thể cần retry, phục hồi hoặc can thiệp vận hành để hoàn tất.
7. Những vấn đề cần lưu ý khi triển khai Saga
Saga giúp tổ chức quy trình nghiệp vụ phân tán, nhưng để vận hành đáng tin cậy, hệ thống cần xử lý các tình huống lỗi thực tế.
7.1. Retry — Thử lại
Một service có thể tạm thời không phản hồi do lỗi mạng hoặc quá tải. Hệ thống cần chính sách retry phù hợp, chẳng hạn giới hạn số lần thử và sử dụng khoảng chờ tăng dần.
Không nên retry vô hạn hoặc retry mọi lỗi mà không phân biệt nguyên nhân.
7.2. Idempotency — Tính lặp an toàn
Một request hoặc message có thể được gửi lại do timeout hoặc cơ chế retry. Nếu xử lý lặp làm trừ tiền hoặc giữ hàng nhiều lần, dữ liệu sẽ sai.
Vì vậy, các bước quan trọng nên có cơ chế nhận diện thao tác đã xử lý, chẳng hạn bằng transaction ID hoặc idempotency key.
7.3. Timeout và trạng thái không xác định
Timeout không nhất thiết có nghĩa là thao tác thất bại. Ví dụ, Payment Service có thể đã xử lý thanh toán thành công nhưng phản hồi bị mất trên đường truyền.
Nếu hệ thống lập tức coi thao tác là thất bại và giải phóng hàng, trạng thái giữa thanh toán và đơn hàng có thể không còn phù hợp.
Trong trường hợp này, hệ thống có thể cần truy vấn trạng thái thanh toán hoặc đối soát trước khi quyết định bước tiếp theo.
7.4. Lưu trạng thái Saga
Hệ thống cần lưu đủ thông tin để biết Saga đã hoàn thành bước nào, đang chờ gì và cần phục hồi ra sao sau khi service bị khởi động lại.
Đối với nghiệp vụ quan trọng, không nên chỉ lưu tiến trình trong bộ nhớ của một tiến trình ứng dụng.
7.5. Transaction bù cũng có thể thất bại
Giả sử thanh toán thất bại nhưng Inventory Service đang ngừng hoạt động nên không thể giải phóng hàng.
Saga chưa thể hoàn tất việc bù trừ. Hệ thống cần lưu trạng thái chờ xử lý, retry hoặc chuyển sang quy trình xử lý sự cố phù hợp.
Điều này cho thấy transaction bù không phải là một thao tác đảm bảo thành công tuyệt đối.
7.6. Transactional Outbox
Transactional Outbox là một kỹ thuật thường được kết hợp với Saga.
Giả sử Order Service vừa lưu đơn hàng vào Database vừa cần phát sự kiện OrderCreated. Nếu Database commit thành công nhưng ứng dụng gặp lỗi trước khi gửi sự kiện, các service khác có thể không biết đơn hàng đã được tạo.
Transactional Outbox giải quyết nguy cơ này bằng cách lưu thay đổi dữ liệu và bản ghi sự kiện cần phát đi trong cùng một local transaction. Sau đó, một tiến trình khác đọc bản ghi Outbox và gửi sự kiện đến message broker.
Kỹ thuật này giúp giảm nguy cơ dữ liệu đã được commit nhưng sự kiện tương ứng không được phát đi. Tuy nhiên, hệ thống vẫn cần xử lý việc gửi trùng và bảo đảm consumer có khả năng xử lý idempotent.
8. Saga Pattern liên quan gì đến Transaction, Locking và Isolation Level?
Các khái niệm này đều liên quan đến tính đúng đắn của dữ liệu, nhưng hoạt động ở những phạm vi khác nhau.
| Khái niệm | Vai trò |
|---|---|
| Transaction | Quản lý một nhóm thao tác dữ liệu trong phạm vi transaction. |
| Locking / Two-Phase Locking | Kiểm soát truy cập đồng thời và xung đột dữ liệu trong Database. |
| Isolation Level | Xác định mức độ cô lập giữa các transaction. |
| Saga Pattern | Quản lý một nghiệp vụ gồm nhiều transaction độc lập trên nhiều service. |
| Compensating Transaction | Bù đắp tác động nghiệp vụ của bước đã hoàn thành khi cần thiết. |
Ví dụ:
- Khi nhiều request cùng mua sản phẩm cuối cùng, hệ thống cần kiểm soát cập nhật tồn kho bằng transaction và cơ chế xử lý đồng thời phù hợp.
- Khi một đơn hàng cần phối hợp Order, Inventory, Payment và Shipping Service, hệ thống có thể sử dụng Saga để quản lý toàn bộ tiến trình.
Saga không thay thế transaction, locking hoặc isolation level. Nó thường dựa vào các local transaction bên trong từng service để đảm bảo tính đúng đắn của dữ liệu cục bộ, đồng thời quản lý kết quả nghiệp vụ ở phạm vi rộng hơn.
9. Khi nào nên sử dụng Saga Pattern?
Saga phù hợp khi một nghiệp vụ cần phối hợp nhiều service hoặc Database độc lập, trong khi việc sử dụng một transaction phân tán duy nhất không phù hợp với kiến trúc hoặc yêu cầu vận hành.
Một số ví dụ:
- Thương mại điện tử: đặt hàng, giữ kho, thanh toán và vận chuyển.
- Du lịch: đặt vé máy bay, khách sạn và các dịch vụ đi kèm.
- Tài chính: phối hợp nhiều hệ thống để xử lý một quy trình nghiệp vụ.
- Logistics: tạo đơn giao hàng, phân công vận chuyển và cập nhật trạng thái giao nhận.
Ngược lại, nếu toàn bộ nghiệp vụ chỉ cập nhật vài bảng trong cùng một Database quan hệ, transaction thông thường thường đơn giản hơn và nên được ưu tiên.
Không nên sử dụng Saga chỉ vì một nghiệp vụ có nhiều bước. Giá trị của Saga thể hiện rõ nhất khi những bước đó thuộc các transaction độc lập và cần một cơ chế phối hợp, phục hồi khi lỗi xảy ra.
10. Kết luận
Saga Pattern là một mẫu thiết kế giúp quản lý các nghiệp vụ phân tán gồm nhiều local transaction trên nhiều service. Thay vì dựa vào một transaction ACID duy nhất, Saga tổ chức các bước xử lý và xác định cách bù trừ khi một bước thất bại.
Hai mô hình triển khai phổ biến là Choreography, trong đó các service phối hợp thông qua sự kiện, và Orchestration, trong đó một thành phần điều phối quản lý tiến trình.
Để triển khai Saga đáng tin cậy, hệ thống cần quan tâm đến retry, idempotency, timeout, lưu trạng thái và xử lý thất bại của transaction bù.
Đối với Backend Developer, hiểu Saga giúp nhận biết khi nào transaction thông thường không đủ để quản lý một nghiệp vụ xuyên suốt nhiều service, từ đó thiết kế hệ thống có khả năng phục hồi và duy trì trạng thái nghiệp vụ phù hợp khi xảy ra lỗi.







Khoá học lập trình game con rắn cho trẻ em




