CRDT là gì: Cấu trúc dữ liệu cho cộng tác offline và đồng thời thực

CRDT (Conflict-free Replicated Data Type) là một kiểu cấu trúc dữ liệu được nhân bản trên nhiều máy trong cùng một mạng, cho phép mỗi bản sao cập nhật độc lập và tự động hòa giải mọi xung đột để cuối cùng hội tụ về cùng một trạng thái. Khái niệm này được hình thức hóa vào năm 2011 bởi nhóm nghiên cứu gồm Marc Shapiro, Nuno Preguiça, Carlos Baquero và Marek Zawirski.

Vấn đề mà CRDT giải quyết rất rõ ràng. Khi hai người dùng cùng soạn thảo một tài liệu trong khi một người đang ngoại tuyến, hai bản sao sẽ tạo ra các thay đổi xung đột. Cách truyền thống là khóa (lock) hoặc hợp nhất thủ công, và cả hai đều dẫn tới trải nghiệm tệ: người dùng phải chờ, hoặc phải tự quyết định giữ phiên bản nào. CRDT đảo ngược bài toán: cho phép mọi cập nhật đi qua và tự động hợp nhất chúng về sau.

Sơ đồ CRDT dựa trên hoạt động minh họa cách các thao tác được truyền và áp dụng

Ba tính chất bắt buộc

Theo định nghĩa chính thống, một CRDT phải thỏa mãn ba yêu cầu: ứng dụng có thể cập nhật bất kỳ bản sao nào một cách độc lập và đồng thời, không cần bất kỳ cơ chế phối hợp nào giữa các bản sao; thuật toán bên trong kiểu dữ liệu tự động giải quyết mọi bất nhất có thể phát sinh; và dù các bản sao có trạng thái khác nhau tại một thời điểm bất kỳ, chúng được bảo đảm sẽ hội tụ về cùng một trạng thái.

Điểm mấu chốt nằm ở chữ “tất định”. Một hệ thống chỉ hội tụ được nếu kết quả hợp nhất không phụ thuộc vào thứ tự đến của các thông điệp và không phụ thuộc vào việc thông điệp có bị lặp lại hay không. Đây chính là lý do các giao thức mạng thực tế vốn không bảo đảm thứ tự vẫn có thể chạy CRDT mà không cần thay đổi hạ tầng.

CRDT dựa trên trạng thái giải thích quy trình hợp nhất trạng thái giữa các bản sao

Hai họ kiểu dữ liệu

CRDT theo trạng thái

CRDT theo trạng thái, còn gọi là convergent replicated data type, được định nghĩa bởi một hàm tạo trạng thái ban đầu, một hàm merge nhận hai trạng thái và trả về trạng thái hợp nhất, cùng một hàm update áp dụng hành động của người dùng lên trạng thái cục bộ. Mỗi lần có thay đổi, bản sao gửi toàn bộ trạng thái của nó đi, và các bản sao nhận được trạng thái mới thì hợp nhất vào trạng thái cục bộ.

Hàm merge bắt buộc phải thỏa mãn ba tính chất toán học: giao hoán, kết hợp và lũy thừa. Ba tính chất này một lần nữa quy về cùng một ý tưởng: kết quả hợp nhất phải bất biến trước việc sắp xếp lại và lặp lại thông điệp. Nhánh delta CRDT là biến thể tối ưu, chỉ truyền đi phần thay đổi gần đây thay vì toàn bộ trạng thái, giúp giảm băng thông đáng kể khi trạng thái lớn.

CRDT theo thao tác

CRDT theo thao tác không định nghĩa hàm merge mà thay vào đó truyền chính các thao tác cập nhật tới các bản sao khác để áp dụng. Một bộ đếm theo thao tác đơn giản có thể chỉ cần phát tán các lệnh tăng hoặc giảm một giá trị cụ thể. Các thao tác phải giao hoán và kết hợp, và hệ thống bắt buộc phải bảo đảm không thao tác nào bị thất lạc hoặc lặp lại khi truyền.

Trên lý thuyết hai cách tiếp cận này tương đương nhau, mỗi cách có thể mô phỏng cách còn lại. Về thực tế, CRDT theo trạng thái dễ thiết kế và dễ triển khai hơn, chỉ cần một cơ chế phát tán kiểu gossip là đủ. Đổi lại, nó phải truyền cả trạng thái, tốn băng thông khi dữ liệu lớn. CRDT theo thao tác nhẹ hơn nhiều về mặt dữ liệu gửi đi nhưng đòi hỏi tầng truyền thông phải bảo đảm tính toàn vẹn, nếu không sẽ dễ dẫn tới sai lệch dữ liệu.

