1 điểm bởi GN⁺ 2025-04-02 | Chưa có bình luận nào. | Chia sẻ qua WhatsApp
  • Graft là một transaction storage engine mã nguồn mở, nhằm kết hợp sự đơn giản của sao chép vật lý với hiệu quả của sao chép logic, thay vì gửi toàn bộ changelog cho mọi client
  • Graft xử lý Volume được tạo từ các Page kích thước cố định theo đơn vị Snapshot, và server không gửi dữ liệu thực mà trả về graft, một bitmap nén của các chỉ mục page đã thay đổi
  • Client xem graft để chỉ tải các page cần thiết, đồng thời có thể chọn prefetch dựa trên Leap, prefetch theo miền, hoặc tải trước toàn bộ phần thay đổi
  • Bằng cách tận dụng object storage và edge server, hệ thống hướng tới sao chép một phần ngay cả trong các môi trường bị hạn chế như trình duyệt, ứng dụng di động, hàm serverless và môi trường nhúng
  • Mô hình nhất quán là Serializable Snapshot Isolation; các commit dựa trên Snapshot cũ sẽ bị từ chối và client sẽ xử lý bằng một trong ba cách: reset/replay, merge hoặc Volume fork

Vấn đề sao chép mà Graft muốn giải quyết

  • Sao chép một phần nghe có vẻ dễ vì chỉ cần đồng bộ dữ liệu cần thiết, nhưng trong thiết kế thực tế mỗi cách sao chép đều có cái giá rõ ràng
    • Sao chép logic theo dõi rất chi tiết mọi thay đổi, nhưng khiến việc duy trì tính nhất quán mạnh trở nên phức tạp
    • Sao chép vật lý tránh được sự phức tạp đó, nhưng buộc phải đồng bộ cả những thay đổi rồi sau này sẽ bị loại bỏ
  • Graft là một transaction storage engine mã nguồn mở được tạo ra với mục tiêu đồng bộ trễ, sao chép một phần, tính nhất quán mạnh, khả năng mở rộng ngang và độ bền của object storage
  • Điểm xuất phát là kinh nghiệm từ SQLSync
    • SQLSync là một database stack tối ưu cho frontend được xây trên SQLite, dùng các ý tưởng từ Git và hệ thống phân tán cho engine đồng bộ
    • SQLSync sao chép toàn bộ changelog tới mọi client, nên phù hợp ở phía server nhưng không hợp với môi trường edge và trình duyệt
  • Mục tiêu của Graft là để client đồng bộ theo tốc độ mong muốn, chỉ lấy đúng phần cần thiết, và sao chép dữ liệu tùy ý với tính nhất quán mạnh ngay cả trên edge và thiết bị offline

Thiết kế nằm giữa sao chép toàn phần và diff nhận biết schema

  • Các lời giải hiện có chủ yếu chia thành hai hướng lớn
    • Sao chép toàn phần: đồng bộ toàn bộ dataset tới từng client nên không thực tế với các môi trường bị hạn chế như hàm serverless hay web app
    • Diff nhận biết schema: theo dõi thay đổi logic ở mức hàng hoặc trường như CDC hay CRDT, nhưng cần tích hợp sâu với ứng dụng và khó khái quát cho dữ liệu tùy ý
  • Graft không phụ thuộc schema giống như sao chép toàn phần
    • Nó không cần biết hay quan tâm dữ liệu được lưu là loại gì, mà sao chép các page chứa byte
  • Đồng thời, giống sao chép logic, nó cung cấp cho client một mô tả nén về những gì đã thay đổi kể từ lần đồng bộ cuối
  • Trừu tượng cốt lõi là Volume
    • Volume là một tập hợp thưa và có thứ tự của các Page kích thước cố định
    • Client đọc và ghi Volume tại một Snapshot cụ thể thông qua transaction API
    • Bên trong, Graft chỉ lưu trữ và sao chép phần cần thiết, đồng thời dùng object storage làm backend bền vững và có thể mở rộng

