← Về danh sách
Cơ sở dữ liệu
#2PC#3PC#분산트랜잭션#원자적커밋#XA
Cập nhật lần cuối · 2026-09-16

Giao thức cam kết hai pha (2PC) và cam kết ba pha (3PC)

1. Tổng quan

Định nghĩa: Giao thức cam kết nguyên tử (ACP, Atomic Commit Protocol) là thủ tục đồng thuận bảo đảm rằng nhiều nút phân tán cùng tham gia một giao dịch sẽ đưa kết quả cuối cùng của giao dịch đó về cùng cam kết toàn bộ (Commit) hoặc cùng hủy bỏ toàn bộ (Abort); cam kết hai pha (2PC, Two-Phase Commit) là cách hiện thực tiêu biểu, còn cam kết ba pha (3PC, Three-Phase Commit) là phần mở rộng nhằm giảm nhẹ giới hạn chặn (blocking) của 2PC.

Khó khăn bản chất của giao dịch phân tán bắt nguồn từ việc một công việc logic được thực hiện vật lý trên nhiều bộ quản lý tài nguyên (RM, Resource Manager) khác nhau. Chẳng hạn, chuyển khoản ngân hàng cập nhật lần lượt hai kho lưu trữ độc lập là DB rút tiền và DB nạp tiền; nếu chỉ một bên được phản ánh thì tiền sẽ biến mất hoặc bị nhân đôi — một sự sụp đổ nhất quán nghiêm trọng. Với giao dịch trên một nút, tính nguyên tử (Atomicity) của ACID có thể được bảo đảm chỉ bằng log và rollback, nhưng trong môi trường phân tán mỗi nút độc lập gặp lỗi, trễ hay đứt mạng, nên không thể quyết định chỉ bằng một lệnh duy nhất rằng "tất cả đã thành công hay chưa". Chính tại đây cần đến cấu trúc hai pha: trước hết hỏi ý kiến của các bên tham gia (bỏ phiếu), và chỉ thông báo xác nhận khi tất cả đã sẵn sàng.

Nhu cầu về cam kết nguyên tử này được chuẩn hóa vào thập niên 1980 cùng với sự xuất hiện của cơ sở dữ liệu phân tán và bộ giám sát xử lý giao dịch (TP Monitor). Tiêu biểu là mô hình DTP (Distributed Transaction Processing) và giao diện XA do X/Open định nghĩa; ngày nay 2PC vẫn được dùng thực tế trong JTA/JTS (Java Transaction API), cầu nối giao dịch của hàng đợi thông điệp và liên kết giữa các DB không đồng nhất. Tuy nhiên, trong môi trường microservice và cloud native, đặc tính khóa đồng bộ và chặn của 2PC cản trở khả năng mở rộng, nên phần lớn đang được thay thế bằng Saga và mô hình nhất quán cuối cùng dựa trên sự kiện sẽ được bàn ở phần sau. Dù vậy, 2PC/3PC là điểm chuẩn giải thích "vì sao nhất quán mạnh lại đắt" và là nền tảng lý thuyết gắn trực tiếp với CAP và định lý bất khả FLP, nên từ góc nhìn Kỹ sư chuyên nghiệp (Professional Engineer) nhất định phải hiểu chính xác.

Việc nhìn cam kết nguyên tử như một dạng đặc biệt của bài toán đồng thuận (consensus) cũng rất quan trọng. Mỗi bên tham gia đề xuất Yes/No và mọi bên phải đi tới cùng một quyết định cuối cùng (commit/abort), điểm này giống đồng thuận, nhưng đây là bài toán khó hơn vì thêm ràng buộc "chỉ cần một phiếu No là bắt buộc phải abort". Vì thế, đã có chứng minh lý thuyết rằng trong mạng bất đồng bộ, nếu dù chỉ một nút có thể chết thì không tồn tại giao thức cam kết nguyên tử không chặn "luôn kết thúc và luôn đúng". 2PC chấp nhận chặn và 3PC chấp nhận rủi ro nhất quán chính là kết quả của việc né tránh sự bất khả này theo hai cách khác nhau, và mọi đánh đổi của hai giao thức đều bắt nguồn từ giới hạn căn bản này.

  • Bảo đảm tính nguyên tử: tất cả bên tham gia cùng commit hoặc cùng abort, ngăn chặn tận gốc việc hoàn tất một phần (partial commit).
  • Phân tách vai trò: phân chia trách nhiệm rõ ràng giữa bộ điều phối (Coordinator/TM) và bên tham gia (Participant/RM).
  • Phục hồi dựa trên log: mỗi nút ghi bắt buộc (force-write) quyết định rồi mới phản hồi, cho phép tiếp tục sau sự cố.

