Hành trình đến giao dịch ACID trong Cassandra 6: Từ BATCH, Paxos đến Accord
Bài viết phân tích sự tiến hóa của Cassandra từ hệ thống NoSQL nhất quán cuối cùng đến cơ sở dữ liệu hỗ trợ giao dịch ACID với giao thức Accord trong phiên bản 6.0. Tác giả đã thiết lập cụm 3 nút và thử nghiệm bốn phương thức giao dịch khác nhau trên khối lượng công việc kế toán, từ đó so sánh ưu nhược điểm của từng phương pháp, đồng thời phát hiện một lỗi cô lập tiềm ẩn trong Accord.

Hành trình đến giao dịch ACID trong Cassandra 6: Từ BATCH, Paxos đến Accord
Cassandra, một trong những hệ quản trị cơ sở dữ liệu nguồn mở được ưa chuộng nhất cho các hệ thống phân tán quy mô lớn, đang tiến một bước dài tới khả năng hỗ trợ giao dịch ACID hoàn chỉnh. Trong bản phát hành 6.0 sắp tới, giao thức Accord hứa hẹn mang lại tính nhất quán nghiêm ngặt (strict serializability) cho các giao dịch xuyên partition — một tính năng mà trước đây Cassandra gần như không thể đáp ứng.
Bài viết này sẽ dẫn dắt bạn qua bốn “trạng thái” giao dịch của Cassandra: mặc định (không giao dịch), BATCH, Lightweight Transaction (LWT) dựa trên Paxos, và cuối cùng là Accord. Tất cả đều được kiểm chứng trên một cụm 3 nút với khối lượng công việc mô phỏng hoạt động chuyển tiền giữa các tài khoản — một bài toán kinh điển để kiểm tra tính toàn vẹn của dữ liệu.
Vì sao Cassandra lại “khó” với giao dịch?
Cassandra là một hệ thống hấp dẫn bởi sự kết hợp hiếm có: mã nguồn mở, ngôn ngữ truy vấn dạng SQL, khả năng phân mảnh (sharding) và nhân bản (replication) tích hợp sẵn. Được sử dụng bởi các ông lớn như Apple, eBay, Bloomberg, hay Netflix, Cassandra nổi tiếng với mô hình nhất quán cuối cùng (eventual consistency).
Tuy nhiên, điểm yếu cố hữu của nó là thiếu hỗ trợ join và mô hình dữ liệu được thiết kế dựa trên truy vấn (query-based modeling). Điều này buộc lập trình viên phải phi chuẩn hóa dữ liệu, biến một thao tác ghi logic thành nhiều thao tác ghi vật lý, và từ đó nảy sinh nhu cầu về các giao dịch để đảm bảo tính toàn vẹn.
Phương án 1: Cập nhật mặc định — Không có gì đảm bảo
Khi sử dụng các câu lệnh UPDATE thông thường, cả hai writer sẽ ghi đè lên nhau mà không có bất kỳ sự kiểm soát nào. Kết quả là độc giả (reader) thường xuyên quan sát thấy tổng số dư hai tài khoản không bằng 2.000 — vi phạm nghiêm trọng tính nhất quán. Trong thử nghiệm, có tới 939/1500 lần đọc cho kết quả sai lệch.
Cập nhật thường không tạo nên một ngân hàng tốt — ít nhất là với mô hình dữ liệu này.
Phương án 2: BATCH — Giải pháp cho một partition, nhưng vẫn còn thiếu sót
BATCH, hoàn thiện từ Cassandra 1.2 (2013), cho phép gom nhiều câu lệnh thành một mutation duy nhất. Với các thao tác ghi trong cùng một partition, BATCH đảm bảo tính nguyên tử (atomicity): hoặc tất cả được áp dụng, hoặc không gì được áp dụng. Tuy nhiên, có một cạm bẫy về timestamp:
- Tất cả câu lệnh trong BATCH dùng chung một timestamp.
- Nếu hai BATCH xung đột có cùng timestamp, Cassandra sẽ giải quyết theo cơ chế last-write-wins trên từng cell, dẫn đến kết quả có thể bị “trộn lẫn” giữa hai giao dịch.
Thử nghiệm cho thấy, dù đa số các lần chạy đều sạch, thỉnh thoảng vẫn xuất hiện tổng số dư lên tới 3.790 — khi cả hai cell đều giữ giá trị lớn từ hai BATCH khác nhau. Đây là hành vi có chủ đích, được tài liệu ghi rõ, nhưng không phải là tính năng lý tưởng.
Khi BATCH vượt qua ranh giới partition, vấn đề càng trở nên rõ ràng. Tính nguyên tử được giữ, nhưng tính cô lập (isolation) gần như không tồn tại — reader vẫn có thể thấy tổng số dư sai trong quá trình ghi. Với khối lượng công việc read-modify-write, BATCH gần như vô dụng vì một giao dịch đọc-sau-ghi (read-modify-write) không thể được bọc trong BATCH, dẫn đến thất bại thảm hại.
Phương án 3: Lightweight Transactions (LWT) — Paxos và so sánh-hoán đổi
Ra mắt trong Cassandra 2.0 (2013), LWT mang đến khả năng so sánh và hoán đổi (compare-and-swap) nguyên tử dựa trên thuật toán đồng thuận Paxos. Điểm mạnh lớn nhất của LWT so với BATCH là timestamp được tạo ra từ Paxos, đảm bảo tính duy nhất trên mỗi partition — xóa bỏ hoàn toàn vấn đề xung đột timestamp.
Tuy nhiên, LWT có một hạn chế: bạn không thể thực hiện một SELECT và UPDATE trong cùng một giao dịch nguyên tử. Để giải quyết, tác giả đã sử dụng kỹ thuật lưu trữ một “op token” (mã định danh thao tác) làm khóa idempotency, cho phép writer tự kiểm tra và thử lại.
Kết quả: LWT hoạt động tốt cho read-modify-write trong cùng một partition. Nhưng với giao dịch xuyên partition, LWT tỏ ra bất lực.
Phương án 4: Accord — Giao dịch ACID xuyên partition
Đây chính là điểm nhấn của Cassandra 6. Accord là một giao thức đồng thuận mới, hứa hẹn mang lại strict serializability — mức nhất quán mạnh nhất — cho các giao dịch xuyên partition. Với cú pháp mới:
BEGIN TRANSACTION \
LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
IF x.balance >= 1 THEN \
UPDATE lab.accounts SET balance -= 1 WHERE customer = 1 AND account_id = 1; \
UPDATE lab.accounts SET balance += 1 WHERE customer = 2 AND account_id = 1; \
END IF \
COMMIT TRANSACTION;
Cả hai thử nghiệm (cùng partition và xuyên partition) đều vượt qua với không một lỗi nào. Không chỉ tính nguyên tử được đảm bảo, mà cả tính cô lập cũng được giữ vững trong suốt quá trình chạy — một bước tiến vượt bậc so với các phương án trước.
Phát hiện về một lỗi tiềm ẩn
Điều thú vị nằm ở chỗ, trong các khối lượng công việc cùng partition sử dụng Accord, tác giả thỉnh thoảng quan sát thấy reader báo cáo tổng số dư không phải 2.000 — một dấu hiệu vi phạm tính cô lập. Dù kết quả cuối cùng không bao giờ sai, đây có thể là một lỗi trong giao thức.
Ngay cả khi đây là một lỗi, nó cũng không quá nghiêm trọng. Hệ thống phân tán luôn có lỗi. Và Cassandra 6 vẫn chưa được phát hành chính thức.
Một điểm đáng chú ý: C. Scott Andreas từ Apple — người có hiểu biết sâu sắc về Cassandra — đã xác nhận đây là một lỗi thực sự, không phải do sai sót trong code của tác giả.
Kết luận
Hành trình từ “không giao dịch” đến ACID của Cassandra phản ánh sự phát triển của cả một hệ sinh thái. Từ BATCH đơn giản, đến LWT dựa trên Paxos, và giờ là Accord — mỗi bước đều mở rộng khả năng của Cassandra, đưa nó từ một “kho lưu trữ” đơn thuần tiến gần hơn đến một hệ quản trị cơ sở dữ liệu đa dụng thực thụ.
Với sự xuất hiện của Accord trong Cassandra 6.0, các nhà phát triển Việt Nam đang xây dựng hệ thống tài chính, thanh toán hoặc bất kỳ ứng dụng nào yêu cầu tính toàn vẹn dữ liệu cao sẽ có thêm một lựa chọn mạnh mẽ từ nền tảng mã nguồn mở. Việc sở hữu một database phân tán hỗ trợ giao dịch ACID xuyên partition mà không phụ thuộc vào vendor là một lợi thế chiến lược đáng cân nhắc.