我喜欢 Rust,也喜欢 SQLite,所以你可以想象,当我得知"SQLite 正在用 Rust 重写"时,我有多么兴奋: Turso 。
SQLite 可能是世界上部署最广泛的数据库,你的任何设备上都有数十个数据库,它也可能是最可靠的软件之一,其测试数量是代码数量的 590 倍(我知道测试也是代码,这只是为了简化):约 92,053,100 行测试代码 vs 约 155,800 行代码。
此外,几乎所有编程语言都有 SQLite 绑定,所以为什么有人会想用 Rust 重写它呢?
SQLite到底是什么?
提到 SQLite,大多数人首先想到的是 C 库、它的可靠性、传奇般的测试覆盖率以及易于嵌入的特性。
但是,SQLite 也可以被视为一种单文件数据库格式的规范,而这正是有趣之处。SQLite 数据库本质上是一个高度优化的 B+ 树集合,存储在磁盘(或内存)上,并包含模式和一些元数据。
如果我们有其他能够理解这种文件格式的数据库引擎呢?Turso 正是如此:它是一款全新的数据库引擎,(大部分情况下,除了 MVCC 模式等极少数例外)与 SQLite 数据库文件格式兼容,但在架构层面上却完全不同。
用户体验也相同,至少在 Rust 中是这样,以下是一个 Hello World 示例:
use turso::{Builder, EncryptionOpts};
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let db = Builder::new_local("test.db").build().await?;
let conn = db.connect()?;
let rows = conn.query("SELECT * FROM users", ()).await?;
return Ok(());
}
SQLite 很棒,但存在很多问题
诚然,SQLite 堪称一件艺术品,但它也存在许多问题,会给毫无防备的开发者带来麻烦。
首先,SQLite 测试套件不是开源的,因此想要修改它的人无法像原开发者那样安心地进行修改。
其次,SQLite 的开发者并不真正接受外部贡献。你可以报告 bug(他们会尽快修复)和提出功能请求,但这可能不足以满足你的需求。
最后,SQLite 是用 C 语言编写的,这使得它容易出现一些很容易避免的错误,这一点可以从变更日志中看出。此外,由于 C 语言糟糕的类型系统和不安全的内存管理,也使得维护和添加新功能变得非常困难。
除此之外,SQLite 还不支持(官方的)并发写入,SQLite 的列默认是弱类型的,这与数据库的预期不符,而且模式更改可能会很麻烦,因为某些操作需要您自己复制整个表。
其中大部分问题都可以通过用 Rust 重写来解决。
在《为什么 SQLite 是用 C 语言编写的》一文中,SQLite 的作者暗示 Rust 是重写 SQLite 的最佳选择,但 Rust 目前还不能满足所有要求,因为 SQLite 部署在非常特殊的地方,而 Rust 代码目前还无法部署到这些地方。
我从创新者的困境角度来看待这种情况:现有企业不愿意牺牲一部分市场份额进行变革,所以我们需要新的竞争者来创新。
Turso 不断创新:甚至在达到 v1.0 版本之前,他们就已经解决了开发者在使用 SQLite 时遇到的绝大多数长期痛点,这些痛点已在《优化 SQLite 以适应服务器》一文中有所介绍:
- 内置加密,这在 2020 年及以后已成为基本配置。
- MVCC 和并发写入支持
- 使用 io_uring 进行异步 I/O
这还没提到 Rust 提供的所有其他好处,例如借用检查器、内存安全以及具有清晰抽象的高级代码,这些都使得无所畏惧的重构成为可能。
一个可扩展到多台机器的进程内数据库
Turso 最容易被误解的特性之一是,它被设计成既可以用作进程内数据库,也可以像 PostgreSQL 一样用作网络数据库,因此其背后的公司可以销售云托管解决方案。

作为一名开发者和创业者,这正是我梦寐以求的数据库:我的十个项目中,有九个只需要一台虚拟机,因此 SQLite/Turso 的进程内模型非常适合它们。但是,对于那些获得用户增长并需要扩展的项目(正如我之前提到的),SQLite 就不太合适了,因为它不支持并发写入。而且,在项目扩展过程中,将应用程序从 SQLite 移植到 Postgres 会浪费你宝贵的时间。
这就是为什么大多数项目一开始就直接使用 PostgreSQL,"以防万一",但这会增加开发和运维过程中的摩擦,尤其是在需要管理扩展、升级数据库版本或管理备份时。
我们迫切需要一个能够从进程内扩展到网络化的数据库,但很少有人知道他们需要的是汽车/火车而不是更快的马。
在智能体时代,智能体在自己的沙箱中工作,你不希望因为每次会话都需要启动一个新数据库而增加额外的开销,这一点尤其如此。此外,对于那些既需要用于本地/嵌入式应用程序的嵌入式数据库,又需要用于后端的数据库的项目来说,这一点也同样适用。
扩展
SQLite 最棒的特性之一就是构建和加载自定义扩展非常容易。与 PostgreSQL 等网络数据库不同,后者通常由云服务提供商管理,用户只能使用有限的扩展,而 SQLite 扩展只是动态库,可以直接添加到容器中。您可以阅读我之前的文章《用 Rust 构建 SQLite 扩展》 ,了解如何用 Rust 构建快速安全的 SQLite 扩展。
Turso 已经支持扩展,并提供了一个 SDK 来用 Rust 编写扩展。
以下是来自https://github.com/tursodatabase/turso/blob/main/extensions/crypto/src/lib.rs的一小段代码,向您展示为 Turso 构建扩展是多么容易。
#[scalar(name = "crypto_sha256", alias = "crypto_sha256")]
fn crypto_sha256(args: &[Value]) -> Value {
if args.len() != 1 {
return Value::error(ResultCode::Error);
}
let Ok(hash) = sha256(&args[0]) else {
return Value::error(ResultCode::Error);
};
Value::from_blob(hash)
}
结语
Turso 正是我期待已久的数据库!虽然我不认识他们,但团队看起来很强大,所以我祝他们好运,并(不)耐心地等待 v1.0 版本。
使用DuckDB处理分析数据和时间序列数据,使用 Turso 处理交易数据,我觉得我们终于回归了理智,此前多年来,分布式系统热潮导致所有数据(不足 100GB)都需要集群处理。
对他们来说,时机非常好,因为嵌入式数据库非常适合人工智能代理,所以我希望他们能够及时取得成功,并靠自身盈利,这样他们就不需要出售公司和/或将项目商业化,这对于风险投资支持的公司来说通常是一个风险。