資料庫 自架服務 SQLite Rust Turso MVCC

SQLITE_BUSY 撐了 25 年沒人換掉,libSQL 只是換包裝:Turso 用 Rust 重寫 SQLite,把單寫入者瓶頸跟同步 API 一起拆掉

Turso 是 SQLite 的純 Rust 重寫版本,2026 年 5 月推進到 0.6.1 beta,靠行級 MVCC 拆掉單寫入者瓶頸、用 io_uring 把同步 API 改成 async、內建向量搜尋接住 RAG 工作負載。本文拆解架構選擇、效能數字、跟 libSQL 的關係,以及在自架場景下該怎麼選。

SQLite 是地球上部署最廣的資料庫——每支瀏覽器、每臺手機、每個 Electron 應用裡都有一份。它的 C 程式碼配上 TH3 測試套件這套組合在嵌入式情境裡近乎無敵,連飛機航電系統都信得過它。但這個地位也讓 SQLite 的核心架構幾乎封死——單一寫入者、同步 syscall、沒有向量索引、TH3 還是付費版——任何想往裡面塞現代資料庫該有功能的人都得在外面繞一圈。Turso 是 2025 到 2026 年間少數真的下決心從頭來過的方案,用 Rust 完整重寫 SQLite,並在 2026 年 5 月推進到 0.6.1 beta。

Turso 這個名字本身在最近一年裡變得很混亂。同一家公司有 libSQL(C 語言的 SQLite fork)、Turso Cloud(託管服務)、以及這次的 Turso Database(Rust 重寫,前代號 Limbo)。本文聚焦在最後一個,因為它跟前兩者在技術定位上是斷層式的差別——前兩者本質還是 SQLite 的延伸,這個是從零寫起的全新引擎,目標是接住 SQLite 在 async I/O、平行寫入、向量搜尋這幾條路線上的空缺。

單寫入者這件事,撐了 25 年也沒人換掉

SQLite 的 WAL 模式雖然讓讀取可以跟寫入並行,但寫入本身依舊序列化——同時間只能有一筆 transaction 寫入 commit。在最樂觀的情況下單機可以推到 15 萬 row/sec,但只要 transaction 裡夾任何業務邏輯,吞吐量就會塌下來。Turso 官方拿了一個常見情境量測:transaction 內加一個 1 毫秒的計算(比如價格驗證、庫存檢查),SQLite 的吞吐量從 15 萬掉到 8 萬,多開執行緒完全沒幫助。

問題的根源不在 SQLite 寫得不夠快,而是它的鎖粒度是整個資料庫。一筆寫入 transaction 拿到的鎖把所有後續寫入擋在門外,第二個寫入請求進來會直接被 SQLITE_BUSY 退掉。任何寫過 Rails 或 Django 配 SQLite 的開發者都熟悉這個錯誤——尖峰流量下整批 worker 退請求、應用程式得自己排隊重試,乾脆換 Postgres 還比較省事。

SQLite 本身有一個實驗性的 BEGIN CONCURRENT,把鎖粒度從整個資料庫拆到 page 層。問題是 page 還是太粗——兩筆寫不同 row 但落在同一 page 的 transaction 依舊衝突。實務上 BEGIN CONCURRENT 從 2017 年實驗到現在還沒進主線,作者本人也說過這條路要走進 SQLite 主版本還需要很多年。

行級 MVCC 把鎖粒度拆到最細

Turso 對這個瓶頸的解法是把 MVCC(Multi-Version Concurrency Control)直接做進引擎裡。實作上維護一份 in-memory 的 row version 索引,每筆寫入記錄 row 的版本,transaction 在 commit 階段才檢查衝突。寫不同 row 的 transaction 完全互不阻塞,就算寫同一張 table 也不會卡死。

這個機制讓多執行緒寫入第一次在 SQLite 相容引擎上變成可能。同樣那個 1 毫秒業務邏輯的 benchmark,8 執行緒下 Turso 跑到 SQLite 的四倍吞吐量。沒有業務邏輯的純寫入下,差距收斂到 16%——核心瓶頸從鎖搬到磁碟。

具體用法是在啟動時加 --experimental-mvcc 然後用 BEGIN CONCURRENT 開 transaction,跟 SQLite 那個 page 級的同名指令在語法上一致,但底下的衝突檢測是 row 級。從現有 SQLite 程式碼遷移幾乎沒有改動成本——BEGINCOMMITSELECTINSERT 全相容,差別在 SQLITE_BUSY 不會再噴出來。