Đồng bộ trễ: client bắt kịp vào thời điểm mình muốn

  • Graft được thiết kế với giả định rằng client ở edge chỉ thỉnh thoảng thức dậy, mạng không ổn định và thời gian thực thi ngắn
  • Thay vì phụ thuộc vào sao chép liên tục, client tự chọn khi nào cần đồng bộ
  • Việc đồng bộ bắt đầu từ câu hỏi: “điều gì đã thay đổi kể từ Snapshot cuối cùng?”
  • Server không gửi dữ liệu thực, mà trả về graft, một bitmap nén của các chỉ mục page đã thay đổi
    • graft đóng vai trò như hướng dẫn để gắn các thay đổi mới vào Snapshot hiện có
    • Client biết page nào có thể tái sử dụng và page nào cần tải khi cần
  • graft là metadata thay đổi chứ không phải dữ liệu, quyền kiểm soát việc tải cái gì và lúc nào vẫn nằm ở client

Sao chép một phần và prefetch

  • Trong tab trình duyệt, ứng dụng di động hay hàm serverless, rất khó tải toàn bộ dataset chỉ để xử lý một vài truy vấn
  • Sau khi nhận graft, client xác định page nào vẫn còn hợp lệ và page nào phải tải
  • Chỉ các page cần thiết mới được tải chọn lọc, nên có thể sao chép đúng phần dữ liệu sẽ thực sự được dùng
  • Graft hỗ trợ nhiều cách prefetch để giảm độ trễ truy cập page
    • Prefetch mục đích chung: prefetcher tích hợp dựa trên thuật toán Leap nhận diện mẫu truy cập để dự đoán các lần truy cập page sắp tới
    • Prefetch theo miền: ứng dụng có thể tận dụng hiểu biết về dữ liệu thường được truy vấn, như hồ sơ người dùng, để tải trước các page liên quan
    • Tải trước chủ động: nếu cần có thể tải toàn bộ phần thay đổi để quay về trạng thái gần như sao chép toàn phần; đặc biệt hữu ích cho workload Graft phía server
  • Các page được host trực tiếp trên object storage, nên đóng vai trò nền tảng sao chép có độ bền và khả năng mở rộng cao

Triển khai edge và client nhúng

  • Sao chép edge của Graft không chỉ nhắm tới việc đồng bộ dữ liệu nào, mà còn đưa dữ liệu tới đúng nơi cần thiết
  • Các page được phân phối từ object storage thông qua một đội edge server toàn cầu
    • Các hot page được truy cập thường xuyên có thể được cache gần client
    • Mục tiêu là độ trễ thấp và phản hồi cao bất kể người dùng ở đâu trên thế giới
  • Graft client được thiết kế nhẹ và dễ nhúng
    • Ít phụ thuộc và runtime nhỏ
    • Có thể tích hợp vào trình duyệt, thiết bị, ứng dụng di động và hàm serverless
  • Vì edge caching tạo ra vấn đề về tính nhất quán và xử lý xung đột, Graft đi kèm một mô hình nhất quán mạnh

Mô hình nhất quán và xử lý xung đột

  • Graft dùng Serializable Snapshot Isolation làm mô hình nhất quán
  • Client nhận được một góc nhìn dữ liệu nhất quán và cô lập tại một Snapshot cụ thể; các thao tác đọc không cản trở nhau và có thể chạy đồng thời
  • Các thao tác ghi được tuần tự hóa nghiêm ngặt để tạo ra một thứ tự toàn cục nhất quán cho mọi transaction
  • Do đặc tính ưu tiên offline và sao chép trễ, client có thể cố commit dựa trên Snapshot cũ
    • Nếu luôn chấp nhận các commit như vậy thì strict serializability sẽ bị phá vỡ
    • Graft từ chối an toàn các commit đó và cho client tự chọn cách xử lý
  • Ba lựa chọn phổ biến phía client là
    • Reset and replay: lấy Snapshot mới nhất, áp dụng lại transaction cục bộ rồi thử lại
      • Dữ liệu toàn cục vẫn giữ trạng thái strict serializable
      • Ở cục bộ, client sẽ trải nghiệm Optimistic Snapshot Isolation; thao tác đọc vẫn thấy Snapshot nhất quán nội bộ nhưng Snapshot đó có thể bị loại bỏ nếu commit bị từ chối
    • Merge: hợp nhất trạng thái cục bộ với Snapshot mới nhất trên server
      • Khi đó mô hình nhất quán toàn cục có thể hạ xuống snapshot isolation
    • Volume fork: tách hẳn bằng cách tạo một Volume mới vĩnh viễn
      • Giữ được global serializability

