2 điểm bởi GN⁺ 2024-06-27 | 1 bình luận | Chia sẻ qua WhatsApp
  • Triplit là một cơ sở dữ liệu mã nguồn mở đồng bộ dữ liệu theo thời gian thực giữa máy chủ và trình duyệt, tự định vị là cơ sở dữ liệu full-stack có thể được tích hợp vào ứng dụng dưới dạng gói Typescript
  • Xử lý đồng thời việc lưu trữ phía máy chủ và đồng bộ truy vấn phía máy khách; hỗ trợ cập nhật gia tăng, giải quyết xung đột ở cấp thuộc tính, bộ nhớ đệm cục bộ, chế độ ngoại tuyến và tự động kết nối lại
  • Hỗ trợ lưu trữ dạng plug-in như SQLite, IndexedDB, LevelDB, Memory, đồng thời cung cấp lưu trữ bền vững phía máy chủ và bảng điều khiển quản trị
  • Có thể dùng API truy vấn và thay đổi trong React và vanilla Javascript; được cung cấp dưới dạng monorepo gồm React/Svelte bindings, CLI, Console, Server, v.v.
  • Cung cấp đồng thời cập nhật lạc quan để tương tác nhanh, rollback/thử lại các cập nhật thất bại, quyền đọc/ghi được cưỡng chế ở máy chủ và tính năng cộng tác dựa trên CRDT

Triplit cung cấp gì

  • Triplit là một cơ sở dữ liệu mã nguồn mở đồng bộ theo thời gian thực dữ liệu giữa máy chủ và trình duyệt
  • Cung cấp kho dữ liệu đồng bộ có thể thêm vào ứng dụng dưới dạng gói Typescript
  • Lưu dữ liệu trên máy chủ và đồng bộ thông minh các truy vấn của máy khách
  • Triplit gọi hình thức này là cơ sở dữ liệu full-stack
    • Cũng có video thuyết trình từ cộng đồng Local First: presentation

Tính năng chính

  • Đồng bộ theo thời gian thực

    • Hỗ trợ cập nhật gia tăng
    • Cung cấp giải quyết xung đột ở cấp thuộc tính
  • Trải nghiệm local-first

    • Cung cấp bộ nhớ đệm cục bộ dựa trên cơ sở dữ liệu hoàn chỉnh phía máy khách
    • Dùng cập nhật lạc quan để mọi tương tác có cảm giác nhanh
    • Hỗ trợ chế độ ngoại tuyến, tự động kết nối lại và đảm bảo tính nhất quán
  • Lưu trữ và vận hành phía máy chủ

    • Cung cấp lưu trữ bền vững phía máy chủ
    • Bao gồm bảng điều khiển quản trị
    • Hỗ trợ nhà cung cấp lưu trữ dạng plug-in như SQLite, IndexedDB, LevelDB, Memory
  • Mô hình dữ liệu và API

    • Hỗ trợ truy vấn quan hệ cho các mô hình dữ liệu phức tạp
    • Cung cấp an toàn dữ liệu và tự động hoàn thành Typescript thông qua schema
    • Cung cấp API đơn giản cho truy vấn và thay đổi trong vanilla Javascript và React
  • Cộng tác và bảo mật

    • Cưỡng chế quyền cho cả đọc và ghi trên máy chủ
    • Cung cấp tính năng cộng tác/multiplayer dựa trên CRDTs
    • Dùng delta patch để giảm lưu lượng mạng và hướng tới độ trễ thấp
    • Quản lý rollback và thử lại đối với các cập nhật thất bại