要注意的是 MVCC 在 Turso 0.6 還算 early preview,已知幾個限制:CREATE INDEX 在 MVCC mode 下還不能用、row version 暫時各存完整副本(記憶體開銷比成熟資料庫高)、底層資料結構還不是 lock-free。這幾個都在 roadmap 上,但在 GA 前不建議拿它跑寫入密集型的關鍵工作負載。

io_uring 把 SQLite 從 blocking syscall 解綁

第二個架構層級的改動是 I/O 模型。SQLite 的 API 從第一天起就是 blocking——每次 step 都可能直接觸發 read()write() 同步呼叫,呼叫端執行緒會被卡住直到 syscall 回來。Node.js、Python asyncio、Tokio 想接 SQLite 都得自己起 helper thread pool 把 blocking call 包進去再丟回 event loop,這個 wrapper 本身就是延遲跟複雜度的來源。

Turso 從骨架就設計成 async-first。Linux 上的 I/O 後端走 io_uring——這是 Linux 5.1 之後引入的 syscall,可以把一批 I/O 請求送進核心、之後再來收結果,期間呼叫端執行緒可以做別的事。對於 SQLite 這種典型工作負載(一次 transaction 觸發多個 page read/write),io_uring 能把多個 syscall 合併成一次系統呼叫,明顯降低 context switch 成本。

對應用程式端的意義是,Node.js 或 Rust 的 async function 裡直接 await db.execute(...) 不會卡住整個 event loop——這在過去 SQLite 生態裡得靠 worker_threads 或 spawn_blocking 才能做到。對於跑在單核心 VPS 上的 Bot、API 服務、或想用 SQLite 撐 WebSocket 連線狀態的場景,這是直接的效能拉升。

內建向量搜尋接住 RAG 工作負載

Turso 的第三個明顯擴張是向量搜尋。SQLite 本身沒有向量索引,過去想做 RAG 的人會裝 sqlite-vecsqlite-vss 這類 extension,但 extension 跟核心引擎的整合永遠是二等公民——查詢計畫沒辦法跨 vector index 跟一般 index 最佳化、ALTER TABLE 改 schema 容易把 extension 弄壞。

Turso 把向量型別跟相似度搜尋做進核心,目前支援精確搜尋(exact KNN),近似搜尋的 vector index 還在 roadmap 上。對於小型嵌入式 RAG 場景——AI agent 在自己的 SQLite 檔裡記憶體幾千到幾十萬筆 embedding——精確搜尋已經夠用,比起架一臺獨立的 Qdrant 或 pgvector 簡單太多。

這個方向跟 Turso 整體定位有關。官方明確把 agentic AI 列為目標客群之一——每個 AI agent 一個小型 SQLite 檔,閒置時只佔儲存、被叫起來時冷啟動近乎零延遲。傳統把 Postgres 當 multi-tenant 後端的架構在「100 萬個 agent、每個一個 schema」的場景下會崩,但 SQLite 的 file-per-tenant 模型天生適合這條路線。

libSQL、Turso Cloud、Turso 這三個名字到底差在哪

這部分得釐清,因為 Turso 自己的命名歷史讓人迷路。

libSQL 是 Turso 公司最早的專案——SQLite 的 C 語言 fork,加上 server mode、HTTP API、embedded replica 等延伸。它依舊是 SQLite 的衍生版本,跟 SQLite 主版本同步 bug fix。目前 Turso Cloud 託管服務跑的就是 libSQL,已經算 production ready,許多 Vercel、Cloudflare Workers 部署的 Next.js 應用用的是這套。

Turso Cloud 是 SaaS 託管服務,底下是 libSQL。它賣的核心是「資料庫即檔案」加上分支複製、edge replication、按用量計費的整套體驗。對於不想自架的小型應用,這條路線存在感比 PlanetScale 弱、但比 Neon 在 SQLite 生態圈裡有優勢。

Turso Database(前代號 Limbo)就是這篇文章的主角,純 Rust 重寫的引擎。MIT 授權、in-process 嵌入式定位,跟 SQLite C library 一樣是「連進應用程式裡跑」的形態,不是 server mode。目前 0.6.x beta,根據官方說法已經有 Kin AI、Spice.ai 等專案在生產跑,但要拿來替代飛機航電系統的 SQLite 還差得遠。

