SQLite 在廉價 VPS 上的效能表現:真實工作負載基準測試

關於何時該從 SQLite 遷移到像 PostgreSQL 這樣的客戶端-伺服器資料庫,爭論的核心通常在於「規模」。然而,規模往往被誤解為一個二元門檻,而非效能權衡的連續光譜。為了了解 SQLite 究竟在何時達到極限,我們需要超越合成微基準測試,並檢視當工作集(working set)超過可用系統記憶體時的表現。

由 s13k 最近在廉價的 Hetzner CX23 VPS(每月 $4.99 美元)上進行的基準測試,為 SQLite 的能力提供了實際的觀察。透過在僅有 3.7 GB RAM 的機器上測試 6 GB 的資料庫,這些測試迫使引擎必須存取磁碟,模擬了數據增長最終超過硬體資源的真實場景。

測試環境

為了確保結果適用於生產環境,基準測試是在一台低階、共享資源的機器上執行的,其規格如下:

  • 硬體: 2 vCPU Intel Xeon Skylake @ 2.1 GHz, 3.7 GiB RAM(無 swap)。
  • 作業系統: Debian 13,使用 ext4 檔案系統(noatime, scheduler=none)。
  • 軟體: SQLite 3.53.1,靜態連結至一個 C 基準測試工具。

生產環境現實配置

基準測試並非為了追求極致速度而進行調優,而是使用了一組「符合生產環境現實」的 pragma 設定。此配置在效能與數據安全性之間取得了平衡:

  • journal_mode = WAL:Write-Ahead Logging 允許讀取者在不阻塞寫入者的情況下進行操作,反之亦然,從而實現更好的併發性。
  • synchronous = NORMAL:這是一個關鍵的權衡。雖然 NORMAL 並非嚴格的 ACID 持久性(斷電可能會導致 WAL 中最新的交易遺失),但它能防止資料庫損壞,且速度明顯快於 FULL。對於需要絕對持久性的應用程式(例如支付處理),FULL 仍是必要的選擇。
  • page_size = 8192cache_size = 256 MiB
  • mmap_size = 256 MiB

效能分析:磁碟受限 vs. 快取

本研究的核心在於比較「快取狀態」(資料庫完全符合在 RAM 中)與「磁碟受限狀態」(資料庫大於 RAM)之間的差異。

當資料庫超過 RAM 時

使用 6 GB 的資料庫時,每一次隨機讀取都必須付出 I/O 代價。針對混合 OLTP 工作負載(70% 讀取、25% 更新、5% 插入)的結果顯示,吞吐量為 3,915 ops/s,p99 延遲為 710 µs,p999 延遲為 2.2 ms

Phase Throughput p50 p95 p99 p999
BULK INSERT (10M rows) 61,300/s 8 µs 58 µs 58 µs 143 µs
SELECT random PK 3,609/s 265 µs 476 µs 715 µs 2.3 ms
SELECT indexed range scan 3,477/s 290 µs 599 µs 895 µs 2.9 ms
UPDATE per-row 2,986/s 257 µs 473 µs 706 µs 2.2 ms
MIXED OLTP 3,915/s 257 µs 455 µs 710 µs 2.2 ms

「引擎天花板」

當工作集縮減至約 246 MB(1M rows)時,資料庫可以輕鬆地放入系統快取中。這揭示了 SQLite 引擎在此特定硬體上的最大潛力,消除了磁碟 I/O 對熱路徑(hot path)的影響。

  • 隨機 PK SELECTs: 從 3.6k/s 跳升至 155.8k/s
  • 混合 OLTP: 從 3.9k/s 增加到 53.2k/s
  • 併發讀取: 從 10.3k/s 增加到 104k/s

關鍵結論與「I/O 崩潰」

比較這兩種狀態可以發現一個殘酷的現實:一旦工作集超過了快取,隨機讀取效能會瞬間崩潰 43 倍。這是 SQLite 應用程式在擴展時的主要瓶頸:並非引擎本身,而是底層的儲存媒介。

然而,即使在最糟的磁碟受限場景下,效能表現依然令人印象深刻。在一個每月 $5 美元的 VPS 上,約 3.9k ops/s 的吞吐量相當於每小時約 1,400 萬次操作。隨著尾端延遲(tail latency)保持在 3 ms 以下,SQLite 對於絕大多數 Web 應用程式來說仍然是一個非常可行的選擇。

結論

對於大多數開發者而言,SQLite 的「規模」極限遠比一般人想像的要來得遠。雖然從 RAM 轉向磁碟時的效能下降非常顯著,但其絕對效能底線仍然足以應付生產環境的負載,即使是在最便宜的硬體上。除非您的應用程式需要對每一次寫入都進行嚴格的 ACID 持久性,或是需要極大的寫入併發量,否則 SQLite 通常綽綽有餘。

Sources