Ví dụ kinh điển: cờ sự kiện một chiều

Ví dụ đơn giản nhất về CRDT là một cờ boolean một chiều chỉ có một bit. Giá trị true nghĩa là sự kiện đã xảy ra ít nhất một lần, false nghĩa là sự kiện chưa xảy ra. Nguyên tắc bất biến: một khi cờ được đặt thành true thì không thể quay lại false, vì sự kiện đã xảy ra thì không thể chưa xảy ra.

Khi hợp nhất hai bản sao, nếu một bản sao có cờ true và bản sao kia có cờ false, kết quả là true. Quy tắc này gọi là “true thắng”. Nhờ tính chất lũy thừa, việc hợp nhất cờ true một trăm lần vẫn cho kết quả true, nên thông điệp lặp lại không gây hại.

Những ứng dụng thực tế

  • Soạn thảo văn bản cộng tác: nền tảng cộng tác trực tuyến dùng CRDT để nhiều người cùng gõ một tài liệu mà không mất dữ liệu ai, kể cả khi có người đang offline.
  • Cơ sở dữ liệu NoSQL phân tán: các sản phẩm như Riak và Azure Cosmos DB cung cấp sẵn các kiểu dữ liệu theo mô hình CRDT để ứng dụng không phải tự viết lại thuật toán hợp nhất.
  • Ứng dụng nhắn tin và cấu hình cục bộ: danh sách tin nhắn, danh sách thiết bị và cài đặt ứng dụng được hợp nhất không cần can thiệp của máy chủ trung tâm.
  • Ứng dụng di động và thời gian thực: các ứng dụng có nhiều thiết bị cùng chỉnh sửa một tài liệu, ví dụ ghi chú trên iPad và iPhone, là miền ứng dụng rất hợp lý của CRDT.

Điểm cộng tác của nhiều thư viện mã nguồn mở như Automerge và Yjs là chúng cung cấp sẵn thuật toán CRDT đã được kiểm chứng, giúp đội phát triển tập trung vào giao diện thay vì phải tự giải quyết bài toán hợp nhất xung đột.

Đánh đổi và giới hạn

CRDT không phải lúc nào cũng là lựa chọn đúng. Với CRDT theo trạng thái, kích thước trạng thái có thể tăng theo thời gian vì dữ liệu đã xóa vẫn phải được giữ lại để bảo đảm khả năng hợp nhất với các bản sao đã không đồng bộ. Với CRDT theo thao tác, tầng truyền thông phải bảo đảm không lặp thao tác, điều mà nhiều hệ thống phân tán hiện tại không cung cấp sẵn.

Ngoài ra, CRDT chỉ giải quyết xung đột ở cấp dữ liệu, không tự quyết định xem thay đổi nào là ý định thật sự của người dùng. Với những trường hợp cần “ý nghĩa” chứ không chỉ cần hợp nhất, như chỉnh sửa đồng thời cùng một câu văn, các ứng dụng vẫn phải bổ sung thêm lớp xử lý xung đột ở tầng ứng dụng.

Kết luận

CRDT đổi cách chúng ta nghĩ về tính nhất quán trong hệ thống phân tán: thay vì ngăn chặn xung đột, nó thiết kế để mọi xung đột đều có thể được hợp nhất một cách tự động và xác định. Với sự bùng nổ của ứng dụng cộng tác trên di động và edge computing, CRDT ngày càng trở thành một kỹ năng bắt buộc của lập trình viên backend.

Bạn có thể đọc thêm chi tiết về mô hình này trong bài viết tiếng Anh trên Wikipedia về Conflict-free replicated data type, hoặc tham khảo thư viện triển khai thực tế tại trang chủ Automerge.

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

SQLite là gì: Cơ sở dữ liệu nhúng và chế độ WAL hiệu quả

SQLite là một hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) nhẹ, không cần máy chủ riêng biệt, được nhúng trực tiếp vào ứng dụng. Khác với MySQL…

Xem thêm

Cây AVL là gì: Cấu trúc dữ liệu tự cân bằng cho lập trình viên

Cây AVL là một dạng cây tìm kiếm nhị phân tự cân bằng, được phát minh bởi Georgy Adelson-Velsky và Evgenii Landis vào năm 1962. Cây AVL đảm bảo độ…

Xem thêm

htmx là gì: Xây web tương tác chỉ bằng HTML, không cần framework

htmx là gì? htmx là gì là câu hỏi nhiều lập trình viên gặp khi nghe tới cách xây giao diện web hiện đại mà không cần framework JavaScript phức…

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