Những ứng dụng có thể xây dựng

  • Ứng dụng ưu tiên offline: với các app như ghi chú, quản lý công việc hay CRUD hoạt động một phần ở chế độ offline, Graft có thể phụ trách đồng bộ
    • Khi kết hợp với conflict handler, còn có thể hỗ trợ tính năng nhiều người cùng thao tác trên dữ liệu tùy ý
  • Dữ liệu đa nền tảng: có thể chia sẻ dữ liệu giữa mobile, thiết bị và web, đồng thời giảm phụ thuộc vào nhà cung cấp
  • Read replica không trạng thái: có thể khởi chạy một bản sao cơ sở dữ liệu mà không cần trạng thái cục bộ, lấy metadata Snapshot mới nhất rồi truy vấn ngay
    • Không cần tải toàn bộ dữ liệu hay phát lại log
  • Sao chép dữ liệu tùy ý: Graft tập trung vào sao chép page nên không can thiệp vào định dạng dữ liệu bên trong page

Tiện ích mở rộng SQLite libgraft

  • Hiện nay, cách dễ nhất để dùng Graft là tiện ích mở rộng SQLite native libgraft
  • libgraft có thể dùng ở mọi nơi SQLite chạy được, và chỉ sao chép phần cơ sở dữ liệu mà client thực sự sử dụng
  • Nó triển khai SQLite VFS để chặn các thao tác đọc và ghi cơ sở dữ liệu
  • Nó cung cấp ngữ nghĩa transaction và đồng thời tương tự những gì SQLite cung cấp trong WAL mode
  • Các tính năng được cung cấp gồm
    • Sao chép bất đồng bộ với object storage
    • Sao chép một phần theo kiểu trễ tại edge và trên thiết bị
    • Serializable Snapshot Isolation
    • Khôi phục theo thời điểm
  • Tài liệu có tại tài liệu SQLite trên GitHub

Tham gia và kế hoạch dịch vụ quản lý

  • Graft được phát triển công khai trên GitHub
  • Dự án nhận issue, thảo luận và Pull Request, đồng thời cung cấp contribution guide
  • Có các kênh trao đổi qua Discord và email
  • Dự án cũng có kế hoạch ra mắt Graft Managed Service và cung cấp liên kết đăng ký danh sách chờ

Lộ trình

  • Graft đã trải qua 1 năm nghiên cứu, nhiều vòng lặp và một lần đổi hướng lớn, nhưng vẫn còn nhiều việc phải làm
  • Các hạng mục dự kiến gồm
    • Hỗ trợ WebAssembly: cho phép dùng Graft trong trình duyệt, với mục tiêu hỗ trợ bản build Wasm chính thức của SQLite, wa-sqlite, và sql.js
    • Tích hợp Graft với SQLSync: sau khi có hỗ trợ Wasm, dự án dự định tách lớp mutation, rebase và query subscription của SQLSync để đặt lên trên cơ sở dữ liệu sao chép bằng Graft
    • Mở rộng thư viện client: muốn có wrapper native cho Python, JavaScript, Go và Java
    • Ghi độ trễ thấp: hiện tại thao tác push bị chặn cho tới khi commit hoàn toàn vào object storage
      • Thử nghiệm S3 express zone
      • Cách đặt một nhóm đồng thuận bền vững độ trễ thấp phía trước object storage
    • Garbage collection, checkpointing, compaction: cần thiết để tối đa hiệu năng truy vấn, giảm tối thiểu không gian lãng phí và hỗ trợ xóa vĩnh viễn
    • Xác thực và phân quyền: là một phạm vi công việc rộng, từ tài khoản cho dịch vụ quản lý đến quyền đọc/ghi chi tiết theo Volume
    • Volume forking: dịch vụ có thể thực hiện zero-copy fork bằng cách sao chép tham chiếu Segment sang Volume mới, nhưng fork cục bộ hiện vẫn phải sao chép mọi page
    • Xử lý xung đột: dự án có kế hoạch cung cấp chiến lược giải quyết xung đột tích hợp và các điểm mở rộng; chiến lược đầu tiên là tự động merge các transaction không chồng lấp

