SQLite 凭什么重新进入后端视野
SQLite 长期背负着一个标签:适合原型开发、移动端、嵌入式,但不适合生产级服务端。这个判断曾经相当准确,但现在值得重新审视。
Cloudflare D1、Turso、Litestream、fly.io 的 LiteFS——这些出现在过去两三年的项目,都在围绕 SQLite 构建可以认真交付的后端服务。它们不是在”克服”SQLite 的缺陷,而是在重新定义适用范围。
问题不是 SQLite 变了,而是我们对”后端数据库应该长什么样”的预设正在松动。
SQLite 的架构为什么不同
大多数数据库是 client-server 架构:数据库以独立进程运行,客户端通过网络协议连接。这个模型解决了一个核心问题:多个客户端并发访问同一份数据。
SQLite 不走这条路。它是一个嵌入式数据库,以库的形式链接进应用程序,直接读写本地文件。整个数据库就是磁盘上的一个文件。
这个设计带来了一些在常规数据库里不存在的特性:
- 无网络往返:查询不经过 socket,直接是函数调用,延迟在微秒量级
- 无独立进程:没有守护进程、没有连接池、没有认证管理,部署复杂度接近于零
- 原子持久化:整个数据库是单个文件,备份就是
cp,迁移就是mv
这不是”功能残缺的数据库”,而是不同的架构选择。它适合的场景,和 PostgreSQL 适合的场景,本来就不完全重叠。
WAL 模式:改变了什么
SQLite 的早期并发模型极其保守:写操作会对整个数据库文件加锁,此时任何读操作都会被阻塞。这在 Web 服务场景下几乎是不可用的。
3.7.0 版本(2010 年)引入了 WAL(Write-Ahead Logging)模式,这件事在今天被低估了。
WAL 的核心机制是写操作不直接修改主数据库文件,而是追加写入一个独立的 WAL 文件。读操作同时检查主文件和 WAL 文件,获取最新状态。
结果是:
- 读写不互斥:读操作读主文件,写操作写 WAL,两者可以并行
- 写操作顺序化:同一时刻只有一个写操作,但这在大多数中低并发场景里是可以接受的
- 检查点机制:WAL 文件定期合并回主文件,保证主文件不会无限增长
WAL 模式把 SQLite 的并发能力从”单用户”推到了”多读单写”。对于读多写少的场景,这已经够用。
实际的限制在哪里
不回避这个问题。
写并发是真正的瓶颈。WAL 模式下写操作仍然是串行的,如果你的应用写入非常频繁(比如每秒数千次写),SQLite 会成为瓶颈。它的峰值写入吞吐量大概在几千次/秒,PostgreSQL 调优后可以轻松超过这个数字一个量级。
跨进程访问不可靠。SQLite 依赖文件系统锁,在网络文件系统(NFS、EFS)上文件锁的行为不可预测,是已知的数据损坏风险。多进程同时写同一个 SQLite 文件是危险的,这个限制不会消失。
没有内置复制。SQLite 本身没有主从复制、没有 binlog、没有 CDC(Change Data Capture)机制。高可用需要在上层另外解决。
这三条限制,在传统的单机多核 Web 服务架构下,是致命的。但放到特定场景下,它们不一定是问题。
工具层是怎么补的
真正让 SQLite 进入生产视野的,不只是 SQLite 本身的改进,而是围绕它出现的一批工具。
Litestream:流式复制工具。它以 sidecar 形式运行,实时监听 WAL 文件变化,将变更复制到对象存储(S3、GCS、R2)。这解决了灾备和主从切换的问题——不是实时主从,而是”随时可以从对象存储恢复到秒级前的状态”。对很多场景,这已经足够。
Turso(libSQL):fork 自 SQLite 的嵌入式数据库,扩展了 HTTP 访问协议和复制能力,支持将数据库”嵌入到边缘节点”。它的核心思路是:与其在一个中心化的数据库前面加一个全球 CDN,不如把数据库实例本身分布到靠近用户的地方。
Cloudflare D1:基于 SQLite 构建的边缘数据库服务。每个 D1 数据库实际上是运行在 Cloudflare 全球节点上的 SQLite 实例,通过 Workers 的 bindings 直接调用,没有网络往返。它不适合高写入吞吐,但对于读多写少的边缘 API,延迟表现极好。
LiteFS(fly.io):基于 FUSE 实现的分布式文件系统,将 SQLite 的 WAL 变化复制到集群内其他节点。读写分离通过 DNS 路由实现——写请求路由到主节点,读请求可以在任意节点完成。
这几个项目的共同逻辑是:SQLite 文件 + 复制机制 + 就近访问,不是试图把 SQLite 变成 PostgreSQL,而是利用它的嵌入式特性做差异化。
什么场景真正合适
给一个判断框架:
合适:读多写少;数据规模在 GB 量级(TB 理论可行但少有实践);单租户或按租户隔离(每个租户一个 SQLite 文件,这个模式非常干净);边缘节点、Serverless 函数;需要极低部署复杂度的小型服务;离线优先的客户端应用。
不合适:高并发写入;需要实时跨节点强一致读;数据库本身作为多服务共享的中心状态;需要复杂权限管理和行级安全的多租户系统。
“每个租户一个 SQLite 文件”这个模式值得单独强调。它把并发问题从”多用户同时写同一个库”变成了”多用户各自写自己的库”,彻底绕开了写串行的瓶颈。Notion 早期的存储设计就有类似思路的影子。
一个更根本的问题
SQLite 的复兴,背后有一个更值得想的问题:我们对数据库”生产就绪”的判断标准,是否被 client-server 架构的先验假设所污染了?
“数据库要支持多进程并发访问”——这个需求是真实的,但它的来源是特定的部署模型,不是所有应用都有这个需求。
“数据库要有独立进程,才能独立扩缩容”——这个逻辑在微服务架构下成立,但 Serverless 和边缘计算正在改变扩缩容的粒度,数据库和计算绑定在一起反而可能是更好的选择。
技术选型里有一种常见的错误:把”我们过去是怎么做的”误认为是”这件事本来应该怎么做”。SQLite 在后端场景的重新出现,是个提醒:值得定期回头审视那些被当成公理的工程假设。