- Cốt lõi của thực thi bền vững không nằm ở bản thân hạ tầng mà ở việc lưu giữ trạng thái workflow; miễn là còn trạng thái tiến trình thì có thể chạy lại và khôi phục
- Obelisk lưu tiến trình workflow vào nhật ký thực thi, phát lại từ lịch sử đã được lưu bền vững, và có cấu trúc phù hợp với việc thử lại hoạt động
- SQLite cung cấp trạng thái bền vững dựa trên giao dịch dưới dạng tệp cục bộ mà không cần dịch vụ cơ sở dữ liệu riêng, network hop hay control plane bổ sung
- Litestream phát trực tuyến bất đồng bộ các thay đổi của SQLite tới object storage tương thích S3, nhưng nếu volume biến mất trước khi sao chép thì có thể mất các lần ghi mới nhất
- Obelisk cũng hỗ trợ Postgres, phù hợp hơn khi cần tính sẵn sàng cao hơn, khả năng mở rộng dùng chung lớn hơn và các đặc tính của cơ sở dữ liệu mạng
Mô hình vận hành của SQLite và Litestream
- Litestream có thể phát trực tuyến bất đồng bộ các thay đổi của SQLite tới object storage tương thích S3
- Có thể giữ trạng thái công việc gần môi trường thực thi, đồng thời sao chép cơ sở dữ liệu ra bên ngoài để sao lưu, migration hoặc kiểm tra
- Do đặc tính sao chép bất đồng bộ, nếu volume SQLite biến mất trước khi được sao chép thì khi khôi phục có thể mất các lần ghi cục bộ mới nhất
- Cấu trúc là chạy máy chủ Obelisk cùng với cơ sở dữ liệu SQLite, sao lưu bằng Litestream, và khi cần thì observer sẽ lấy cơ sở dữ liệu cần thiết
- Cùng một tệp SQLite có thể được dùng để phát lại cục bộ, gỡ lỗi và hiểu những gì tác nhân đã thực sự thực hiện
Phạm vi sử dụng phù hợp và tiêu chí chọn Postgres
- Tác nhân AI và workflow do AI tạo ra thường có tính bùng phát theo đợt và mang tính thử nghiệm, nên cấu hình mỗi tác nhân hoặc mỗi tenant có một đơn vị trạng thái nhỏ riêng sẽ dễ hiểu hơn
- Cách dùng nhiều máy chủ nhỏ trong micro VM hoặc container, mỗi máy có cơ sở dữ liệu SQLite và bản sao lưu object storage riêng, có thể đơn giản hơn, rẻ hơn và cô lập lỗi tốt hơn so với một hệ thống chia sẻ lớn luôn chạy
- Nếu sao chép bất đồng bộ tới object storage không phải là mô hình độ bền mong muốn, hoặc cần tính sẵn sàng cao hơn, khả năng mở rộng dùng chung rộng hơn hay các đặc tính của cơ sở dữ liệu mạng, thì Postgres sẽ phù hợp hơn
- Nhiều hệ thống workflow không cần mức hạ tầng như vậy ngay từ ngày đầu, và không cần bắt đầu với hạ tầng lớn hơn nhu cầu trạng thái
- Chỉ với cơ sở dữ liệu SQLite cục bộ, sao lưu Litestream lên S3 và kết hợp worker giá rẻ cũng có thể tạo ra một hệ thống bền vững với ít hạ tầng; trong mảng tác nhân AI, đây có thể là một mặc định hợp lý
1 bình luận
Ý kiến trên Hacker News
Tôi bắt đầu dùng Temporal để xây dựng workflow; với ứng dụng cục bộ thì nó triển khai khá gọn nhẹ, và trong các cài đặt cục bộ được cô lập thì dùng SQLite
Việc xử lý retry API, dọn dẹp workflow và tác vụ trở nên thực sự đơn giản, nên tôi khuyên nên thử một lần. Về mặt triết lý, nó đi đúng cùng hướng với điều bài viết này đề xuất, nhưng bổ sung một giao diện rất phong phú và linh hoạt, phù hợp để agent sử dụng. Cũng rất dễ xem workflow qua web UI và rà soát các lần chạy của agent
Temporal gần như thêm độ tin cậy cao hơn cho hệ thống với chi phí gần như miễn phí. Hệ thống phân tán và đáng tin cậy rất khó, nên tôi nghĩ tốt hơn là đừng phát minh lại bánh xe
Nếu bạn muốn dễ dàng nhìn vào cơ sở dữ liệu SQLite, hiểu điều gì đang diễn ra trong workflow, kết hợp các tác vụ riêng lẻ và giúp workflow có thể được gọi một cách đơn giản, thì Temporal đáng để xem qua
Cùng với đó, tôi gần như đã giảm hẳn việc dùng file cho agent. Markdown và JSON cũng tốt, nhưng khi làm ứng dụng cục bộ nhỏ thì chúng giống như một cái bẫy. LLM xử lý SQLite rất tốt, và từ đó có thể render ra bất kỳ định dạng nào bạn muốn như Markdown hay JSON. Nếu agent có thể truy vấn đúng các hàng cần thiết thay vì chạy jq hay grep trên Markdown, thì cũng tiết kiệm được rất nhiều token. Bạn sẽ có một hệ thống quản lý dữ liệu tự chứa, tính di động tốt, đồng thời buộc cấu trúc dữ liệu phải quy củ hơn so với việc dùng nhiều file. Khi dự án cục bộ nhỏ phát triển lớn hơn hoặc trở nên chính thức hơn, bạn cũng có thể chuyển tiếp sang MySQL/Postgres, và khi đó đã sẵn có schema cùng tính kỷ luật dữ liệu
Temporal trở nên phức tạp hơn nhiều khi mở rộng quy mô. Việc vận hành Cassandra chẳng vui vẻ gì, còn Ringpop và TChannel thì rất khó debug khi có sự cố. Hỗ trợ SQL backend không cho phép replica scale ngang vì yêu cầu nhất quán, nên chỉ khả thi với một instance duy nhất
Tùy cách viết code, việc sửa mã đã nằm trong workflow cũng trở nên phức tạp. Những thay đổi làm đảo thứ tự sự kiện trong history sẽ phá vỡ tính quyết định của các worker đã được triển khai
Chúng tôi dùng Temporal rất nhiều; ai bắt đầu bằng scripting hay automation đơn giản thì đều thích, còn ai xây hệ thống production thực sự trên đó thì đều ghét. Có thể là do chúng tôi chưa đủ giỏi về vận hành, nhưng bức tranh màu hồng trong các bình luận ở đây không khớp với trải nghiệm của tôi
Tôi chưa tự làm, nhưng muốn nghe thêm trải nghiệm thực tế
Tôi không hiểu sự ám ảnh với việc dùng SQLite cho ứng dụng production thực tế. SQLite là cơ sở dữ liệu nhúng nên hoàn toàn không phù hợp để quản lý đồng thời
Đó là lý do tồn tại của các máy chủ cơ sở dữ liệu như Postgres hay MySQL. Toàn bộ vai trò của chúng là cho phép nhiều tiến trình sửa đổi dữ liệu đồng thời từ các máy khác nhau
Đây là nguyên lý cơ bản của khoa học máy tính, nên phe hô hào “SQLite cho mọi thứ” có vẻ hơi thiếu kinh nghiệm
SQLite là một cơ sở dữ liệu production rất tốt cho nhiều workload thực tế, và điều này đã được tài liệu hóa rộng rãi. Nó rất khác Postgres, nên cần học một bộ kỹ thuật hoàn toàn khác
Một góc nhìn là SQLite có thể rất phù hợp với những phần của hệ thống vốn được phân vùng mạnh một cách tự nhiên
net/httpcủa Go, nhiều dịch vụ đã có thể xử lý toàn bộ mức tải mà người ta có thể hình dung. Điều này càng đúng hơn nếu theo thời gian bạn có thể nâng cấp phần cứng, và SQLite có thể mở rộng khá dễ dàng tới hàng trăm nghìn TPSThứ thực sự phải đánh đổi là tính sẵn sàng cao/chuyển đổi dự phòng và khôi phục thảm họa, nhưng ngay cả việc đó cũng có giải pháp. Các hệ thống một máy chủ nhìn chung bền vững đến ngạc nhiên. Bởi khi không có control plane phức tạp, độ sẵn sàng của hệ thống thường giảm khi quy mô tăng lên
Tôi thích đánh giá lại các “best practice” hiện có dưới góc nhìn của thay đổi công nghệ. Đặc biệt là khi nó hướng tới sự đơn giản hơn. Vận hành một trang mạng xã hội gia đình bằng một DB SQLite trên một VPS là rất tuyệt. Có khoảng 15 người dùng và hầu như không cần bảo trì. Tôi cũng chạy một instance FreshRSS và trang “now” bằng SQLite
Ở chỗ làm, trong vài chục năm qua tôi đã dùng SQLite cho đủ loại mục đích. Tôi đã dùng nó cho hàng đợi công việc tạm thời, để nạp và truy vấn nhanh rất nhiều log cục bộ, và để hiển thị/lọc theo thời gian thực bằng https://github.com/simonw/datasette tuyệt vời của simonw
Tôi nghĩ nó gần với “SQLite ở nhiều nơi hơn bạn tưởng rất nhiều” hơn là “SQLite cho mọi thứ”
Công việc về edge SQLite của kentonv/Cloudflare có thể đã phổ biến hóa thêm suy nghĩ này, nhưng đó vốn đã là một xu hướng sẵn có. https://blog.cloudflare.com/sqlite-in-durable-objects/
Muốn biết và tận dụng những trường hợp nhỏ nhưng hữu ích như vậy không phải là dấu hiệu thiếu kinh nghiệm, mà ngược lại có thể là dấu hiệu của kinh nghiệm
SQLite có khả năng được dùng nhiều hơn tất cả các engine cơ sở dữ liệu khác cộng lại. Có hàng tỷ bản sao SQLite tồn tại ngoài thực tế. Nó có mặt trong thiết bị Android, iPhone và thiết bị iOS, Mac, các bản cài đặt Windows 10/11, Firefox/Chrome/Safari, Skype, iTunes, Dropbox client, TurboTax và QuickBooks, PHP và Python, hầu hết TV và set-top box, phần lớn hệ thống giải trí trên xe hơi, cùng vô số ứng dụng khác
https://sqlite.org/mostdeployed.html
Cách này khiến khả năng mở rộng dễ hiểu hơn rất nhiều. Chỉ cần tách ra rồi lặp lại. Cứ mỗi N người dùng thì thêm một shard
Đổi lại, bạn sẽ có các vấn đề khác như truy vấn xuyên shard, ví dụ phân tích dữ liệu, và cách cân bằng tải khi người dùng rời đi hoặc trở nên cũ kỹ
Nhưng bạn có thể tránh được toàn bộ vấn đề mở rộng chỉ mục dùng chung do insert/update tạo ra ở quy mô người dùng lớn
Nó trở thành một cơ sở dữ liệu phân cấp hơn là một cơ sở dữ liệu quan hệ
Đã thay thế tất cả những thứ sau bằng Go + SQLite: Intercom, Zendesk, email marketing, Kanban, Todo, payment stack, issue tracker, forum, giám sát uptime, bản sao PagerDuty
Vì đang bán hàng chục sản phẩm, tôi nghĩ sao không tự làm hết luôn
Tất cả đều chạy trên cùng một server và dùng rất ít bộ nhớ. Tôi đã thay toàn bộ các công cụ SaaS đang dùng bằng những thứ này
Sau khi chuyển sang server riêng, chi phí giảm còn khoảng 1/10 so với số tiền từng trả cho các giải pháp cloud managed, trong khi vẫn giữ cùng mức độ sẵn sàng cao và còn có độ trễ thấp hơn. Một phần lý do cũng là tail latency từng tăng do noisy neighbor trên VPS
Trước đây tôi đã tốn rất nhiều tiền cho mấy thứ này, nhưng giờ đã vận hành được 4 tháng và chỉ cần vài cập nhật nhỏ
Triển khai thật sự rất đơn giản. Không có Docker hay Kubernetes, chỉ có các service systemd và các binary được build trên máy phát triển rồi deploy
Trước đây tôi cũng trả tiền cho các dịch vụ như MaxMind hay IPData, nhưng rồi tự làm dịch vụ định vị địa lý IP và trong thử nghiệm nó cho hiệu năng tốt hơn phần lớn các giải pháp hiện có
Ban đầu là để thay Uptime Robot, sau đó tự tin hơn nên thay luôn PagerDuty. Sau nữa là thay Intercom
Cuối cùng, tôi luôn nghe câu “đừng tự xây payment stack”, nhưng nghĩ YOLO nên quyết định tự mình phạm sai lầm đó. Tôi đã nghiên cứu các giải pháp thanh toán hiện có, tự phát triển và triển khai nó, và đến giờ hoàn toàn chưa có vấn đề gì
Phía trước tôi dùng Caddy
Tôi nhận ra rằng trong số các chức năng mà đa số sản phẩm SaaS cung cấp, thực ra tôi chỉ dùng 1~5%, còn những chức năng thật sự cần thì ngày càng bị chôn sâu hơn trong các nền tảng “enterprise-grade” này, khiến workflow khó khăn hơn
Tôi sẽ không cho xem các sản phẩm thương mại vì đối tác và khách hàng chắc sẽ không thích biết tôi rẻ đến mức nào, nhưng tôi gọi đây là sự tháo vát
Có thể cho xem app miễn phí. Mới ra mắt gần đây và đã có hơn 20 nghìn người dùng: https://macrocodex.app/
App này chỉ dùng bản sao Zendesk. Email được xử lý bằng Cloudflare routing nên chi phí vận hành gần như bằng không
Giữa một file và cơ sở dữ liệu đa phân vùng là cả một khoảng cách lớn. Khi vận hành thực tế phụ thuộc vào nó, chạy cơ sở dữ liệu trong container không hợp gu của tôi
Cá nhân tôi thấy nhiều ETL có thể xử lý cục bộ mà không cần kéo cơ sở dữ liệu enterprise vào. Trong những trường hợp đó, DuckDB tốt hơn SQLite khoảng 5~10 lần, đồng thời đơn giản và nhanh hơn rất nhiều so với việc dựng một cơ sở dữ liệu Postgres chuyên dụng
Với scripting thông thường, một script awk 20 dòng không thể so với một script SQL tương đương dựa trên DuckDB sạch sẽ hơn nhiều, chắc chắn hơn và dễ bảo trì hơn
Mong là MotherDuck không rơi vào tình cảnh phải pump-and-dump để IPO. Sẽ rất buồn nếu mất công cụ này vì lòng tham doanh nghiệp quen thuộc
Câu chuyện về script awk 20 dòng rất thú vị. Hôm qua tôi gần như đã đưa ra đúng lập luận đó tại Ubuntu Summit. Từ một thời điểm nào đó, việc viết shell script bằng GNU coreutils trở nên thiếu thực tế, còn script SQL của DuckDB mở rộng tốt hơn về độ phức tạp, khả năng bảo trì và thường cả hiệu năng nữa. Slide ở đây: https://blobs.duckdb.org/slides/duckdb-ubuntu-summit-2026.pd... trang 32~36
Ngoài ra MotherDuck phát triển một DBaaS mã nguồn đóng trên nền DuckDB. Họ xây trên DuckDB, và kết nối tới MotherDuck bằng DuckDB, nhưng là một công ty được đầu tư VC riêng biệt có trụ sở tại Seattle
DuckDB được phát triển bởi DuckLabs, một công ty bootstrap tại Amsterdam, tức công ty dựa trên doanh thu. Tài sản trí tuệ của dự án thuộc về tổ chức thứ ba là DuckDB Foundation, một tổ chức phi lợi nhuận tại Hà Lan. Xem thêm tại https://duckdb.org/faq#how-are-duckdb-the-duckdb-foundation-...
Tôi đã tạo một thư viện cho phép cập nhật đồng thời an toàn SQLite DB trên S3[0]
Nó hoạt động khá hiệu quả và an toàn nhờ dùng SQLite sessions extension ít người biết đến cùng compare-and-swap của S3 cho một file metadata nhỏ. Tôi đang dùng nó rất vui trong nhiều dự án nhỏ cần DB lưu trạng thái cho hàm Lambda nhưng không muốn trả chi phí cho cả một instance cơ sở dữ liệu
[0]: https://github.com/psanford/s3db
SQLite cho hiệu năng đáng ngạc nhiên ngay cả khi so với Postgres trong ứng dụng một node
Postgres dùng bộ nhớ nhiều hơn rất nhiều, và I/O phải đi qua giao tiếp liên tiến trình. Trong khi đó, với SQLite bạn có thể giữ mọi thứ trong cùng tiến trình thông qua shared connection pool
Tôi đang thử nhiều storage engine cho agent harness, và với SQLite thì trên một vCPU đơn lẻ có thể đạt tới 7,5 nghìn phiên đồng thời, còn Postgres thì hoặc crash hoặc cạn kết nối
[0] https://github.com/impalasys/talon/pull/23#issuecomment-4577...
Ngay khoảnh khắc bạn rời khỏi thread hiện tại thì đã là một cuộc chơi thua về độ trễ. Nếu không ép giao tiếp liên thread, SQLite có thể hoạt động ở thang thời gian micro giây
Trong bối cảnh một node, Postgres là quá mức cần thiết. Không nên kỳ vọng nó cạnh tranh với SQLite
Nó gần giống như benchmark giữa HashMap gần như chạy trong bộ nhớ với Redis, rồi ngạc nhiên khi HashMap cho kết quả tốt trong điều kiện lý tưởng nhất
Sau nhiều năm đọc về SQLite, tôi đã thử dùng nó cho một dự án cá nhân, nhưng sau khi quen với Postgres thì tôi bị sốc vì hệ thống kiểu dữ liệu của nó quá nghèo nàn.
Thật sự rất kém, tôi không hiểu vì sao nó lại được ca ngợi nhiều đến vậy.
https://sqlite.org/datatype3.html
https://www.postgresql.org/docs/current/datatype.html
Cảm giác xử lý ngày/giờ như đang dùng một cơ sở dữ liệu 30 năm tuổi, và khi chèn dữ liệu thì chẳng có gì được ép buộc cả. Cần ai đó giải thích vì sao nhiều người lại thích nó đến vậy.
PRAGMA journal_mode = WAL
PRAGMA foreign_keys = ON
Something non-null
PRAGMA busy_timeout = 1000This is fine for most applications, but see the manual
PRAGMA synchronous = NORMALIf you use it as a file format
PRAGMA trusted_schema = OFFTùy binding mà có thể cần thêm các tùy chọn khác. Ví dụ, ứng dụng Python không nên dùng giá trị mặc định của mô-đun sqlite3. Mặc định đó đơn giản là sai. Trước 3.12 thì thậm chí không có lựa chọn nào khác ngoài việc dùng binding ngoài thư viện chuẩn: https://docs.python.org/3/library/sqlite3.html#transaction-c...
Cũng nên dùng strict table. https://www.sqlite.org/stricttables.html
Dù hơi khó dùng, bạn cũng có thể dùng ràng buộc CHECK. Ví dụ với hỗ trợ ngày tháng tích hợp của SQLite thì làm được, nhưng khá gượng gạo:
CHECK (
date(my_date_col) IS NOT NULL
AND my_date_col = date(my_date_col)
)
Cần
IS NOT NULLvìdatetrả về NULL khi ngày không hợp lệ. Kiểm tra còn lại là vì nó cũng chấp nhận cả ngày Julius, nêndate('2026')sẽ trở thành một thời điểm nào đó trong năm 4707 TCN.Tôi đồng ý là nó gây thất vọng, đặc biệt là trước khi có strict table.
Bạn nên xem DuckDB. Nó gần giống một SQLite có kiểu dữ liệu tử tế. Tuy nhiên, nó là OLAP, tức array-of-structs, chứ không phải OLTP, tức struct-of-arrays, nên với tải SQLite thông thường thì hiệu năng có thể tệ hơn. Nhưng với những ứng dụng thực sự cân nhắc giữa hai bên thì có lẽ khác biệt không lớn.
Tôi đã chuyển từ nhiều cụm Postgres lớn sang SQLite, và hiện toàn bộ một dịch vụ có số người dùng hoạt động hàng tháng 7 chữ số đang chạy trên SQLite durable objects.
Cần suy nghĩ khác về mẫu truy cập, nhưng lợi ích đem lại hoàn toàn xứng đáng.
Cách đặt vấn đề này rất hay. Nếu vấn đề chính là lưu trạng thái workflow một cách bền vững, có thể quan sát được và dễ khôi phục, thì trong nhiều trường hợp SQLite là đủ.
Tôi rất muốn sớm thấy vòng lặp tiếp theo của ý tưởng này: “workflow bền vững chỉ cần log là đủ”.
Một lý do khiến các giải pháp kiểu “chỉ cần log là đủ” có thể thất bại là khi log không đáng tin cậy trở thành một cuộc tấn công chèn đầu vào[1].
Hãy kiểm tra SBOM, và đừng quên bao gồm cả pipeline CI/CD[2].
[1] https://news.ycombinator.com/item?id=48315440
[2] https://github.com/jqwik-team/jqwik/issues/708#issuecomment-...
Nói nghiêm túc thì, làm chuyên gia là biết dùng đúng công cụ cho đúng việc.