簡單記法:要 SaaS 用 Turso Cloud、要嵌入相容性穩用 libSQL、要 async + MVCC + 向量搜尋這些新特性自架用 Turso Database。

該選 SQLite、libSQL 還是 Turso

放下意識形態的選擇判斷其實清楚。

繼續用 SQLite 的情境:應用程式是純讀多寫少(部落格、文件站、查詢型 API);寫入併發從來沒撞到 SQLITE_BUSY;需要極端穩定、二十年來 zero CVE 的 track record。多數小型 web 應用屬於這一類,換掉沒好處。

選 libSQL 的情境:需要 server mode(多個 client 透過網路連同一份資料)、需要 embedded replica(本地寫入同步到遠端)、想用 Turso Cloud 的託管服務。這條路線是 SQLite C 核心配上現代 ops 體驗,穩定度跟 SQLite 接近。

選 Turso Database 的情境:寫入密集、被 SQLITE_BUSY 打到過;用 Rust、Node.js、Python async 重度依賴 await 模型;需要做 RAG、AI agent、需要在同一個檔案裡塞向量搜尋;或者單純想評估下一代 SQLite 長什麼樣。這條路線目前不適合金融、健保、航空這類零容錯場景,beta 就是 beta。

中間有一個混合用法值得提:開發階段用 SQLite、staging 環境跑 Turso 評估相容性、生產維持 SQLite 直到 Turso GA。這套漸進式遷移路徑在這類底層替換上是合理的——資料檔案二進制相容,回退到 SQLite 不需要 dump/restore。

Beta 階段的真實風險

Turso 在 Hacker News 上被批評最多的點是測試覆蓋。SQLite 的 TH3 測試套件號稱「達到 100% MC/DC 覆蓋率」,但它是 SQLite 作者付費版獨家,外部專案拿不到。Turso 只能靠 SQLite 公開的測試集加自己寫的 fuzzing,這個 gap 短期內補不上。

實務上的意義是:Turso 在常見路徑上表現穩定,但邊界情境——transaction rollback 在 OS 崩潰中途、SQL 解析器的詭異輸入、page corruption recovery——這些 SQLite 用 25 年磨出來的健壯性,Turso 還沒到。要在生產跑 Turso 的人應該假設「核心邏輯沒問題、但邊界 case 自己得多測」,且備份策略要比平常更謹慎。

另一個爭議是 VC 模型的長期可持續性。Turso 公司本身有募資壓力,未來改授權的可能性永遠存在——這在 HashiCorp、Redis、Elastic 連環事件之後是合理的擔憂。MIT 授權加上完整 source 在 GitHub 上提供了基本保護,但比起 SQLite 的 public domain 還是低一階。Turso 自己拿來當賣點的「open governance」是不是真的能維持,得看接下來兩三年的執行。

SQLite 的下一個 25 年該長什麼樣

SQLite 之所以難動,不只是技術問題,更是因為它已經穩定到「不變才是最重要的特性」。Turso 願意賭的是另一個方向——AI agent、邊緣運算、Rust 原生 async,這些新工作負載對 SQLite 的需求跟過去 25 年差很多。如果它能在 GA 前把 MVCC、io_uring、向量搜尋三條主線打磨穩定,那 SQLite 的下一個十年很可能會分成兩個生態:經典 SQLite 守住嵌入式跟離線情境,Turso 接住 AI agent 跟 async 服務。

對於在 VPS 或邊緣節點跑大量小型 SQLite 檔的場景——AI agent、多租戶 SaaS、bot 平台——Turso 的架構優勢在 beta 階段就已經能看到。要平穩跑起來需要的底層條件不複雜:穩定的 Linux 核心(io_uring 在 5.6+ 才完整)、足夠的 IOPS(MVCC 對隨機寫入敏感)、足夠的單核心效能(async runtime 仍然受單核時脈影響)。

NCSE Network 在臺灣是方電訊機房提供採用 Intel Xeon Gold CPU 與 NVMe SSD 的 VPS 主機,單核心效能與磁碟 IOPS 在這類嵌入式資料庫工作負載上有實際差異,搭配臺灣本地的低延遲線路適合跑 Bot、AI Agent、多租戶後端服務。前往 ncse.tw 了解規格與方案細節。

需要技術開發支援?

NCSE Network 提供 Discord Bot、LINE Bot、AI Agent、爬蟲、監控系統等客製化開發服務,從規劃到上線一站式完成。

洽談專案 →