Định lý CAP là gì? Tính nhất quán, sẵn sàng và phân vùng mạng

Định lý CAP là nguyên lý nền tảng trong thiết kế hệ thống phân tán, phát biểu rằng một cơ sở dữ liệu phân tán không thể đồng thời bảo đảm cả tính nhất quán, tính sẵn sàng và khả năng chịu lỗi phân vùng mạng. Bài viết này giải thích CAP là gì, ý nghĩa thực tiễn của từng thành phần và vì sao định lý này thường được hiểu sai trong phỏng vấn kỹ thuật.

Sơ đồ ba thành phần của định lý CAP: Consistency, Availability và Partition tolerance với các vùng giao nhau

Định lý CAP là gì?

Định lý CAP — còn gọi là định lý Brewer — được nhà khoa học máy tính Eric Brewer đề xuất và sau đó được chứng minh chặt chẽ bởi Sagi Gilbert và Nancy Lynch. Cả hai bài đăng tại Wikipedia: CAP theorem.

Định lý phát biểu rằng khi mạng bị chia cắt thành hai phần không liên lạc được, hệ thống phân tán buộc phải lựa chọn: hoặc giữ tính nhất quán bằng cách từ chối phục vụ, hoặc giữ tính sẵn sàng bằng cách trả về dữ liệu có thể đã cũ. Không có cách nào thoát khỏi ngưỡng lựa chọn này.

Điểm quan trọng nhất cần nhấn mạnh: ngưỡng lựa chọn chỉ phát sinh khi có phân vùng mạng thực sự. Trong điều kiện bình thường, hệ thống vẫn có thể đạt cả ba thuộc tính cùng lúc. Vì vậy câu nói “hệ thống phân tán chỉ chọn được hai trong ba” là cách giải thích đơn giản hóa, dù dễ nhớ.

Sơ đồ định lý PACELC mở rộng CAP với nhánh Else về đánh đổi giữa độ trễ và tính nhất quán

Ba thành phần của CAP

Consistency (tính nhất quán). Mọi lần đọc đều nhận được giá trị mới nhất từ một lần ghi nào đó, hoặc báo lỗi. Nói cách khác, mọi node đều thấy cùng một trạng thái dữ liệu tại cùng một thời điểm. Yêu cầu này rất đắt: một lần ghi chỉ được coi là thành công khi nó đã được nhân bản tới toàn bộ các node còn lại.

Availability (tính sẵn sàng). Mỗi yêu cầu gửi tới một node đang hoạt động phải nhận được phản hồi — khung hồi chẩn đoán trong thời gian hữu hạn. Lưu ý phản hồi này không bắt buộc phải chứa bản dữ liệu mới nhất. Đây là định nghĩa của Gilbert và Lynch, khác với khái niệm high availability trong kiến trúc phần mềm.

Partition tolerance (khả năng chịu lỗi phân vùng). Hệ thống tiếp tục hoạt động bình thường dù mạng có tùy ý số lượng tin nhắn bị mất hoặc bị trễ giữa các node.

Yếu tố Ý nghĩa thực tế Cách đo
Consistency Tất cả node cùng thấy một trạng thái Đọc sau ghi phải thấy giá trị mới nhất
Availability Luôn có phản hồi cho mọi yêu cầu Tỉ lệ yêu cầu nhận được câu trả lời
Partition tolerance Không sập khi mạng đứt đoạn Thời gian hoạt động liên tục qua sự cố mạng

Phân vùng mạng không phải lỗi hiếm gặp

Đây là điểm mà nhiều lập trình viên hiểu sai. Mạng phân tán luôn có phân vùng: một switch hỏng, một sợi cáp bị đào, một vùng cloud gặp sự cố, hay đơn giản là một packet bị mất trên đường đi. Trong hệ phân tán quy mô lớn, phân vùng là bình thường, không phải ngoại lệ.

Vì vậy câu hỏi thực tế mà định lý CAP buộc bạn phải trả lời không phải “nên chọn hai trong ba”, mà là:

  • CP — chấp nhận không sẵn sàng để giữ nhất quán. Ví dụ: MongoDB với thiết lập đa số phiếu, HBase, ZooKeeper. Phù hợp khi dữ liệu sai còn tệ hơn không có dữ liệu, như hệ thống đồng thuận, khóa phân tán, kho chứng từ.
  • AP — chấp nhận dữ liệu có thể cũ để luôn sẵn sàng. Ví dụ: Cassandra, Riak, DynamoDB với eventual consistency. Phù hợp cho mạng xã hội, cập nhật số liệu, nơi người dùng chấp nhận nhìn thấy dữ liệu chậm vài giây.
  • CA — bảo đảm nhất quán và sẵn sàng, nhưng chỉ khi không có phân vùng. Đây là lựa chọn của một cơ sở dữ liệu đơn máy như PostgreSQL hay MySQL chạy trên một node. Không mở rộng được ra nhiều node mà vẫn giữ đảm bảo này.

Định lý PACELC — mở rộng đầy đủ hơn