Cấu trúc monorepo

  • TriplitDB: DB được thiết kế để chạy trong các môi trường JS như trình duyệt, Node, Deno, React Native; cung cấp các truy vấn nhanh, cập nhật trực tiếp, đồng thời duy trì tính nhất quán với nhiều bên ghi trên mạng
  • Client: thư viện trình duyệt để tương tác với TriplitDB cục bộ/từ xa
  • CLI: công cụ dòng lệnh để scaffold dự án, chạy môi trường phát triển full-stack, migration máy chủ, v.v.
  • React: React binding cho @triplit/client
  • Svelte: Svelte binding cho @triplit/client
  • Console: ứng dụng để xem và thay đổi dữ liệu dự án Triplit cũng như quản lý schema
  • Server: máy chủ Node đồng bộ dữ liệu giữa các Triplit client
  • Server-core: thư viện không phụ thuộc giao thức để xây dựng máy chủ Triplit
  • Docs: tài liệu Triplit được xây dựng bằng Nextra
  • Types: các type dùng chung giữa các dự án Triplit
  • UI: thành phần UI dùng chung dựa trên shadcn

Luồng bắt đầu nhanh

  • Dự án mới bắt đầu bằng npm create triplit-app@latest my-app
  • Với dự án hiện có, cài @triplit/cli làm dependency phát triển rồi chạy npm run triplit init
  • Định nghĩa schema trong my-app/triplit/schema.ts
    • Ví dụ định nghĩa các trường id, text, completed trong collection todos
    • completed được thiết lập là trường Boolean có giá trị mặc định là false
  • Khởi động máy chủ đồng bộ cho phát triển bằng npm run triplit dev
  • Máy chủ phát triển xuất ra các biến môi trường cần thiết để ứng dụng đồng bộ với máy chủ
    • Trong ví dụ Vite: VITE_TRIPLIT_SERVER_URL=http://localhost:6543
    • VITE_TRIPLIT_TOKEN=copied-in-from-triplit-dev

Ví dụ dùng React và kiểm tra đồng bộ

  • Ví dụ React dùng TriplitClientuseQuery
  • Client được tạo với schema, URL máy chủ và token
  • Đăng ký nhận kết quả truy vấn todos bằng useQuery(client.query('todos'))
  • Khi checkbox thay đổi, dùng client.update để đảo giá trị completed
  • Sau khi khởi động ứng dụng, mở một tab trình duyệt khác để xác nhận dữ liệu được đồng bộ theo thời gian thực

Tài liệu và kênh liên hệ

