SQLite Backend 的效能受三個因素影響:儲存裝置(SSD vs HDD vs SD card)、Go driver 選擇(modernc.org/sqlite pure Go vs mattn/go-sqlite3 CGO)、並發模型(WAL mode + single-writer)。本章根據 SQLite 的技術特性和業界基準推導預期效能範圍,並提供實測方法讓使用者在自己的環境驗證。所有數字是預期範圍而非實測值 — 實際效能依硬體和 workload 而定。

寫入吞吐

寫入吞吐決定 collector 每秒能消化多少事件。SQLite 的寫入效能主要受 fsync 頻率和 WAL checkpoint 影響。

單筆 INSERT

每筆 INSERT 獨立一個 transaction 時,每次 commit 都會 fsync。WAL mode 的 fsync 成本比 journal mode 低(append-only),但仍是寫入的主要瓶頸。

儲存裝置單筆 INSERT 延遲理論上限
NVMe SSD10-30 μs30,000-100,000 inserts/sec
SATA SSD30-50 μs20,000-30,000 inserts/sec
HDD50-200 μs5,000-20,000 inserts/sec
SD card500-2000 μs500-2,000 inserts/sec

modernc.org/sqlite(pure Go)的效能約為 CGO driver(mattn/go-sqlite3)的 60-80%。上表數字基於 CGO driver,pure Go 需打八折。Go HTTP handler 的開銷(JSON 解碼、schema 驗證、goroutine 調度)再扣 10-20%。

批次 INSERT

一個 transaction 包裹多筆 INSERT,只做一次 fsync。Collector 接收 SDK 的 flush batch(一個 HTTP request 帶一批事件)天然適合批次寫入。

吞吐提升幅度和批次大小的關係:

批次大小相對單筆的吞吐提升
10 筆/tx3-5x
100 筆/tx5-10x
1000 筆/tx8-15x

提升來自 fsync 次數從「每筆一次」降到「每批一次」。超過 100 筆/tx 後邊際收益遞減。

實際預期

結合 pure Go driver、HTTP handler 開銷和批次寫入,不同環境下的預期吞吐:

環境單筆批次(100/tx)適合場景
Mac M1/M2 NVMe + pure Go~5,000/sec~30,000/sec開發機
Linux VPS SATA SSD~3,000/sec~20,000/sec小型部署
Raspberry Pi 4 SD card~200/sec~1,000/sec邊緣設備

和事件產生速率的對照

場景預估 events/secSQLite 批次能撐嗎
自用 1 個 app< 10遠超需求
小團隊 5 人各跑 1 個 app< 50綽綽有餘
10 SDK 同時 flush100-1000 burst批次 INSERT 撐得住
100+ 使用者持續活躍500+ 持續邊界 — 觀察 database is locked

burst 和持續的差異在於:burst 是短暫的高峰(flush batch 到達後數秒內消化完),持續是長時間的穩定高流量。SQLite 的 WAL mode 對 burst 容忍度高(write lock 等待時間短),對持續高流量容忍度有限(write lock 等待累積)。

查詢延遲

查詢延遲決定 dashboard 的刷新體驗。SQLite 的查詢效能取決於索引覆蓋和掃描行數。

有索引的查詢

建議的索引(見 規模演進 的建議索引段)覆蓋 dashboard 的核心查詢模式。有索引時的預期延遲:

查詢模式10 萬筆50 萬筆100 萬筆
等值查詢(WHERE session_id = ?)< 1ms< 1ms< 1ms
範圍查詢(WHERE ts BETWEEN ? AND ?)< 10ms10-50ms50-100ms
GROUP BY name10-50ms50-200ms200-500ms
COUNT DISTINCT session_id50-100ms200-500ms500ms-1s
JOIN + window function100ms-1s1-3s3-10s

無索引的查詢

無索引時 SQLite 做全表掃描。掃描速度約 50-100 MB/sec(SSD)、10-30 MB/sec(HDD)。

資料量預估大小SSD 全掃延遲HDD 全掃延遲
10 萬筆~40 MB200-500ms1-3s
100 萬筆~400 MB2-5s10-30s
300 萬筆~1.2 GB5-15s30-90s

超過 100 萬筆無索引查詢會超出 dashboard 可接受的刷新延遲 — 這是 day-one 就建索引的理由。

Dashboard 刷新頻率 vs 查詢延遲

Dashboard 的每個視圖有不同的刷新間隔和可接受延遲。查詢延遲超過可接受值時,dashboard 體驗變差(等待轉圈、資料過時)。

Dashboard 視圖刷新間隔可接受延遲10 萬筆有索引100 萬筆有索引
即時狀態卡1-5 秒< 100ms滿足滿足
Error 列表5-10 秒< 500ms滿足滿足
趨勢圖(最近 24h)30 秒< 1s滿足邊界
長期聚合(最近 30 天)5 分鐘< 3s滿足需要預聚合

「需要預聚合」代表原始事件的聚合查詢超過可接受延遲,應該依賴分層保留策略中的 hourly_summary / daily_summary 表(見 規模演進 的分層保留段)。

資源消耗

記憶體

元件佔用備註
Go HTTP server20-50 MB基礎開銷
SQLite page cache2 MB(預設)PRAGMA cache_size 可調
寫入 buffer(channel)1-10 MB取決於 channel 容量和事件大小
查詢結果暫存和結果集成正比GROUP BY 10 萬筆 ~10 MB
Collector 整體50-100 MB自用場景

Raspberry Pi(1 GB RAM)上建議把 page cache 調小(PRAGMA cache_size = -512 = 512 KB),避免大結果集查詢(加 LIMIT),dashboard 刷新頻率降低。

CPU

操作CPU 使用備註
INSERT(寫入)可忽略I/O bound,CPU 不是瓶頸
SELECT(查詢)和掃描行數正比有索引時可忽略
Downsample(每小時)短暫 spike < 1s處理最近一小時的事件
Purge(每天)短暫 spike 1-3s分批 DELETE
整體< 5%自用場景

磁碟

日事件量原始資料/天原始資料/月含索引/月
1,000(極低)0.3-0.5 MB9-15 MB11-18 MB
10,000(自用)3-5 MB90-150 MB110-180 MB
100,000(小團隊)30-50 MB0.9-1.5 GB1.1-1.8 GB

WAL 檔案通常 < 10 MB(auto-checkpoint 在 WAL 達到 1000 pages 時觸發)。分層保留策略下,原始事件只保留 7 天,長期佔用由聚合摘要表決定(遠小於原始事件)。

邊緣設備場景

Raspberry Pi、低配 VPS(1 核 / 1 GB RAM)、甚至 NAS 上跑 collector 時的特殊考量:

SD card 的隨機寫入:SD card 的隨機寫入 IOPS 極低(100-500 IOPS),WAL mode 的 checkpoint(把 WAL 內容合併回主資料庫檔案)可能卡住 1-5 秒。期間新的寫入等待 checkpoint 完成。建議調高 wal_autocheckpoint 的閾值(如 5000 pages),讓 checkpoint 頻率降低但每次時間更長 — 在非活躍時段(凌晨)手動觸發 PRAGMA wal_checkpoint(TRUNCATE)

1 GB RAM:cache_size 調小(512 KB)、避免 SELECT * 不帶 LIMIT、GROUP BY 的結果集用 HAVING 條件過濾減少暫存。Dashboard 的長期聚合直接查 hourly_summary 表而非原始事件。

ARM CPU:pure Go SQLite driver(modernc.org/sqlite)在 ARM 上的效能差距可能比 x86 更大(pure Go 的 C-to-Go 翻譯在 ARM 的指令最佳化較少)。實測確認。

建議配置:邊緣設備上 collector 的 dashboard 刷新頻率從預設值降低(即時狀態卡 5 秒 → 30 秒,趨勢圖 30 秒 → 5 分鐘),降採樣 job 頻率從每小時改為每 6 小時。

實測方法指引

教學的預期數字是推導值,實際效能取決於使用者的硬體和 workload。Collector 提供內建的 benchmark 命令讓使用者在自己的環境實測。

寫入 benchmark

1# 單筆寫入:10000 筆,每筆獨立 transaction
2./collector benchmark write --events=10000 --batch=1 --storage=sqlite
3
4# 批次寫入:10000 筆,每 100 筆一個 transaction
5./collector benchmark write --events=10000 --batch=100 --storage=sqlite

輸出:total duration、events/sec、p50/p95/p99 latency per event。

查詢 benchmark

1# 先灌入測試資料
2./collector benchmark seed --events=100000 --storage=sqlite
3
4# 跑查詢 benchmark
5./collector benchmark query --type=error --group-by=name --storage=sqlite
6./collector benchmark query --session-id=random --storage=sqlite

輸出:query duration、rows scanned、rows returned。

Production 觀察指標

部署後用 DevOps dashboard(見 DevOps Dashboard 設計)觀察 collector 自身的效能 metric:

  • collector.storage.write_duration_ms:每次寫入的延遲。P95 超過 100ms 是瓶頸訊號。
  • collector.storage.query_duration_ms:每次查詢的延遲。P95 超過 dashboard 刷新間隔是瓶頸訊號。
  • collector.storage.db_size_bytes:資料庫大小。接近磁碟可用空間的 80% 時觸發 purge 或擴容。
  • collector.storage.wal_size_bytes:WAL 檔案大小。持續 > 50 MB 代表 checkpoint 跟不上寫入速度。

下一步路由