已经迁移到了 PostgreSQL,你可以让 ai 帮你迁移,很快很方便

deepseek v4 pro 分析结果,ai 含量 100%
komari 源码中 SQLite 的局限
1、单连接写入
opts = append(opts,
metric.WithMaxOpenConns(1),
metric.WithMaxIdleConns(1),
metric.WithSQLiteReadPool(4),
)
所有写入——包括多个 agent 同时上报、compaction、数据清理——都必须排队经过这一个连接。
2、聚合查询回退
func sqlAggValueExpr(driver Driver, agg Aggregation) (string, bool) {
switch agg {
case AggStdDev:
switch driver {
case DriverMySQL, DriverPostgreSQL:
return "STDDEV_POP(value)", true
default:
return "", false
}
default:
if frac, ok := percentileFractionString(agg); ok {
if driver == DriverPostgreSQL {
return fmt.Sprintf("percentile_cont(%s) WITHIN GROUP (ORDER BY value)", frac), true
}
return "", false
}
}
}
- SQLite:必须把所有原始数据点从磁盘读到内存,在 Go 中完成计算
- PostgreSQL:只需一个 SQL 查询,数据库引擎原生完成计算,只返回最终结果
对于保留 90 天、每分钟一个采样点的场景,单个指标就有 ~130,000 行。如果有 10 个 agent、20 个指标,那就是 2600 万行。SQLite 做一次 P95 查询可能要拉几十万行数据到内存,而 PostgreSQL 只返回一个数字。
3、写入锁竞争
sqlDB.SetMaxOpenConns(1)
多个 agent 同时上报数据时,SQLite 下它们只能串行写入。busy_timeout=5000(5秒) 是一个缓冲区,但高频写入下仍可能触发 SQLITE_BUSY。
4、Compaction 阻塞写入
func (sqliteDialect) compactTxOptions() *sql.TxOptions { return nil }
SQLite compaction 事务使用默认隔离级别,由于只有单连接,compaction 期间所有 metric 写入都被阻塞。
而 PostgreSQL 用 SERIALIZABLE 隔离级别 + 重试机制:
func (postgresDialect) compactTxOptions() *sql.TxOptions {
return &sql.TxOptions{Isolation: sql.LevelSerializable}
}
写入不会被阻塞,只在真正冲突时才触发重试。
SQLite 的优化措施(源码中做了什么来缓解)
Komari 对 SQLite 做了大量优化,说明开发者清楚其局限:
优化 |
源码位置 |
效果 |
|---|
WAL 模式 |
dbcore.go:407-408 |
读写并发(读不阻塞写) |
独立读连接池 (4个) |
metricstore.go:144 |
SELECT 走读池,减轻主连接压力 |
64MB 页缓存 |
dbcore.go:413 |
cache_size=-65536 |
256MB mmap |
config.go:168 |
大文件读取性能 |
_txlock=immediate |
dbcore.go:271 |
事务开始即获取写锁,避免锁升级死锁 |
busy_timeout=5000 |
dbcore.go:271 |
写锁等待最多 5 秒 |
temp_store=MEMORY |
dbcore.go:414 |
临时表放内存 |
synchronous=NORMAL |
dbcore.go:412 |
性能优先于持久性 |
这些优化让 SQLite 在中小规模下表现可接受,但不能改变其单写者架构本质。
PostgreSQL 在 Metric 场景下的具体优势
能力 |
SQLite |
PostgreSQL |
|---|
并发写入 |
1 个连接串行 |
25 个连接并发 |
STDDEV 查询 |
内存计算(拉全量) |
SQL 下推 |
P50/P95/P99 查询 |
内存计算(拉全量) |
SQL 下推 |
Compaction 与写入并发 |
互相阻塞 |
不阻塞(SERIALIZABLE) |
JSON 字段类型 |
TEXT |
JSONB(原生索引) |
空间回收 |
VACUUM |
VACUUM FULL |
连接池 |
无(单连接) |
完整连接池 |
部署复杂度 |
零依赖 |
需要额外服务 |
PostgreSQL 显著优于 SQLite 的核心原因:
聚合查询性能可能差 10-100 倍:当查询涉及百分位或标准差时,SQLite 必须把所有原始点拉到应用层内存计算,而 PostgreSQL 只需要一个 SQL 查询。这是源码中最明确的性能分水岭 (dialect.go:399-444)。
高并发写入不会互相阻塞:SQLite 的 MaxOpenConns=1 在 agent 数量增长时会成为瓶颈。
Compaction 不阻塞写入:SQLite 的 compaction 事务(清理过期数据+构建 rollup)会占用唯一的写连接,期间新数据无法写入。
一句话总结:对于小规模部署,Komari 对 SQLite 的优化已经足够好;但当 agent 数量和查询复杂度增长时,PostgreSQL 的 SQL 聚合下推能力(尤其是百分位查询)和真正的并发写入支持,使其在 metric 场景下确实比 SQLite 好很多——这个差异是架构性的,不是微调参数能弥补的