Turso 如何解决 SQLite 的单写者瓶颈:MVCC 重写之路

SQLite 一次只能处理一个写操作,这一架构限制把它挡在高并发场景门外。Turso 用 Rust 重写 SQLite 并引入 MVCC(行级多版本并发控制),实现真正的并发写。本文讲清单写瓶颈成因、BEGIN CONCURRENT 的不足、Turso MVCC 原理与当前限制。

最佳实践
数据库架构主题插画

SQLite 是全球部署量最大的数据库——手机、浏览器、操作系统里到处都是。轻量、零配置、极可靠,但有个根本性架构限制:同一时刻只允许一个写操作。在多核与高并发时代,这个单写者瓶颈把 SQLite 限制在"嵌入式/本地存储"的舒适区。Turso 的做法很激进:用 Rust 从零重写 SQLite,引入 MVCC,把单写限制彻底拿掉。

SQLite 的单写瓶颈是怎么回事

标准 SQLite 的写并发模型是数据库级锁:任何进程执行 INSERT/UPDATE/DELETE 前,要先锁住整个数据库文件,锁释放前其他写者全部排队。模型简单、ACID 有保证,代价是并发度为零。

对桌面应用、移动端本地缓存这不是问题;但对以下场景就是死穴:

  • IoT 数据接入:数千传感器每秒写入,串行化意味着积压甚至丢数据;
  • 高频交易记录:每秒数千笔,等锁延迟不可接受;
  • 网游服务端:数千玩家状态持续更新,单写模型直接卡死游戏体验。

这类需求只能转向 PostgreSQL/MySQL 等客户端-服务器数据库——并发有了,运维复杂度也来了。

官方尝试:BEGIN CONCURRENT 为什么不够

SQLite 官方实验特性 BEGIN CONCURRENT(配合 WAL 模式)把排他写锁推迟到 COMMIT 阶段,让多个事务并行执行——一种乐观锁思路。但它的冲突检测是页级的:两个事务只要改了同一个 4KB 数据页,哪怕改的是完全不同的行,也算冲突,后提交者直接 SQLITE_BUSY_SNAPSHOT 失败。写密集负载下热点页冲突率高,事务失败率难以接受。

为什么 Turso 选择"重写"而不是"贡献"

SQLite 是公有领域代码,但社区政策是"开源不开放贡献"——官方不收外部 PR,以保证代码库极端可靠和血统纯净。这成就了 SQLite 的传奇稳定性,也意味着"换并发模型"这种架构级改动永远无法从社区合入。

Turso 的第一步是创建 libSQL:开放贡献的 SQLite 社区分支,先后做出嵌入式只读副本等主线没有的特性。最终他们更进一步,用 Rust 从零重写整个引擎,目标是兼容 SQLite 的文件格式与生态,同时换掉它的并发心脏。

MVCC:不写锁,写版本

MVCC(多版本并发控制)是 PostgreSQL、Oracle 等高性能数据库的同款机制。核心思想:写操作不原地覆盖数据,而是创建数据的新版本。每个事务看到的是自己开始时刻的快照——写者不阻塞读者,读者不阻塞写者,写者之间也能并行。

Turso 的实现参考了微软 SQL Server 的 Hekaton 内存优化引擎,关键技术是行级版本化。用一张库存表演示:

CREATE TABLE products (name TEXT PRIMARY KEY, quantity INTEGER);

T1 插入 Mug:创建行版本 V1,元数据 (Begin: T1, End: ∞)——T1 创建,无限期有效。

T2 插入 Teapot:动的是不同行,无冲突并行,各自创建 V1。

T3 把 Mug 库存减一:不加锁,而是——

  • 找到 Mug 当前版本 V1,把它的 End 标记为 T3("此版本到此作废");
  • 创建新版本 V2(quantity=99),元数据 (Begin: T3, End: ∞)
Mug V1: (100)  Begin: T1, End: T3    ← 历史版本
Mug V2: (99)   Begin: T3, End: ∞     ← 当前版本

数据库变成一台"时间机器":T3 之后开始的事务看到 V2,而 T3 之前就在跑的长事务仍看到 V1,视图一致性有保证。整个过程没有排他锁。后台的垃圾回收进程会清理不再被任何事务可见的旧版本,回收内存。

性能与当前的限制

基准测试对比:随着写线程增加,标准 SQLite 吞吐持平在约 15 万行/秒(单写者天花板),Turso 4 线程时接近 20 万行/秒且随线程数继续增长。

但 MVCC 目前仍是实验特性,有三个已知短板:

  • 内存占用高:每个新版本存整行完整副本。宽表 + 高频更新会在垃圾回收前堆积大量行副本;未来方向是只存版本间差值(delta);
  • 版本向量竞争:行版本由中心化的"版本向量"管理,注册新版本要拿它的写锁——事务逻辑可以并行,注册这一步是串行的。超多核 + 极高频写入时,这把锁会成为新的竞争点,扩展性不是完美线性;
  • 实验状态:API 和行为仍可能变化,生产关键业务先观望。

怎么看这件事

Turso 的意义不在于"又一个 SQLite 发行版",而在于证明:SQLite 的简洁部署模型(单文件、零配置、可嵌入)和企业级并发控制可以共存。如果 MVCC 成熟,一大批原本被迫上重型数据库的场景——边缘计算、IoT 网关、桌面级高并发应用——都能留在轻量世界里。

观测云对照

无论你的数据层是 SQLite/Turso 还是重型数据库,应用侧的数据库访问表现都值得监控。观测云 APM 可追踪每个请求中的 SQL 调用耗时与慢调用排行,写锁等待、事务失败重试这类并发问题在链路详情里清晰可见;配合监控器对事务错误率告警,评估 Turso 这类新引擎时就有客观数据依据。 1 2

常见问题(FAQ)

Q:Turso 和 SQLite 文件格式兼容吗?
兼容是项目目标之一——重写的是引擎,不是格式,旨在让现有 SQLite 生态(工具链、驱动、ORM)平滑过渡。

Q:现在能把 Turso MVCC 用于生产吗?
不建议用于关键业务。MVCC 尚处实验阶段,内存开销和版本向量竞争都在优化中。可以先在测试环境做负载验证。

Q:libSQL 和 Turso 是什么关系?
libSQL 是 Turso 团队发起的 SQLite 社区分支(保留原版架构做增强);Turso 的引擎则是更进一步的 Rust 重写。两者同属"让 SQLite 走向现代并发"的路线。

Q:MVCC 是不是只有优点?
不是。它用存储和内存换并发:版本副本占用空间、需要垃圾回收、长事务会阻止旧版本清理。写多读少且冲突少的场景收益最大。

参考资料

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台