Định lý CAP chỉ mô tả tình huống khi hệ thống đang gặp sự cố. Phần còn lại của thời gian — khi mọi thứ hoạt động bình thường — cũng có một sự đánh đổi: latency hay consistency. Đây chính là nội dung của chữ E trong PACELC:

  • Nếu có Partition — phải chọn giữa Availability hay Consistency.
  • Else (nếu không có phân vùng) — vẫn phải chọn giữa P (latency, tức độ nhất quán) hay Consistency.

Nói cách khác, ngay cả khi mọi node đều hoạt động, bạn vẫn phải trả giá. Quyết định đọc trong vùng đồng ý (consistency zone) sẽ chậm hơn nhưng chính xác; quyết định đọc ở gần người dùng sẽ nhanh hơn nhưng có thể dữ liệu cũ. Đây chính là lý do các hệ thống như Cassandra có cấu hình read consistency tùy chỉnh theo từng loại truy vấn.

Ảnh minh họa các thành phần của hệ thống tài chính phân tán trong bài giải thích định lý CAP

Áp dụng định lý CAP vào thiết kế hệ thống

Ví dụ một hệ thống cho phép người dùng đặt vé sự kiện. Nếu có hai người cùng mua được chỗ cuối cùng ở hai node khác nhau, hệ thống đã vi phạm tính nhất quán nghiêm trọng. Vì vậy ở bước giữ chỗ, hệ thống buộc phải ưu tiên C — dù phải chậm hơn và có thể báo lỗi cho người dùng khi hệ thống quá tải.

Nhưng ở màn hình danh sách sự kiện, việc người dùng không thấy sự kiện mới vừa được thêm trong 2 giây là không đáng kể. Ở đây ưu tiên A — luôn trả về kết quả, chấp nhận dữ liệu hơi cũ.

Cùng một hệ thống, hai thành phần khác nhau chọn hướng khác nhau. Đó là cách định lý CAP thực sự trở thành công cụ thiết kế chứ không phải gánh nhãn lý thuyết.

Những hiểu lầm phổ biến

“CAP bắt ta phải bỏ một trong ba luôn.” Sai. Sự đánh đổi chỉ xảy ra khi có phân vùng mạng. Ngoài điều kiện đó, hệ thống có thể đạt cả ba. Đây là lý do nhiều tài liệu kiến trúc hiện đại khuyến nghị dùng khung PACELC thay vì CAP đơn thuần.

“Consistency trong CAP giống consistency của ACID.” Không đúng. Consistency của CAP là mô hình linearizable — mọi lần đọc thấy trạng thái mới nhất, tức mạnh hơn nhiều so với tính nhất quán cấp độnh của ACID.

“Chọn CP nghĩa là hệ thống sẽ sập.” Chọn CP nghĩa là hệ thống từ chối phục vụ một phần yêu cầu trong lúc phân vùng để không phục vụ dữ liệu sai. Nó vẫn hoạt động, chỉ là chọn an toàn hơn là chọn sẵn sàng.

CAP và các công nghệ phổ biến

Cơ sở dữ liệu Hướng CAP Ghi chú
PostgreSQL đơn node CA Không có phân vùng khi chạy một node
etcd / ZooKeeper CP Ưu tiên nhất quán tuyệt đối cho đồng thuận
MongoDB đa node CP Mặc định dùng Write Concern đa số phiếu
Cassandra / Riak AP Cho phép cấu hình consistency tùy truy vấn
DynamoDB AP Eventual consistency mặc định

Kết luận

Định lý CAP không phải lựa chọn bị áp đặt từ trên xuống mà là công cụ để đặt câu hỏi đúng: trong hệ thống của bạn, lúc nào việc mất tính nhất quán là không chấp nhận được, và lúc nào độ trễ thấp quan trọng hơn? Hệ thống tốt là hệ thống trả lời được câu hỏi này rõ ràng, thay vì mặc định chọn theo thói quen.

Điều đáng nhớ nhất: trong một hệ phân tán thực sự, phân vùng mạng luôn xảy ra. Vì vậy câu hỏi không phải “nên bỏ thuộc tính nào”, mà là khi mạng đứt, hệ thống của bạn sẽ hành xử theo hướng nào — và người dùng có chấp nhận được hành vi đó không.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Huffman coding là gì? Thuật toán nén dữ liệu theo tần suất ký tự

Huffman coding là gì? Thuật toán nén dữ liệu theo tần suất ký tự Sơ đồ cây Huffman dựng từ tần suất bốn ký tự, mỗi lá là một ký…

Xem thêm

HyperLogLog là gì? Cấu trúc dữ liệu xác suất đếm phần tử duy nhất

HyperLogLog là gì? Cấu trúc dữ liệu xác suất để ước lượng unique HyperLogLog (HLL) là một cấu trúc dữ liệu xác suất được thiết kế để ước lượng số…

Xem thêm

Dependency Injection là gì? Nguyên tắc tiêm phụ thuộc trong lập trình

Dependency Injection (DI) là một nguyên tắc thiết kế phần mềm trong đó các đối tượng không tự tạo ra phụ thuộc của chúng, mà nhận phụ thuộc từ bên…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất