SQLite 與 Litestream:實現持久化工作流的極簡方法
「持久化執行」(durable execution)的概念經常與對沉重、持久化基礎設施的需求混淆。然而,對於大量的應用程式——特別是涉及 AI agent 和實驗性工作流的應用——實際需求並非龐大的資料庫集群,而僅僅是需要一種可靠的方式來持久化工作流狀態。
開發者社群最近的討論(因意識到 Postgres 可以處理持久化執行而引發)將對話推向了更深層次:對於許多使用場景,SQLite 不僅足夠,而且是最佳選擇。
極簡持久化的架構
持久化執行的核心意義在於,如果一個程序崩潰或伺服器重啟,工作流可以從中斷的地方繼續執行。這需要一個執行日誌(execution log),用於記錄進度並持久化歷史紀錄。雖然運算層可以保持廉價且可拋棄(例如 micro-VMs 或 containers),但狀態必須是持久的。
SQLite 非常契合此模型,因為它在提供事務持久性(transactional durability)的同時,無需額外資料庫服務的運維開銷。透過消除與客戶端-伺服器資料庫相關的網路跳轉和複雜的控制平面,開發者可以將狀態保留在運行時(runtime)的本地。
使用 Litestream 解決可移植性問題
在生產環境中使用 SQLite 的主要批評之一是「本地檔案」問題:你該如何備份、遷移或檢查存放在特定磁碟上的資料庫?
Litestream 透過將 SQLite 的變更非同步地串流到 S3 相容的物件儲存中來解決此問題。這建立了一種混合模型,讓應用程式既能享受本地資料庫的低延遲,又能維持雲端備份以供復原與檢查。
必須注意一個關鍵的權衡:由於 Litestream 的複製是異步的,突發的磁碟故障可能會導致最近的寫入遺失。對於高風險的金融系統,這是一個致命傷;但對於 AI agent 和實驗性工作,這通常是可接受的風險。
為什麼此模型在 AI Agent 中表現卓越
AI 生成的工作流通常具有突發性且具實驗性質。為每個 agent 或租戶分配其獨立且自給自足的 SQLite 資料庫具有以下優點:
- 故障隔離: 一個 agent 的狀態損壞或故障不會影響其他 agent。
- 簡單性: Agents 可以部署在一群微型伺服器中,每個伺服器管理自己的狀態檔案。
- Token 效率: 正如社群貢獻者所指出的,LLMs 非常擅長編寫 SQL。允許 agent 查詢 SQLite 表中的特定行,比強迫它使用
jq或grep等工具來解析大型 JSON 或 Markdown 檔案要有效率得多。
反對意見:何時該選擇 Postgres
儘管 SQLite+Litestream 技術棧具有優勢,但它並非萬能解決方案。在幾種場景下,網路資料庫(如 Postgres)仍然是正確的選擇:
- 高可用性: 當需要零資料遺失且異步複製不足以滿足需求時。
- 共享擴展性: 當多個不同機器上的程序必須同時修改相同的數據時。
- 複雜的 Schema 演進: SQLite 有限的
ALTER TABLE能力會使 Schema 遷移變得繁瑣,通常需要建立臨時表來搬移數據。 - 嚴格類型: 來自 Postgres 的開發者通常會發現 SQLite 靈活的類型系統(manifest typing)在數據完整性方面是一種退步。
社群觀點與替代方案
關於「嵌入式 vs. 伺服器」資料庫的辯論凸顯了架構哲學的分歧。有些人認為,從重量級系統(如 Postgres)開始可以避免日後的「遷移稅」(migration tax)——這是一種為了防止未來瓶頸而進行「明智的過度工程」的哲學。
其他人則指出,根據工作負載的不同,有其他的嵌入式工具可供選擇:
- DuckDB: 推薦用於 ETL 和分析任務,其性能超過 SQLite 的能力。
- Temporal: 一個更強大的編排引擎,使用 SQLite 進行本地開發,但在生產環境中擴展到完全分佈式系統。
- Cloudflare Durable Objects: 一個大規模生產系統的範例,利用類似 SQLite 的變體來管理邊緣運算的狀態。
結論
對於許多開發者來說,最明智的預設做法是從最少的基礎設施開始。本地 SQLite 資料庫搭配 Litestream 備份到 S3,為現代 agentic workflows 提供了一個持久、可檢查且高效能的基礎。雖然它可能無法在單個檔案上擴展到數百萬個併發寫入者,但對於隔離的 agent 狀態管理,這通常就是你所需要的一切。