SQLite 在廉价 VPS 上的性能表现:真实工作负载基准测试
关于何时从 SQLite 迁移到 PostgreSQL 等客户端-服务器数据库的争论通常集中在“规模”上。然而,规模往往被误解为一个二进制阈值,而不是性能权衡的光谱。为了了解 SQLite 究竟在何时达到极限,我们需要超越合成微基准测试,去观察当工作集超过可用系统内存时它的表现如何。
由 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 = 8192和cache_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 | 80 µ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 | 473 µs | 706 µs | 2.2 ms | |
| MIXED OLTP | 3,915/s | 257 µs | 455 µs | 710 µs | 2.2 ms |
“引擎天花板”
当工作集减少到约 246 MB(100 万行)时,数据库可以轻松装入系统缓存中。这揭示了 SQLite 引擎在此特定硬件上的最大潜力,从而消除了磁盘 I/O 对热路径的影响。
- 随机 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 万次操作。由于尾部延迟保持在 3 ms 以下,对于绝大多数 Web 应用来说,SQLite 仍然是一个非常可行的选择。
结论
对于大多数开发者来说,SQLite 的“规模”极限远比通常认为的要宽。虽然从 RAM 移动到磁盘时性能会大幅下降,但其绝对性能底线仍然足以处理廉价硬件上的生产负载。除非你的应用需要对每一次写入都进行严格的 ACID 持久性,或者需要极高的写入并发性,否则 SQLite 通常绰绰有余。