2. Cấu trúc tổng thể và các chủ thể tham gia

Commit của giao dịch phân tán có luồng điều khiển hình sao (star), trong đó một bộ điều phối chỉ huy nhiều bên tham gia. Sơ đồ cấu trúc dưới đây thể hiện khung của mô hình X/Open DTP, trong đó chương trình ứng dụng (AP) gom nhiều bộ quản lý tài nguyên (RM = bên tham gia) thông qua bộ quản lý giao dịch (TM = bộ điều phối). Bộ điều phối quản lý việc bắt đầu·kết thúc giao dịch và tổng hợp phiếu bầu, còn bên tham gia đảm nhận cập nhật dữ liệu thực tế và quản lý log cục bộ. Điểm cốt lõi trong cấu trúc này là quyền quyết định tập trung tại một chỗ là bộ điều phối — vừa là ưu điểm bảo đảm kết quả nhất quán, vừa là gốc rễ của nhược điểm khiến bộ điều phối trở thành điểm lỗi đơn (SPOF).

graph TD
    AP["Chương trình ứng dụng (AP)"] -->|"Yêu cầu giao dịch"| TM["Bộ điều phối (TM / Coordinator)"]
    TM -->|"Chỉ thị Prepare / Commit"| RM1["Bên tham gia RM1 (DB rút tiền)"]
    TM -->|"Chỉ thị Prepare / Commit"| RM2["Bên tham gia RM2 (DB nạp tiền)"]
    TM -->|"Chỉ thị Prepare / Commit"| RM3["Bên tham gia RM3 (hàng đợi thông điệp)"]
    RM1 -->|"Vote(Yes/No)"| TM
    RM2 -->|"Vote(Yes/No)"| TM
    RM3 -->|"Vote(Yes/No)"| TM
    TM -.->|"force-write log quyết định"| LOG["Log giao dịch của bộ điều phối"]

Trong cấu trúc hình sao này, vai trò bộ điều phối có thể do một tiến trình quản lý giao dịch riêng đảm nhận, hoặc do một trong các nút tham gia kiêm nhiệm. Dù theo cách nào, bộ điều phối cấp mã định danh giao dịch (XID) để mọi bên tham gia cùng chỉ tới một giao dịch, đồng thời quản lý danh sách bên tham gia và kết quả bỏ phiếu. Khi bên tham gia được thêm động (tài nguyên mới được đăng ký giữa chừng giao dịch), bộ điều phối phải đưa nó vào tập bên tham gia, và thông tin đăng ký này cũng phải được lưu ổn định trước khi quyết định thì sau khi khởi động lại mới có thể thông báo quyết định cho tất cả mà không bỏ sót. Tóm lại, bộ điều phối là điểm thẩm quyền duy nhất chịu trách nhiệm cả về thành viên "ai thuộc giao dịch này" lẫn kết quả "đã quyết định gì".

Bộ điều phối và bên tham gia mỗi bên đều ghi trạng thái của mình vào log trên bộ nhớ ổn định (stable storage). Log này là trụ cột nâng đỡ độ tin cậy của giao thức. Trước khi bỏ phiếu "Yes", bên tham gia phải ghi bắt buộc xuống đĩa trước mọi thay đổi mà nó có thể commit dưới dạng log REDO/UNDO; nhờ vậy dù có sự cố sau khi bỏ phiếu, khi khởi động lại vẫn có thể hoàn tất commit hoặc abort theo quyết định cuối cùng của bộ điều phối. Tương tự, bộ điều phối chỉ thông báo cho bên tham gia sau khi đã ghi bắt buộc quyết định cuối cùng (global commit/abort) vào log. Nếu nguyên tắc WAL (Write-Ahead Logging) "ghi trước, thông báo sau" này không được tuân thủ, sau sự cố mỗi nút có thể đi tới kết luận khác nhau và tính nguyên tử bị phá vỡ.

