想象一下:100万行数据,1.5GB体积,零缓存,完全冷启动。从按下回车到看到结果,你甚至数不到三个数。

这不是本地SSD的功劳。这是从AWS S3——那个传统认知里"慢吞吞"的对象存储——里硬拉出来的速度。

image

Russell Romney搞的Turbolite,干了一件听起来像骗人的事:让SQLite这个"本地嵌入式数据库之王",直接从S3里做JOIN查询,延迟压到250毫秒以内。

水和油怎么搅在一起?

老实讲,SQLite和S3天生八字不合。

一个是你的手机App里藏着的小文件,毫秒级响应,零延迟;一个是远程的对象存储,动辄几十毫秒RTT,按请求计费。传统经验告诉我们不太行

image

但Turbolite偏偏要问:如果泥地不是泥地,而是另一种赛道呢?

重写规则,而非适配硬件

大部分人做SQLite-over-S3,思路是"怎么让S3看起来像硬盘"。Turbolite反着来:既然S3是API而非文件系统,那就为API重新设计数据库。

这里有几个反直觉的骚操作。

页面要够大。 SQLite默认4KB页面是为了匹配机械硬盘的扇区。但在S3上,"磁盘页大小"这个概念毫无意义。Turbolite直接上64KB大页,减少 round trip 次数。

不要省空间。 S3存储便宜到近乎免费,请求费才是杀手。Turbolite的策略是:宁可多存几个版本,也不做原地更新。对象不可变?正好, manifest 文件原子切换,垃圾回收延后处理。

聪明地"作弊"。 传统预取是盲目的,Turbolite玩的是查询计划预判——在SQLite执行前拦截 EXPLAIN QUERY PLAN,提前知道你要查哪几张表,先把数据从S3拉下来。一个五表JOIN,本来要五次"请求-等待",现在变成一次并行发射。

B树感知的降维打击

最有意思的是Turbolite对B树的"偷窥"。

image

SQLite内部用B树组织数据,但页号是随机分布的。Turbolite利用B树内省(B-tree introspection),把同一棵树的页面物理上捆在一起塞进S3。内部页、索引叶、数据叶分门别类打包。

这意味着什么? 当你查用户表时,系统不会傻乎乎地把隔壁帖子表的数据也拖下来。冷查询只需要拉取数据页,内部路由页早就通过"积极预取"躺在内存里了。

更夸张的是那个实验性的语义预测功能。如果你总是先查用户再查帖子,Turbolite会记住这个模式(用trie结构存着),下次你刚点开用户资料,帖子数据已经在后台排队了。

不是扩展,是范式转移

读到作者自己的评论,我才意识到这项目的真正野心。

" motivating question for me was less 'can SQLite read over the network?' and more 'what assumptions break once the storage layer is object storage instead of a filesystem?' "

翻译过来:这不是给SQLite装个网卡,而是问"如果存储层本质是对象存储,数据库的哪些前提假设会崩塌"。

布局(layout)被重构了。延迟模型被重构了。甚至一致性模型也变成了"单写者多读者"的快照隔离。

这有点像当年从机械硬盘到SSD的转变——不只是变快了,而是随机访问和顺序访问的代价关系被颠覆,整个数据库架构都要跟着变。

但评论区有人灵魂发问:S3按请求收费,这么频繁地GET,跑正常负载一小时得多少钱?MySQL可是免费的。

说实话,这是个好问题。Turbolite在EC2上用S3 Express One Zone(同可用区,~4ms延迟)做基准测试,但生产环境的成本账还没人算清楚。也许对于读多写少、数据量巨大但访问模式可预测的场景,这种架构才划算。

"冷数据"不再冰冷

Turbolite的出现,模糊了一条古老的界限:本地数据库和远程存储的边界。

以前我们默认,热数据放SSD,冷数据扔S3,中间隔着一条"加载时间"的鸿沟。现在有人告诉你,从S3冷启动查100万行只要250毫秒——冷数据几乎变成了温数据。

这会改变我们设计架构的方式吗?当SQLite能直读S3,当边缘计算节点能秒开TB级数据库,PostgreSQL的统治地位还会那么稳固吗?

或许不久的将来,"数据库在本地还是云端"这个问题,会变得像"文件在内存还是硬盘"一样无关紧要。

【kimi-k2.5锐评】:把SQLite嫁接到S3上还能保持亚秒级延迟,这不是简单的性能优化,而是对"数据库必须靠近存储"这一铁律的优雅反叛,尽管账单可能会教会我们什么叫昂贵的浪漫。

参考链接:
https://github.com/russellromney/turbolite