Bạn từng để ý một tin đồn lan trong nhóm bạn chưa? Người đầu tiên biết tin ngay lập tức, người thứ hai nghe lại sau vài phút, còn người cuối cùng trong nhóm chat có khi mai mới biết. Trong khoảng thời gian đó, mỗi người "tin" một phiên bản khác nhau của sự thật, nhưng cuối cùng cả nhóm đều hội tụ về cùng một câu chuyện. Đó chính xác là cách eventual consistency (nhất quán cuối cùng) hoạt động trong các hệ thống phân tán như DynamoDB hay Cassandra.

Khi một giá trị được ghi vào hệ thống chạy trên nhiều node ở nhiều khu vực địa lý, dữ liệu không thể được đồng bộ tức thời tới mọi bản sao cùng lúc vì độ trễ mạng vật lý. Bắt mọi yêu cầu phải chờ tất cả bản sao xác nhận sẽ khiến hệ thống chậm đi và dễ trục trặc khi một node gặp lỗi. Vì vậy, các hệ thống này chấp nhận trả về dữ liệu tạm thời chưa cập nhật, thay vì bắt người dùng chờ đợi. Tức là một lần đọc có thể chưa thấy bản ghi mới nhất, đổi lại hệ thống nhanh hơn và chịu lỗi tốt hơn. Đây là đánh đổi quen thuộc trong định lý CAP: giữa nhất quán tuyệt đối và khả năng phục vụ liên tục, DynamoDB và Cassandra ưu tiên tính sẵn sàng.

Nhưng "eventual" không có nghĩa là tùy tiện. Hệ thống cam kết convergence, tức nếu không có thao tác ghi mới nào xảy ra, tất cả các bản sao rồi sẽ hội tụ về cùng một giá trị. Cassandra đạt được điều này qua anti-entropy repair: các node định kỳ so sánh dữ liệu bằng cấu trúc Merkle tree, phát hiện phần nào lệch nhau rồi chỉ đồng bộ đúng phần đó thay vì truyền lại toàn bộ dữ liệu. Ngoài ra còn có read repair, sửa lỗi ngay khi phát hiện trong lúc đọc, và hinted handoff, node tạm giữ hộ dữ liệu ghi cho node đang offline rồi chuyển lại khi nó hồi phục.

Quan trọng hơn, các hệ thống này không chỉ hứa dữ liệu sẽ đúng ở một thời điểm nào đó. Chúng còn đưa ra những cam kết cụ thể hơn để lập trình viên xây dựng ứng dụng thực tế. Read-your-writes đảm bảo chính bạn, sau khi ghi một giá trị, sẽ luôn đọc lại được đúng giá trị đó, dù người dùng khác có thể vẫn thấy dữ liệu cũ trong lúc đó. Monotonic reads đảm bảo một khi bạn đã đọc được phiên bản mới của dữ liệu, các lần đọc sau sẽ không bao giờ thụt lùi về phiên bản cũ hơn, dù bạn kết nối tới bản sao nào. Gộp hai cam kết này trong phạm vi một phiên làm việc của người dùng, ta có session consistency, kiểu đảm bảo phổ biến nhất trong thực tế vì đủ mạnh để người dùng cảm thấy trải nghiệm nhất quán, mà vẫn giữ được tốc độ của kiến trúc phân tán.

DynamoDB hiện thực hóa điều này bằng hai lựa chọn: eventually consistent read, nhanh và rẻ nhưng có thể trả về dữ liệu cũ trong vài trăm mili giây; và strongly consistent read, chậm hơn, tốn kém hơn nhưng luôn trả về bản mới nhất. Cassandra thì linh hoạt hơn qua tham số consistency level: ghi ở QUORUM và đọc ở QUORUM sẽ đảm bảo giao nhau giữa tập ghi và tập đọc, từ đó ép buộc mọi lần đọc đều thấy giá trị mới nhất, gần với nhất quán mạnh dù bản chất hệ thống vẫn là phân tán. Hiểu rõ những cấp độ hệ thống phân tán này giúp bạn chọn đúng cấu hình cho từng bài toán: giỏ hàng thương mại điện tử cần read-your-writes, nhưng bộ đếm lượt xem video thì eventual consistency thuần túy là quá đủ.

Bài học cốt lõi: nhất quán cuối cùng không phải một khiếm khuyết cần chịu đựng, mà là một công cụ thiết kế có chủ đích. Khi làm việc với các cơ sở dữ liệu NoSQL phân tán quy mô lớn, câu hỏi không phải làm sao để luôn nhất quán tuyệt đối, mà là hệ thống của bạn thực sự cần mức cam kết nào, và bạn sẵn sàng đánh đổi bao nhiêu tốc độ để lấy nó.