Mặt khác, khoảng thời gian từ lúc bên tham gia bỏ phiếu "Yes" đến khi nhận được thông báo cuối cùng được gọi là trạng thái không chắc chắn (in-doubt/uncertain). Bên tham gia ở trạng thái này không thể tự quyết định commit hay abort mà chỉ có thể chờ chỉ thị của bộ điều phối, và trong thời gian đó vẫn tiếp tục giữ khóa (lock) trên tài nguyên liên quan. Sự tồn tại của khoảng không chắc chắn chính là nguyên nhân trực tiếp của vấn đề chặn và suy giảm hiệu năng của 2PC, đồng thời là mục tiêu mà 3PC muốn giải quyết.

Xét về độ phức tạp thông điệp, khi có N bên tham gia, 2PC chuẩn đòi hỏi tối thiểu 3N thông điệp tính từ bộ điều phối (Prepare N + Decision N + ACK N), cùng 1 lần ghi bắt buộc log ở bộ điều phối và 2 lần ở mỗi bên tham gia. Các vòng khứ hồi đồng bộ và I/O đĩa này quy định cận dưới của độ trễ, nên số bên tham gia càng nhiều hoặc phân tán địa lý càng rộng thì độ trễ commit càng tăng hơn tuyến tính. Đây là lý do các tối ưu như giả định hủy bỏ ra đời để giảm chi phí này, và với phân tán quy mô lớn thì thay hẳn giao thức bằng cơ chế dựa trên đồng thuận sẽ có lợi hơn.

3. Thủ tục cam kết hai pha (2PC)

Đúng như tên gọi, 2PC gồm hai vòng: pha bỏ phiếu (Voting/Prepare Phase) và pha hoàn tất (Completion/Commit Phase). Ở pha đầu, bộ điều phối gửi PREPARE tới mọi bên tham gia để hỏi "đã sẵn sàng commit chưa", mỗi bên thực thi·kiểm chứng giao dịch cục bộ, ghi bắt buộc log rồi trả lời Yes(Ready) hoặc No(Abort). Ở pha thứ hai, bộ điều phối tổng hợp phiếu và nếu chỉ cần một bên No hoặc không phản hồi thì quyết định hủy bỏ toàn cục, còn nếu tất cả Yes thì quyết định commit toàn cục, ghi vào log rồi thông báo cho tất cả bên tham gia. Bên tham gia xác nhận commit/abort theo thông báo và gửi lại ACK; bộ điều phối kết thúc giao dịch khi nhận đủ ACK.

Sơ đồ tuần tự dưới đây thể hiện từng bước của đường commit bình thường. Mỗi mũi tên là một vòng khứ hồi mạng; cần chú ý rằng với N bên tham gia, có tối thiểu 2 vòng phát quảng bá và nhiều lần ghi bắt buộc log. Các vòng khứ hồi đồng bộ này quy định giới hạn về độ trễ (latency) và thông lượng của 2PC.

sequenceDiagram
    participant C as Bộ điều phối (Coordinator)
    participant P1 as Bên tham gia P1
    participant P2 as Bên tham gia P2
    Note over C,P2: Pha 1 - Chuẩn bị (Prepare/Voting)
    C->>P1: PREPARE
    C->>P2: PREPARE
    P1->>P1: Thực thi cục bộ + force-write log
    P2->>P2: Thực thi cục bộ + force-write log
    P1-->>C: Vote Yes(Ready)
    P2-->>C: Vote Yes(Ready)
    Note over C,P2: Pha 2 - Hoàn tất (Commit/Completion)
    C->>C: Ghi log quyết định COMMIT toàn cục
    C->>P1: GLOBAL COMMIT
    C->>P2: GLOBAL COMMIT
    P1-->>C: ACK
    P2-->>C: ACK
    Note over C,P2: Bộ điều phối kết thúc giao dịch sau khi nhận mọi ACK

A. Ý nghĩa của pha chuẩn bị và việc giữ khóa. Việc bên tham gia bỏ phiếu Yes không chỉ là một phản hồi mà là một cam kết "tôi bảo đảm có thể commit giao dịch này trong bất kỳ tình huống nào sau đây". Do đó, trước khi bỏ phiếu phải kiểm chứng mọi điều kiện quyết định sự thành công của commit như ràng buộc toàn vẹn, trigger, dung lượng đĩa trống, và nắm giữ ổn định phần thay đổi cùng khóa. Từ thời điểm này, bên tham gia giữ khóa độc quyền trên các bản ghi liên quan cho tới khi có thông báo cuối cùng, nên các giao dịch khác phải chờ tài nguyên đó. Cấu trúc trong đó một giao dịch phân tán giữ khóa của nhiều nút trong thời gian dài làm thông lượng giảm mạnh; trong thực tế, thường gặp trường hợp một 2PC gây ra thời gian giữ khóa từ vài chục đến vài trăm mili giây và trở thành nút thắt cổ chai ở các dịch vụ có TPS cao.

Vì tính chất khế ước này, pha chuẩn bị về thực chất phải là trạng thái "đã thực thi xong, chỉ hoãn việc xác nhận". Nếu bên tham gia đã bỏ phiếu Yes nhưng thực tế rơi vào tình trạng không thể commit (khóa bị giải phóng, phiên kết thúc, tài nguyên bị thu hồi) thì tính nguyên tử sụp đổ, nên bộ quản lý tài nguyên đặc biệt bảo vệ giao dịch sau phiếu Yes (cô lập trạng thái prepared). Vì vậy pha chuẩn bị tiêu tốn nhiều tài nguyên, và nếu bộ điều phối không phản hồi lâu thì các giao dịch prepared tích tụ lại, gây tác dụng phụ ăn mòn tài nguyên. Người vận hành phải giám sát các giao dịch in-doubt như vậy và đặt ra chính sách chỉ cho phép can thiệp quản trị (heuristic decision) như phương án cuối cùng.

B. Pha hoàn tất và các tối ưu (Presumed Abort/Commit). 2PC chuẩn đòi hỏi nhiều I/O log: ghi log quyết định, thông báo, thu ACK và ghi log kết thúc. Để giảm bớt, các tối ưu giả định hủy bỏ (Presumed Abort) và giả định cam kết (Presumed Commit) được sử dụng rộng rãi. Giả định hủy bỏ tận dụng tính chất rằng bộ điều phối trả lời "đã hủy bỏ" cho các truy vấn về giao dịch mà nó đã mất thông tin (không có trong log) vẫn an toàn, từ đó bỏ qua ghi log và ACK khi hủy bỏ. Hầu hết DBMS thương mại (ví dụ giao dịch phân tán của Oracle, các cài đặt X/Open XA) mặc định chọn giả định hủy bỏ để giảm tối đa chi phí trên đường commit bình thường. Triết lý thiết kế "làm cho đường đi thường xuyên trở nên rẻ" này là nguyên lý chung của các hệ thống giao dịch.

C. Kịch bản thất bại và vấn đề chặn. Điểm yếu chí mạng của 2PC lộ ra khi bộ điều phối chết sau pha 1. Nếu bộ điều phối sập ngay sau khi mọi bên tham gia đã bỏ phiếu Yes và vào trạng thái không chắc chắn, các bên tham gia không có cách nào biết quyết định cuối cùng là commit hay abort. Tự commit thì có rủi ro bộ điều phối đã quyết định abort, tự abort thì có rủi ro ngược lại, nên bên tham gia phải chờ vô hạn (blocking) cho tới khi bộ điều phối phục hồi và tiếp tục giữ khóa. Hiện tượng chặn này là khiếm khuyết căn bản về mặt tính sẵn sàng, khiến sự cố của một nút làm dừng tiến trình của toàn hệ thống. Giao thức kết thúc hợp tác (cooperative termination), trong đó các bên tham gia hỏi lẫn nhau, có thể giải quyết một số tình huống (khi đã có ai đó nhận được quyết định), nhưng nếu tất cả đều ở trạng thái không chắc chắn thì vẫn chỉ có thể chờ.

D. Quy tắc phục hồi theo điểm xảy ra sự cố. Sự vững chắc của giao thức đến từ việc "chết ở bất kỳ thời điểm nào thì sau khi khởi động lại vẫn hội tụ về kết luận đúng". Bảng dưới đây tổng hợp các quy tắc phục hồi theo vị trí xảy ra sự cố, và căn cứ của chúng đều nằm ở nguyên tắc ghi bắt buộc log (WAL) đã giải thích ở trên. Nếu bên tham gia chết trước khi bỏ phiếu thì log không có dấu vết nào nên có thể an toàn coi là hủy bỏ; nếu chết sau khi bỏ phiếu (trạng thái không chắc chắn) thì dựa trên bản ghi Ready trong log để hỏi lại bộ điều phối quyết định cuối cùng. Nếu bộ điều phối chết trước khi ghi log quyết định thì hủy bỏ, nếu chết sau khi đã ghi thì phát lại quyết định trong log.

Vị trí sự cố Trạng thái log Xử lý sau khi khởi động lại
Bên tham gia, trước khi bỏ phiếu Không có bản ghi Prepare Coi là hủy bỏ (giả định hủy bỏ)
Bên tham gia, sau khi bỏ phiếu (không chắc chắn) Có bản ghi Ready Hỏi lại bộ điều phối quyết định, giữ khóa cho tới lúc đó
Bộ điều phối, trước khi quyết định Không có bản ghi quyết định toàn cục Hủy bỏ toàn cục
Bộ điều phối, sau khi quyết định Có bản ghi Commit/Abort Phát lại quyết định đó tới các bên tham gia

Như bảng cho thấy, tính nhất quán của 2PC không bao giờ bị phá vỡ dưới bất kỳ tổ hợp sự cố nào. Tuy nhiên, mục "giữ khóa ở trạng thái không chắc chắn và chờ hỏi lại" chính là thực chất của hiện tượng chặn đã nêu, một lần nữa xác nhận sự căng thẳng căn bản giữa tính sẵn sàng và tính nhất quán.

4. Thủ tục cam kết ba pha (3PC) và so sánh

3PC là giao thức chia pha hoàn tất thêm một lần thành pha tiền cam kết (Pre-Commit) để giảm hiện tượng chặn của 2PC. Ý tưởng cốt lõi là "trước khi xác nhận commit, hãy lan truyền trước cho mọi người chính sự thật rằng tất cả đã sẵn sàng commit". Khi xác nhận mọi bên đều bỏ phiếu Yes, bộ điều phối không commit ngay mà phát PRE-COMMIT để các bên tham gia biết "sắp được commit", rồi chỉ sau khi nhận ACK của các bên mới gửi DO-COMMIT. Nhờ vậy, dù bộ điều phối chết, các bên tham gia còn sống có thể tự suy luận quyết định cuối cùng dựa trên việc mình đã nhận Pre-Commit hay chưa. Nếu có ai đã nhận Pre-Commit nghĩa là tất cả đều Yes nên kết thúc bằng commit; nếu không ai nhận thì kết thúc bằng hủy bỏ.

graph LR
    S0["Khởi tạo (Init)"] -->|"Nhận PREPARE, bỏ phiếu Yes"| S1["Sẵn sàng (Ready/Waiting)"]
    S1 -->|"Phiếu No hoặc hết thời gian chờ"| SA["Hủy bỏ (Abort)"]
    S1 -->|"Nhận PRE-COMMIT"| S2["Tiền cam kết (Pre-Commit)"]
    S2 -->|"Hết thời gian chờ (bộ điều phối lỗi)"| SC["Cam kết (Commit)"]
    S2 -->|"Nhận DO-COMMIT"| SC

Điểm chính của sơ đồ chuyển trạng thái trên là quy tắc khi hết thời gian chờ ở trạng thái tiền cam kết thì tiến tới commit chứ không phải hủy bỏ. Cơ chế "tự kết thúc dựa trên timeout" này khiến 3PC trở thành không chặn (non-blocking). Tức là dù bộ điều phối không phản hồi, các bên tham gia vẫn có thể tự kết thúc theo quy tắc định sẵn thay vì chờ vô hạn. Tuy nhiên, tính không chặn này chỉ đúng dưới tiền đề không có phân vùng mạng, chỉ có lỗi nút (giả định mạng đồng bộ). Thực tế khi xảy ra phân vùng mạng, hai nhóm bị chia cắt có thể đưa ra phán đoán timeout khác nhau, một bên commit còn bên kia hủy bỏ, dẫn đến bất nhất (split-brain). Vì thế, dù đẹp đẽ về lý thuyết, 3PC hầu như không được hệ thống thương mại chấp nhận; thay vào đó, cách tiếp cận dựa trên đồng thuận (Paxos/Raft) sẽ bàn ở phần nâng cao đã trở thành chuẩn thực tế.

Khác biệt giữa hai giao thức không chỉ nằm ở số pha mà ở chỗ dưới giả định thất bại nào thì từ bỏ thuộc tính nào. Bảng dưới đây tổng hợp đánh đổi đó, và "lý do" của mỗi mục dựa trên phần trình bày ở trên.

