Hãy tưởng tượng bạn điều hành một công ty với hai văn phòng ở Hà Nội và TP.HCM. Hai bên vẫn liên lạc thường xuyên để thống nhất quyết định. Một ngày nọ, đường dây bị đứt. Cả hai văn phòng đều nghĩ: "Bên kia chắc gặp sự cố, tôi phải tự quyết để công ty không đứng yên." Kết quả là cả hai cùng tự xưng là trụ sở chính, đưa ra những quyết định giẫm chân nhau. Đó chính là split-brain: vấn đề kinh điển của mọi hệ phân tán (distributed system).
Split-brain là gì
Split-brain xảy ra khi phân vùng mạng (network partition) khiến các nhóm node trong cùng một hệ thống không còn liên lạc được với nhau, và mỗi nhóm đều tự cho rằng mình vẫn "sống" nên tiếp tục xử lý dữ liệu độc lập. Hậu quả thường gặp:
- Mâu thuẫn dữ liệu nghiêm trọng: một tài khoản ngân hàng có 1000$, bị split-brain thành hai nhóm A và B. Nhóm A xử lý lệnh rút 800$, nhóm B xử lý lệnh rút 700$ trên cùng tài khoản. Khi mạng nối lại, bạn có hai bản ghi mâu thuẫn: một nơi báo còn 200$, nơi kia báo còn 300$, trong khi thực tế tài khoản đã bị rút vượt quá số dư.
- Mất tính nhất quán (consistency): người dùng nhận kết quả khác nhau tuỳ vào việc họ đang kết nối tới node của nhóm nào, làm mất niềm tin vào hệ thống.
Vì sao vấn đề này khó giải quyết
Cái khó nằm ở một nghịch lý: làm sao phân biệt được "node kia đã thật sự chết" với "node kia chỉ đang tạm thời mất kết nối"? Ở góc nhìn của một node còn sống, cả hai tình huống đều biểu hiện giống hệt nhau: bạn gửi tín hiệu, không nhận được phản hồi. Không có cách nào để biết chắc chắn phía bên kia đã sập hẳn hay chỉ đang bị nghẽn mạng tạm thời, nên hệ thống không thể chỉ dựa vào "im lặng" để tự ý quyết định ai còn quyền lãnh đạo.
Cách hoạt động: quy tắc đa số ngăn split-brain
Cả Paxos và Raft đều giải quyết bài toán này theo cùng một nguyên tắc gốc: quorum (số node tối thiểu cần đồng ý trước khi một thay đổi được coi là hợp lệ), thường được tính là hơn một nửa tổng số node. Nếu một hệ thống có 5 node và bị phân vùng thành nhóm 2 và nhóm 3, chỉ nhóm 3 node mới đạt quorum (3 trên 5 là đa số), nên chỉ nhóm này được phép tiếp tục ghi dữ liệu. Nhóm 2 node còn lại buộc phải từ chối mọi lệnh ghi, dù nó hoàn toàn không biết nhóm kia còn sống hay đã chết.
Bạn có thể tự kiểm tra logic quorum này bằng vài dòng code. Đây không phải cài đặt đầy đủ Paxos hay Raft (hai thuật toán đó phức tạp hơn nhiều ở phần bầu leader và đồng bộ log), mà chỉ là phần lõi giúp bạn hình dung điều kiện "đủ đa số":
def has_quorum(alive_nodes: int, total_nodes: int) -> bool:
# Quorum = nhiều hơn một nửa tổng số node
return alive_nodes > total_nodes // 2
total = 5
group_a = 2 # bị cô lập sau phân vùng mạng
group_b = 3
print("Nhóm A đủ quorum:", has_quorum(group_a, total))
print("Nhóm B đủ quorum:", has_quorum(group_b, total))
Paxos: người tiên phong
Paxos được Leslie Lamport hình thành từ cuối những năm 1980, mô tả trong tài liệu kỹ thuật nội bộ, rồi công bố chính thức năm 1998 qua paper "The Part-Time Parliament" (xem mục Nguồn tham khảo bên dưới). Paxos hoạt động dựa trên nguyên tắc đa số (majority rule) đã nói ở trên: một thay đổi chỉ được coi là "đã commit" khi hơn một nửa số node chấp nhận nó. Với ví dụ 5 node ở trên, khi phân vùng chia thành nhóm A (2 node) và nhóm B (3 node), chỉ nhóm B mới có thể xử lý giao dịch ghi; nhóm A từ chối toàn bộ để tránh tạo ra dữ liệu mâu thuẫn.
Raft: phiên bản dễ hiểu hơn
Raft được Diego Ongaro và John Ousterhout giới thiệu năm 2014 qua paper "In Search of an Understandable Consensus Algorithm" (xem Nguồn tham khảo), với mục tiêu rõ ràng ngay từ tên paper: dễ hiểu hơn Paxos nhưng vẫn giải quyết cùng một bài toán đồng thuận (consensus).
Raft dùng mô hình leader-follower tường minh: chỉ leader được xử lý ghi, và leader chỉ đắc cử khi nhận đủ phiếu đồng ý từ đa số cluster. Khi phân vùng mạng xảy ra, nếu leader cũ chỉ còn liên lạc được với nhóm thiểu số, nó tự nhận ra mình đã mất quyền (thường qua việc không nhận đủ phản hồi "heartbeat" từ đa số) và tự chuyển về trạng thái follower, ngừng xử lý ghi. Trong khi đó nhóm đa số bầu leader mới và tiếp tục hoạt động. Cơ chế này đảm bảo tại mọi thời điểm chỉ có tối đa một leader hợp lệ trong toàn cluster.
Vì sao cả hai đều "hy sinh" tính sẵn sàng
Bạn có thể thắc mắc: sao không để cả hai nhóm cùng hoạt động để hệ thống luôn sẵn sàng (availability)? Vấn đề nằm ở chỗ nếu cho phép cả hai nhóm ghi độc lập, bạn sẽ tạo ra những thay đổi xung đột không thể tự động hoà giải sau này (giống ví dụ tài khoản 1000$ bị rút vượt số dư ở trên). Một đường dây mạng đứt thì có thể nối lại, nhưng dữ liệu đã ghi sai thì không thể "nối lại" một cách chính xác và tự động. Vì vậy cả Paxos lẫn Raft đều chọn chấp nhận từ chối phục vụ (giảm availability) ở phía thiểu số, để đổi lấy việc dữ liệu không bao giờ mâu thuẫn (giữ consistency).
- Số node nên là số lẻ. Với cluster 4 node, một phân vùng 2-2 khiến không nhóm nào đạt quorum, cả hệ thống ngừng ghi hoàn toàn. Đáng nói hơn: cluster 4 node cũng chỉ chịu được tối đa 1 node lỗi, y hệt cluster 3 node, tức thêm một node mà không thêm chút khả năng chịu lỗi nào, lại rước thêm nguy cơ chia đôi bế tắc. Chỉ khi lên tới 5 node, hệ thống mới thực sự chịu được tối đa 2 node lỗi, nên 3 hoặc 5 node thường được chọn hơn 4.
- Paxos và Raft chỉ chống được lỗi dừng đột ngột (crash fault), không chống được node "nói dối" hoặc bị tấn công (Byzantine fault). Nếu cần chống cả trường hợp node độc hại cố tình gửi thông tin sai, bạn cần nhóm thuật toán khác (Byzantine fault tolerance), không phải Raft/Paxos thuần.
- Đừng tự viết lại Paxos/Raft từ đầu cho production. Cả hai đều có nhiều chi tiết cài đặt tinh vi rất dễ làm sai (edge case về log, về nhiệm kỳ leader...). Hầu hết dự án thực tế dùng lại qua etcd, Consul, ZooKeeper (dùng thuật toán Zab, họ hàng gần với Paxos) thay vì tự cài đặt.
- Quorum giải quyết split-brain ở tầng đồng thuận dữ liệu. Nếu bạn chỉ cần khoá phân tán (distributed lock) đơn giản, vẫn nên kèm thêm cơ chế "fencing token" để chặn trường hợp một tiến trình tưởng mình còn giữ khoá nhưng thực ra đã hết hạn.
Câu hỏi để suy ngẫm
Nếu bạn thiết kế một ứng dụng chat nhóm thay vì hệ thống ngân hàng, liệu bạn có chấp nhận một chút không nhất quán (inconsistency) tạm thời để đổi lấy tính sẵn sàng cao hơn không? Vì sao use case (ngân hàng so với chat) lại ảnh hưởng tới việc bạn chọn ưu tiên consistency hay availability?
Tóm tắt
- Split-brain xảy ra khi phân vùng mạng khiến nhiều nhóm node cùng tự nhận mình có quyền xử lý dữ liệu, dẫn tới ghi mâu thuẫn.
- Paxos và Raft ngăn split-brain bằng quy tắc quorum: chỉ nhóm nắm giữ đa số node mới được phép ghi.
- Paxos (Lamport, cuối thập niên 1980, công bố 1998) là nền tảng lý thuyết; Raft (Ongaro và Ousterhout, 2014) là bản diễn giải dễ hiểu hơn, dùng mô hình leader-follower rõ ràng.
- Cả hai đều đánh đổi availability lấy consistency khi có partition, đúng theo tinh thần của CAP theorem.
- Trong thực tế, nên dùng lại cài đặt đã kiểm chứng (etcd, Consul, ZooKeeper) thay vì tự viết Paxos/Raft từ đầu; số node cluster nên là số lẻ.
Nguồn tham khảo
- Leslie Lamport, "The Part-Time Parliament" (Paxos), ACM Transactions on Computer Systems, 1998 - lamport.azurewebsites.net/pubs/lamport-paxos.pdf
- Diego Ongaro, John Ousterhout, "In Search of an Understandable Consensus Algorithm" (Raft), USENIX ATC, 2014 - raft.github.io/raft.pdf
- Kai