So sánh với các giải pháp sao chép SQLite

  • Thông tin so sánh được tổng hợp từ tài liệu và bài blog, kèm lưu ý rằng có thể chưa hoàn toàn chính xác
  • mvSQLite

    • mvSQLite triển khai một lớp VFS tùy biến lưu trực tiếp các page SQLite vào FoundationDB
    • Graft và mvSQLite giống nhau ở chỗ quản lý phiên bản ở mức page, cho phép fetch trễ và góc nhìn cơ sở dữ liệu một phần
    • Khác biệt nằm ở nơi lưu trữ và cách theo dõi thay đổi page
      • mvSQLite phụ thuộc vào FoundationDB và mọi node phải truy cập trực tiếp vào cụm
      • changeset dựa trên Splinter của Graft là tự chứa nên dễ triển khai hơn, và không cần truy vấn trực tiếp FoundationDB để biết phiên bản page đã thay đổi
  • Litestream

    • Litestream là giải pháp backup dạng streaming, liên tục sao chép các WAL frame của SQLite vào object storage
    • Graft tích hợp trực tiếp vào quá trình commit của SQLite thông qua VFS tùy biến, cho phép sao chép một phần theo kiểu trễ và ghi phân tán
    • Cả hai đều sao chép page lên object storage và hỗ trợ khôi phục theo thời điểm
  • cr-sqlite

    • cr-sqlite là tiện ích mở rộng SQLite biến bảng thành CRDT để cho phép sao chép logic ở mức hàng
    • Nó cung cấp giải quyết xung đột tự động nhưng đòi hỏi nhận biết schema và tích hợp ở cấp ứng dụng
    • Graft không phụ thuộc schema và tương thích với tiện ích mở rộng SQLite tùy ý cùng các cấu trúc dữ liệu tùy biến, nhưng để giữ global serializability thì ứng dụng phải xử lý giải quyết xung đột một cách tường minh
  • Cloudflare Durable Objects with SQLite Storage

    • Kết hợp Durable Objects với SQLite cho phép đặt cơ sở dữ liệu có tính nhất quán mạnh và độ bền cao, được bao bởi business logic, trên mạng edge của Cloudflare
    • Về mặt nội bộ, cách này giống Litestream ở chỗ sao chép SQLite WAL lên object storage và checkpoint định kỳ
    • Graft phơi bày replication như một tính năng hạng nhất và hướng đến sao chép hiệu quả với edge
  • Cloudflare D1

    • Cloudflare D1 là cơ sở dữ liệu SQLite được quản lý, truy cập qua HTTP API
    • Graft là mô hình phân tán, nhúng dữ liệu vào ứng dụng client và sao chép trực tiếp ra edge
  • Turso & libSQL

    • Turso cung cấp cơ sở dữ liệu SQLite được quản lý và bản sao nhúng thông qua libSQL
    • Graft khác biệt nhờ hỗ trợ sao chép một phần và các cấu trúc dữ liệu tùy ý không phụ thuộc schema
    • Dịch vụ backend của Graft hoạt động ở mức page và giao toàn bộ vòng đời transaction cho client
  • rqlite & dqlite

    • rqlitedqlite phân tán SQLite qua đồng thuận dựa trên Raft và giao thức mạng
    • Chúng tập trung vào việc đồng bộ một tập node có trạng thái và duy trì kết nối với nhau
    • Graft là hệ thống không trạng thái được xây trên object storage và được thiết kế để trao đổi dữ liệu với edge
  • Verneuil

    • Verneuil sao chép bất đồng bộ SQLite Snapshot tới các read replica thông qua object storage, ưu tiên độ tin cậy
    • Nó chủ ý tránh các cơ chế nhằm giảm tối đa độ trễ sao chép hoặc tăng độ tươi dữ liệu
    • Graft vận hành gần với một cơ sở dữ liệu phân tán nhiều writer hơn và nhấn mạnh vào sao chép một phần chọn lọc theo thời gian thực

Chưa có bình luận nào.

Chưa có bình luận nào.