Phân loại Cam kết hai pha (2PC) Cam kết ba pha (3PC)
Số vòng 2 pha (Prepare→Commit) 3 pha (Prepare→Pre-Commit→Commit)
Khi bộ điều phối lỗi Xảy ra chặn (chờ vô hạn) Kết thúc không chặn nhờ timeout
Phân vùng mạng An toàn (giữ nhất quán, đổi lại phải chờ) Rủi ro bất nhất (split-brain)
Thông điệp/độ trễ Ít (2 vòng khứ hồi) Nhiều (3 vòng khứ hồi, tăng độ trễ)
Mức áp dụng thực tế Rộng rãi (XA, JTA, DBMS) Hiếm (chủ yếu cho lý thuyết·giảng dạy)

Hàm ý thực tiễn rút ra ở đây là rõ ràng. 2PC hy sinh tính sẵn sàng (Liveness) để có tính nhất quán (Safety), còn 3PC đạt tính sẵn sàng trong một mô hình thất bại nhất định nhưng phải chấp nhận rủi ro nhất quán khi phân vùng và độ trễ cũng tăng. Rốt cuộc, bóng của định lý bất khả FLP (Fischer-Lynch-Paterson) — "không thể đạt cam kết nguyên tử hoàn hảo một cách không chặn trong mạng bất đồng bộ" — phủ lên cả hai giao thức.

Xét cụ thể hơn lý do 3PC bị thực tế ngó lơ: thứ nhất, độ trễ tăng do vòng bổ sung là khó chấp nhận với phần lớn workload; thứ hai, giả định "mạng đồng bộ·chỉ có lỗi nút" để tính không chặn của 3PC thành lập không khớp với trung tâm dữ liệu thực tế (độ trễ biến thiên·phán đoán timeout sai·phân vùng cục bộ); thứ ba, với cùng công sức, sao chép bộ điều phối bằng Paxos/Raft là giải pháp tốt hơn, vừa giữ được nhất quán ngay cả khi phân vùng vừa đạt tính sẵn sàng cao. Tức là, hiểu 3PC như "ý tưởng quá độ giữa 2PC và commit dựa trên đồng thuận" là chính xác.

5. Nâng cao: Ứng dụng thực tế và các phương án thay thế — XA, Saga, commit dựa trên đồng thuận

A. XA/DTP và liên kết tài nguyên không đồng nhất. Lĩnh vực mà 2PC còn sống rõ ràng nhất trong thực tế là liên kết tài nguyên không đồng nhất qua giao diện X/Open XA. Ví dụ, trong xử lý đơn hàng khi cần gộp việc cập nhật DB quan hệ và phát hành thông điệp JMS thành một đơn vị nguyên tử, trình quản lý giao dịch JTA (ví dụ Narayana, Atomikos) đăng ký hai tài nguyên bằng XA và commit bằng 2PC. Cách này cung cấp nhất quán mạnh nhưng có ràng buộc là thời gian giữ khóa dài và nếu một bộ quản lý tài nguyên không hỗ trợ XA thì toàn bộ không thể thực hiện. Vì thế, trong miền thanh toán·đơn hàng đòi hỏi hiệu năng cao, ngày càng nhiều trường hợp đi vòng bằng Outbox pattern + CDC, đưa việc phát hành thông điệp vào trong giao dịch DB thay cho XA.

Phần đặc biệt cần chú ý khi vận hành XA là quyết định heuristic (heuristic outcome). Khi phản hồi của bộ điều phối bị trễ kéo dài, bộ quản lý tài nguyên có thể cưỡng chế commit/rollback giao dịch prepared bằng can thiệp quản trị hoặc chính sách riêng; khi đó nếu lệch với quyết định cuối cùng của bộ điều phối thì một vi phạm nhất quán gọi là heuristic mixed/hazard được ghi nhận. Đây là sự bất nhất dữ liệu không tự phục hồi, nên tiêu chuẩn vận hành nhất định phải bao gồm điều kiện cho phép quyết định heuristic, cảnh báo khi xảy ra và thủ tục điều chỉnh nhất quán thủ công sau đó. Tức là cần nhận thức rằng áp dụng 2PC là quyết định gánh vác không chỉ "nhất quán mạnh trên đường bình thường" mà cả "gánh nặng vận hành trên đường ngoại lệ".