1 bình luận

 
GN⁺ 2024-06-27
Ý kiến trên Hacker News
  • Tôi đã dùng Triplit trong dự án https://github.com/thanhnguyen2187/cryptaa và nó hoạt động như kỳ vọng
    Mô hình dữ liệu khá phù hợp với ý tưởng thiên về phân tán/P2P hơn là đặt một DB trung tâm duy nhất làm nguồn chân lý, nhưng self-hostingngôn ngữ truy vấn thì còn đáng tiếc
    Tài liệu không nói rõ cách tạo token xác thực cho server nên tôi đã tạo token bằng lệnh dev của CLI; việc token bị ghi log dạng văn bản thuần trong system service là không tốt về bảo mật, nhưng tôi cho rằng nó giả định đã có vấn đề quyền truy cập lớn hơn
    DSL truy vấn tùy chỉnh thiếu tính biểu đạt như UNIQUE, COUNT trong SQL, nên một số phần tổng hợp phải tự làm
    Gần đây tôi có xem Evolu https://www.evolu.dev/docs, phạm vi và tính năng trông khá giống; Triplit có .subscribe() còn Evolu thì không, Evolu là SQL có kiểu dựa trên Kysely nên truy vấn quen thuộc và nâng cao hơn, và trên trình duyệt Evolu dùng SQLite trên OPFS trong khi Triplit dường như dùng IndexedDB
    Bài tôi đăng trên Reddit: https://www.reddit.com/r/sveltejs/comments/1dndpj8/cryptaa_a...

    • Tài liệu self-hosting đang được chỉnh lý để phần cấu hình rõ ràng hơn, và những điểm bạn nêu rất hữu ích
      Về truy vấn, hiện vẫn chưa có aggregate nhưng đã nằm trong roadmap; tôi nghĩ tận dụng incremental query engine có thể mở ra một hướng rất hay
      Ví dụ, với dashboard dữ liệu được cập nhật mỗi giờ, trong các hệ thống hiện có (Postgres, MongoDB, v.v.) mỗi lần đều phải chạy lại truy vấn từ đầu, nhưng nếu xử lý theo cách gần với Materialize, chỉ xử lý dữ liệu mới, thì có thể tiếp tục cập nhật hiệu quả hơn nhiều
      Tôi vẫn chưa trực tiếp dùng Evolu, nhưng có thể có người trên Discord đã so sánh: https://triplit.dev/discord
    • Cảm ơn đã cho biết về Evolu; cả Triplit và Evolu đều trông thú vị nên tôi muốn xem một bài so sánh giữa hai bên
    • Evolu cũng hỗ trợ subscribe qua useQuery hoặc theo một cách tách rời
  • Khi dùng một DB có giao thức đồng bộ offline tuyệt vời như vậy, tôi tò mò việc tiến hóa schema được xử lý ra sao trong tình huống không thể nâng cấp đồng thời các phiên bản client khác nhau
    Trước đây tôi từng khổ sở vì vấn đề này trong bối cảnh một ứng dụng sức khỏe trên di động

    • Tốt nhất là chỉ tạo bảng mới và không thực hiện thay đổi phá vỡ tương thích trên các bảng hiện có
      Nếu cần thì sẽ phải dual-write vào cả hai phiên bản
      Nó giống việc live migration không downtime cho các thay đổi phá vỡ tương thích trong SQL DB, nhưng thời điểm chuyển đổi phụ thuộc vào khách hàng nên phải duy trì logic đó lâu hơn
      Một bảng điều phối phiên bản mới nhất cũng rất quan trọng; nếu có thay đổi phá vỡ tương thích thì các client tụt hậu cần yêu cầu người dùng nâng cấp
      Cũng có thể quyết định cần duy trì dual read/write trong bao lâu dựa trên phiên bản tối thiểu được hỗ trợ trên toàn bộ client
    • Nói ngắn gọn, cách dễ nhất để đảm bảo tương thích là duy trì tương thích ngược cho schema
      Triplit sẽ hiển thị cảnh báo nếu bạn tạo thay đổi không tương thích ngược; có thể xem trong tài liệu: https://www.triplit.dev/docs/schemas/updating#pushing-the-sc...
      Tuy nhiên theo thời gian, một định nghĩa schema lộn xộn với nhiều tên dễ gây nhầm lẫn có thể tự nhiên xuất hiện
      Chúng tôi vẫn chưa phát hành giải pháp để sửa chuyện này, nhưng đang làm một số thứ để khiến nó bớt đau hơn; để có bối cảnh về nhiều cách tiếp cận, tài liệu Cambria rất hay: https://www.inkandswitch.com/cambria/
    • Tôi nghĩ một số client, chẳng hạn server, cần có khả năng đồng bộ ngay cả với schema rất cũ
      Người dùng có thể đã để điện thoại trong ngăn kéo suốt 2 năm, nên mỗi client chỉ cần tự migration cho mình càng sớm càng tốt
    • Nếu có một cơ chế tích hợp sẵn để định nghĩa và hỗ trợ các migration trong quá khứ thì có lẽ sẽ là tính năng sát thủ
      Mọi người sẽ không cần tự phát minh lại cách quản lý migration của riêng mình
  • Tôi chưa hiểu rõ việc client có thể ghi trực tiếp vào DB thì phù hợp với loại ứng dụng nào, và làm sao có thể trụ được không có logic backend
    Tôi cũng có cùng thắc mắc với Supabase và Firestore, nên có vẻ tôi đang bỏ sót điều gì đó

    • Phần lớn những thứ được xây dựng trong thế giới thực hầu như không có business logic, gần như chỉ là CRUD
      Trong môi trường doanh nghiệp thì tất nhiên ngược lại, và tôi thấy bực khi các cuộc thảo luận bỏ qua điều này
      Đặc biệt khi thấy trên tech Twitter có người bênh vực một stack hay cách làm nào đó, quá rõ là họ chỉ từng làm CRUD chứ chưa từng xây dựng business system, nên họ thường không hiểu vì sao các developer nhiều kinh nghiệm không đồng ý
    • Tôi từng xây dựng ứng dụng cộng tác bằng Firebase; nếu hạn chế mạnh những gì mỗi người có thể làm với comment hay card của chính họ và chỉ cấp quyền cho một số thao tác cụ thể, thì nó hoạt động tạm ổn
      Tôi không nghĩ nó hợp với những thứ có nhiều logic backend
    • Cả hai đều có kiểm soát truy cập được backend cưỡng chế, nên không phải là hoàn toàn không có logic backend
      Trong Supabase, ví dụ, có một tính năng gọi là row-level security
      Client có thể gửi request tới Supabase, nhưng Supabase sẽ chạy thêm truy vấn ở backend để xác định request đến có được phép hay không
      Ví dụ đơn giản, có thể chỉ cho phép đọc, ghi và cập nhật một hàng khi giá trị cột UserID bằng với người dùng đã xác thực đang gửi request
  • Đã lưu cấu hình người dùng vào Triplit, và các cấu hình này cần được quản trị viên quản lý
    Người dùng cần cảm thấy như ứng dụng luôn chạy cục bộ, chất lượng Internet cũng thường không tốt, nhưng họ dùng qua nhiều thiết bị và quản trị viên cần xem, quản lý cấu hình của người dùng khác nên cần đồng bộ hóa
    Nhìn chung Triplit có trải nghiệm dành cho lập trình viên frontend lẫn hỗ trợ đều rất tuyệt; khi tìm thấy issue hay yêu cầu tính năng, đội ngũ xử lý rất nhanh
    Khi có câu trả lời cho triển khai tính sẵn sàng cao, dự định sẽ chuyển cả dữ liệu quan trọng hơn sang thay cho Postgres

  • Tò mò vì sao lại chọn giấy phép AGPL

    • Muốn dùng giấy phép AGPL để giúp Triplit dễ tự host, đồng thời bảo đảm những người sửa đổi sẽ đóng góp lại các thay đổi đó cho cộng đồng
    • Nếu do DB đang dùng mà sản phẩm cũng phải làm theo AGPL thì muốn tránh
  • Có vẻ đã xem bài trình bày trên YouTube https://www.youtube.com/playlist?list=PLTbD2QA-VMnXFsLbuPGz1... trong server Discord Local First https://localfirstweb.dev/, nên thấy trên Show HN thì rất vui
    Vì không dùng TypeScript nên có thể không phải đối tượng chính, và khác với web, chủ yếu dùng local-first cho ứng dụng di động có kết nối không ổn định, với Flutter và backend Rust
    Các giải pháp local-first khác như ElectricSQL và PowerSync đồng bộ trực tiếp DB phía client và server, nên độc lập hơn với client/server
    Các giải pháp dựa trên CRDT cũng có thể dùng ở client và server qua FFI; ví dụ automerge viết bằng Rust nên phía Flutter có thể dùng FFI qua flutter_rust_bridge, trên web dùng WASM, và ở backend dùng Rust
    Triplit có vẻ là kiểu đồng bộ client-server cổ điển hơn, lấy server làm nguồn sự thật, thay vì giải quyết không xung đột giữa các client khác nhau
    Tò mò vì sao lại chọn giải pháp ở cấp ngôn ngữ thay vì cách tiếp cận tầng DB độc lập hơn với client và server; có vẻ việc hỗ trợ các ngôn ngữ và framework ngoài nền JS trong tương lai sẽ khó
    Ngoài ra có vẻ muốn cạnh tranh với Supabase, nhưng Supabase cũng đang thử nghiệm đồng bộ cấp DB của Postgres và CRDT https://news.ycombinator.com/item?id=33931971, nên có thể sẽ bắt kịp

    • Đã suy nghĩ rất nhiều về hỗ trợ Flutter và các native khác, đặc biệt Flutter thường xuyên được nhắc đến
      Tuy nhiên khi bắt đầu, quyết định tập trung vào TypeScript thuần; thị trường đủ lớn, tin vào tương lai của PWA, và cho rằng phải tập trung vào đó mới tạo được trải nghiệm tốt nhất
      Có lẽ một ngày nào đó sẽ làm thứ gì đó độc lập nền tảng hơn, nhưng thời điểm thì chưa chắc
      Các đội ElectricSQL và Supabase đều xuất sắc, thấu đáo và có vẻ sẽ tiếp tục phát triển trong lĩnh vực SQL; đây là khác biệt căn bản nhất trong cách tiếp cận
      Triplit cho rằng có thể mang lại trải nghiệm tốt nhất cho lập trình viên bằng cách tránh SQL, và có đủ không gian để hai triết lý cùng tồn tại
  • Nếu là LWW thì tò mò liệu lượng thông tin ở client có tăng tuyến tính theo số phép toán không
    Tức là người dùng càng sửa DB nhiều thì nhật ký thao tác có cứ tiếp tục phình to không, hay có checkpoint; và về mặt dung lượng thì mở rộng thế nào khi người dùng thực hiện hàng triệu thao tác mỗi ngày

    • Triplit lưu lịch sử sửa đổi của một thuộc tính cụ thể, nhưng nhờ chỉ mục giá trị mới nhất nên truy vấn vẫn nhanh
      Tuy nhiên bản thân LWW register không yêu cầu lưu lịch sử; đó chỉ là cách triển khai hiện tại nhằm giúp cả các client đã offline lâu cũng đồng bộ hiệu quả
      Chưa thể nói là đã hoàn toàn đạt tới mức một triệu thao tác mỗi ngày, nhưng có lợi thế là server có thẩm quyền
      Trong tương lai, server Triplit có thể theo dõi timestamp đồng bộ cuối cùng của từng client và cắt tỉa lịch sử dần dần, tương tự cách Postgres VACUUM các tuple đã chết
  • Sẽ rất tốt nếu có binding Rust để dùng trong Tauri
    Kết hợp đà tăng trưởng của Tauri, hỗ trợ thiết bị di động sắp ra mắt, và độ phổ biến gần đây của SQLite, nó có thể lấp khoảng trống cho ứng dụng offline-first và trở thành lựa chọn mặc định của nhiều đội phát triển

    • Đang muốn thêm binding Rust cho ElectricSQL, một giải pháp đồng bộ tương tự
      ElectricSQL hoạt động ở tầng DB nên độc lập ngôn ngữ, và đang dùng Rust ở server nên binding Rust có thể hoạt động ở cả client lẫn server
      Nếu muốn cùng phát triển thì cho biết nhé
    • Tauri có vẻ dùng web renderer native phải không
      Nếu vậy thì Triplit có lẽ sẽ hoạt động ngay
  • Đã dùng Triplit trong một ứng dụng React Native một thời gian và nó hoạt động rất tốt
    Rất khuyến nghị; đây là DB local-first duy nhất đáp ứng tất cả điều kiện tôi cần
    Có ngôn ngữ truy vấn hợp lý và sane (không phải SQL), hỗ trợ TypeScript tuyệt vời, hỗ trợ offline, hỗ trợ React Native; thêm việc mã nguồn mở và có thể tự host cũng rất tốt

  • Tò mò liệu có thể dùng cùng với PostgreSQL DB hiện có không

    • Hiện tại thì chưa, nhưng có một công cụ nội bộ dùng giao thức replication của Postgres và WAL2JSON để thực hiện đồng bộ hai chiều
      Chưa sẵn sàng công khai, nhưng dự định sẽ sớm cho mọi người dùng thử
    • Nên xem ElectricSQL, hoạt động với Postgres hiện có
      Tôi cũng đang nghiêng về phía dùng nó