B. Saga và nhất quán cuối cùng. Microservice có nguyên tắc "database-per-service", mỗi dịch vụ sở hữu DB riêng, nên khóa toàn cục của 2PC về căn bản không phù hợp. Phương án thay thế được dùng rộng rãi là Saga pattern: chia một giao dịch nghiệp vụ thành chuỗi các giao dịch cục bộ và khi thất bại thì hoàn tác bằng giao dịch bù trừ (compensating transaction). Saga không giữ khóa lâu nên khả năng mở rộng vượt trội, nhưng phải chấp nhận nhất quán cuối cùng (eventual consistency) khi trạng thái trung gian bị lộ ra bên ngoài, và do tính cô lập yếu nên cần bổ trợ ở mức ứng dụng như semaphore·kiểm tra phiên bản. Tức là nhất quán mạnh của 2PC và tính sẵn sàng cao của Saga là vấn đề lựa chọn theo góc nhìn CAP, cần quyết định dựa trên mức yêu cầu nhất quán của miền nghiệp vụ.

Để so sánh cụ thể, hãy giả định một luồng thanh toán thương mại điện tử phải xử lý hàng nghìn đơn hàng mỗi giây. Nếu gộp ba dịch vụ phê duyệt thanh toán·trừ tồn kho·tích điểm bằng 2PC (XA), khóa của ba nút được giữ vài chục đến vài trăm ms mỗi giao dịch, khiến thông lượng hữu hiệu tụt mạnh do tranh chấp khóa, và sự cố tức thời của một dịch vụ bất kỳ chặn toàn bộ việc thanh toán. Ngược lại, nếu cấu thành cùng luồng đó bằng Saga dạng orchestration, mỗi dịch vụ commit·giải phóng giao dịch cục bộ ngay nên thông lượng tăng vài lần, nhưng phải thiết kế để người dùng và logic quyết toán chịu được khoảng bất nhất trung gian như "thanh toán đã được duyệt nhưng trừ tồn kho thất bại → bù trừ bằng hủy thanh toán". Khoảng cách về thông lượng·nhất quán khi hiện thực cùng một yêu cầu bằng hai cách như vậy cho thấy lựa chọn giao thức chính là quyết định kiến trúc.

C. Cam kết nguyên tử dựa trên đồng thuận. Cách tiếp cận giải quyết tận gốc điểm yếu phân vùng của 3PC là Paxos Commit và commit dựa trên Raft. Ý tưởng là để quyết định của bộ điều phối không do một nút mà do một nhóm đồng thuận được sao chép đưa ra, qua đó hấp thụ sự cố của bộ điều phối bằng cơ chế bầu leader của giao thức đồng thuận. Google Spanner là ví dụ tiêu biểu hiện thực nguyên lý này ở quy mô lớn: đặt 2PC lên trên mỗi shard (nhóm Paxos) nhưng sao chép cả trạng thái của bộ điều phối và bên tham gia, loại bỏ đồng thời hiện tượng chặn và SPOF, và bảo đảm cả nhất quán ngoài (external consistency) bằng TrueTime (đồng hồ nguyên tử + GPS). Đây được đánh giá là chuẩn mực hiện đại kết hợp "tính nguyên tử của 2PC + tính sẵn sàng cao của đồng thuận". Như vậy, xu hướng thực tế đã tiến hóa theo hướng không bỏ 2PC mà bổ sung điểm yếu của nó — độ tin cậy của bộ điều phối — bằng đồng thuận.

D. Hướng ra đề dự kiến và chiến lược xây dựng bài làm. Trong kỳ thi Kỹ sư chuyên nghiệp, chủ đề này có xu hướng xuất hiện như luận cứ cốt lõi của các câu hỏi cấp cao hơn như "phương án bảo đảm tính nguyên tử của giao dịch phân tán", "nhất quán dữ liệu trong MSA", "so sánh CAP/BASE với nhất quán mạnh" hơn là được ra đề độc lập. Do đó, bài làm nên (1) trình bày chính xác thủ tục 2PC và nguyên lý log bằng sơ đồ tuần tự, (2) chỉ rõ vấn đề chặn, rồi (3) liên kết tới giới hạn của 3PC và các phương án Saga·Paxos Commit, kết thúc bằng mạch lập luận "vì sao nhất quán mạnh đắt và thực tế thỏa hiệp ra sao" — cách cấu trúc này có lợi cho điểm cao. Nếu ra ở dạng trả lời ngắn (tiết 1), trình bày cô đọng cốt lõi "2PC = bảo đảm nguyên tử, nhược điểm = chặn, phương án thay thế = 3PC/Saga" kèm bảng.

6. Các lưu ý và hàm ý

Giao thức cam kết nguyên tử là chủ đề thể hiện rõ nét nhất mệnh đề "nhất quán mạnh trong môi trường phân tán không miễn phí". Từ góc nhìn Kỹ sư chuyên nghiệp, vượt lên việc thuộc thủ tục, có thể tổng kết rằng lựa chọn giao thức chính là quyết định kiến trúc về tính sẵn sàng·hiệu năng·độ phức tạp vận hành như sau.

  • Lựa chọn tường minh đánh đổi nhất quán-sẵn sàng (chiến lược áp dụng): cần định nghĩa trước yêu cầu nhất quán theo từng miền rồi mới chọn giao thức, chẳng hạn miền tài chính·tồn kho bắt buộc tính nguyên tử mạnh thì dùng 2PC/XA, còn dịch vụ hướng người dùng ưu tiên quy mô và tính sẵn sàng thì dùng Saga·nhất quán cuối cùng dựa trên sự kiện. "2PC trên toàn tuyến" là anti-pattern làm hại khả năng mở rộng.
  • Bảo đảm tính sẵn sàng cao cho bộ điều phối (quản lý đánh đổi): SPOF của bộ điều phối — rủi ro lớn nhất của 2PC — cần được giảm nhẹ bằng sao chép log bộ điều phối, bộ điều phối dự phòng (standby), và xa hơn là sao chép bộ điều phối dựa trên Paxos/Raft. Chỉ đơn thuần áp dụng 3PC lại mang tới tăng độ trễ và rủi ro nhất quán khi phân vùng nên cần thận trọng.
  • Thời gian giữ khóa và quan sát hiệu năng (vận hành): cần giám sát thường xuyên thời gian giữ khóa của giao dịch phân tán, số giao dịch in-doubt, I/O log của bộ điều phối, và quy định rõ chính sách timeout cùng tự giải quyết (heuristic decision). heuristic commit/rollback có thể phá vỡ nhất quán nên nhất định phải đi kèm log kiểm toán và kiểm chứng nhất quán sau đó.
  • Liên kết tiêu chuẩn·công nghệ và triển vọng (công nghệ liên quan): XA/JTA, Outbox+CDC, orchestration Saga, commit dựa trên đồng thuận kiểu Spanner không loại trừ nhau mà được kết hợp theo tầng. Trong tương lai, dự báo sự trừu tượng hóa sẽ tiến triển theo hướng ứng dụng không trực tiếp xử lý giao thức commit mà ủy thác, nhờ bảo đảm nhất quán ngoài dựa trên TrueTime·đồng hồ logic lai (HLC) và sự phổ biến của DB phân tán được quản lý trên đám mây (NewSQL).
  • Nguyên tắc ra quyết định kiến trúc (phán đoán thiết kế): lựa chọn giao thức không nên quyết định bằng một con số hiệu năng mà phải là phán đoán dựa trên rủi ro, cân nhắc đồng thời chi phí khi vi phạm nhất quán của miền (tổn thất tài chính·quy định·niềm tin) và yêu cầu về độ trễ·tính sẵn sàng. "Thiết lập ranh giới nhất quán" — chỉ áp dụng cục bộ 2PC cho sổ cái (ledger) cốt lõi bắt buộc nhất quán mạnh và tách các miền xung quanh bằng Saga — là chuẩn mực thực tiễn.
  • Chiến lược kiểm thử·kiểm chứng (bảo đảm chất lượng): khiếm khuyết của commit phân tán lộ ra ở tổ hợp sự cố chứ không phải trên đường bình thường, nên cần đưa vào CI kiểm thử chaos tiêm việc buộc dừng ở từng pha của bộ điều phối/bên tham gia và tự động hóa kiểm chứng lại nhất quán (reconciliation) sau sự cố. Chỉ kiểm chứng "bình thường thì chạy tốt" là không đủ để tin vào bảo đảm tính nguyên tử.

Tài liệu tham khảo


Tóm tắt một câu: 2PC bảo đảm tính nguyên tử của giao dịch phân tán bằng hai pha bỏ phiếu chuẩn bị·hoàn tất nhưng có điểm yếu chặn khi bộ điều phối lỗi, 3PC thêm pha tiền cam kết để hướng tới không chặn nhưng dễ tổn thương trước phân vùng mạng, nên thực tế thỏa hiệp giữa nhất quán và tính sẵn sàng theo từng miền bằng XA·Saga·commit đồng thuận dựa trên Paxos/Raft.