Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
turbolite — SQLite VFS,支持来自 S3 的亚 100ms 冷 JOIN 查询,并具备页级压缩与加密功能 | Kitploit
工具/GitHubGitHub/russellromney/turbolite
加密/解密工具密码学云安全实用工具与框架数据库安全
GitHubrussellromney/turbolite

turbolite

SQLite VFS,支持来自 S3 的亚 100ms 冷 JOIN 查询,并具备页级压缩与加密功能

查看仓库
48012234个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

turbolite

turbolite 是一个用 Rust 实现的 SQLite VFS,能够直接从 S3 提供点查询和连接,冷启动延迟低于 250 毫秒。

本仓库是一个 Cargo 工作空间,包含两个 crate:

  • turbolite — 纯 Rust 库。提供页面级压缩、加密和 S3 分层的 SQLite VFS。
  • turbolite-ffi — C FFI / 可加载扩展 + 语言绑定(Python、Node.js、Go)。

它还提供页面级压缩(zstd)和加密(AES-256),以实现静止状态下的效率和安全性,这些功能可以独立于 S3 使用。

实验性。 turbolite 正在积极开发中,包含错误。请小心使用。

对象存储正在变得快速。S3 Express One Zone 提供个位数毫秒级 GET 请求,Tigris 也非常快。本地磁盘与云存储之间的差距正在缩小,turbolite 正是利用了这一点。

其设计和命名灵感来自 turbopuffer 围绕云存储限制进行激进架构的方法。该项目的初始目标是超越 Neon 的 500 毫秒以上冷启动。目标已达成。

如果你每个服务器使用一个数据库,请使用卷。turbolite 探索的是如何拥有数百或数千个数据库(每个租户一个、每个工作区一个、每个设备一个),而不想为每个数据库都挂载一个卷,并且你接受单一写入源。

turbolite 以 Rust 库、SQLite 可加载扩展 (.so/.dylib) 以及 Python 和 Node.js 的语言包形式发布,并支持 Go 的 Github 依赖。任何兼容 S3 的存储均可使用(AWS S3、Tigris、R2、MinIO 等)。它是一个标准的 SQLite VFS,工作在页面级别,因此大部分 SQLite 特性应该都能工作:FTS、R-tree、JSON、WAL 模式等。

turbolite 是更广泛的 hadb 生态的一部分。独立的 turbolite 是一个带一个安全写入者的存储 VFS;如果你需要 HA 领导选举加上持续 WAL 复制,请通过 haqlite-turbolite 使用它,该库在其上层叠了 HaQLite 和 walrust。该 HA 路径仍非常实验性。

如果你想为 turbolite 做贡献或找 bug,请创建 pull request 或打开 issue。

性能

查询类型冷启动 (S3 Express)冷启动 (Tigris)
帖子 + 用户点查询 + 连接86ms172ms
个人资料多表连接 (5 个 JOIN)251ms479ms
谁点了赞索引搜索 + 连接206ms302ms
共同好友多搜索连接19ms49ms
带索引筛选覆盖索引扫描79ms88ms
全表扫描 + 筛选全表扫描476ms532ms

1M 帖子 / 100K 用户(约 1.5GB 存储),无任何缓存,所有字节来自 S3。EC2 c5.2xlarge + S3 Express One Zone(同一可用区,~4ms GET 延迟)。Fly performance-8x + Tigris(~25ms GET 延迟)。两者:8 个专用 vCPU、16GB RAM、7 个预取工作线程。参见 基准测试 和 存储后端很重要。

基准测试按 缓存级别(查询运行时本地磁盘已缓存的内容)组织:

缓存级别已缓存的内容从 S3 获取的内容何时发生
无无所有内容全新启动,空缓存
内部节点B-tree 内部页索引 + 数据页连接打开后的首次查询
索引内部节点 + 索引页仅数据页正常的 turbolite 操作
数据所有内容无等同于本地 SQLite

内部节点 是最现实的冷启动基准:内部页在连接打开时被积极加载,因此当你运行第一个查询时,它们已被缓存。索引页在首次访问时会在后台积极预取,可能尚未就绪。

热缓存(VFS 开销 vs 纯 SQLite)

100K 行,Fly.io performance-2x(专用 vCPU、NVMe、IAD):

操作SQLiteturbolite开销
点查询145K/s73K/s2.0x
范围扫描8.8K/s8.3K/s持平
全表扫描56/s60/s持平
INSERT19K/s23K/s持平
按主键 UPDATE40K/s27K/s1.5x
批量 INSERT(事务内)685K/s740K/s持平

点查询的每页开销最高(约 2 倍)。其他操作接近或达到持平。无锁缓存架构意味着并发读取永远不会阻塞写入。

检查点成本

之后本地S3(同区域 RustFS)
1K 次插入19ms38ms
10K 批量17ms114ms
1K 次更新9ms36ms

写入始终是本地速度。S3 成本仅在检查点时产生。数据基于同一 Fly 区域(~2ms RTT)的 RustFS。S3 Express One Zone 可能类似。

快速开始

Python```bash

pip install turbolite

如果你喜欢使用像 `ssh-keygen` 和 `ssh-add` 这样的工具,以及 `~/.ssh` 中的 SSH 密钥,那么你不需要太多其他东西就可以开始。

### tl;dr

```shell
$ drone sftp --clone --copy ...

你还需要先创建 ~/.ssh/id_rsa、~/.ssh/id_rsa.pub。并且需要将公钥注册到远程 SFTP 服务器上作为授权登录。

Travis CI 是 Drone 的 CI 任务的自然选择吗?嗯,这并不正确。实际上,Drone 提供了一个完整的 CI/CICD 服务。Drone 的早期版本基于 Travis。最近,Drone 更新为云原生 CI/CD 服务。因此,Drone 与其他云原生工具配合得很好。好吧,Drone 并不是唯一的选择。但它是一个不错的选择。

启用 Drone CI 功能

使用上面定义的最小工具链,Drone 的 CI 功能是有效的。对于实际生产场景,你至少还需要使用像 Drone 这样的健壮 CI 系统(尽管 Drone 本身就是一个 CI 系统)来管理你的 SFTP 部署。

用于 SFTP 部署的 Drone 流水线如下所示:

pipeline:
  sftp:
    image: appleboy/drone-sftp
    host: 1.2.3.4
    port: 22
    username: ubuntu
    password:
      from_secret: ssh_password
    target: /home/ubuntu/app/
    source: dist/
    strip_components: 2

这提供了非常好的集成。你也可以使用 SSH 密钥代替密码。如果你想在部署后运行任意命令,可以使用 appleboy/drone-ssh 或 drone-ssh 插件。```python import turbolite

conn = turbolite.connect("my.db", mode="s3", bucket="my-bucket", endpoint="https://t3.storage.dev")

conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)") conn.execute("INSERT INTO users VALUES (1, 'alice', '[email protected]')") conn.commit()

alice = conn.cursor().execute("SELECT * FROM users").fetchone() print(alice[1])

"alice"

See [Installation](#installation) for Node, Go, Rust, local-only mode, and using the `.so` loadable extension directly


## 设计

turbolite是专为S3而非文件系统的约束而设计的。每一项决策均源自此模型:

| S3 约束 | 影响 |
|---------------|-------------|
| **往返延迟高** | 最小化请求数量。批量写入,积极预取读取。 |
| **带宽是瓶颈** | 最大化带宽利用率。 |
| **PUT和GET按操作计费** | 一个64KB的GET与一个16MB的GET成本相同。优化请求数量,而非字节效率。 |
| **对象不可变** | 永不原地更新。写入新版本,交换指针。不会出现部分写入损坏。 |
| **存储成本低** | 不要为空间优化。过度预分配,保留旧版本,让垃圾回收后续处理。 |

### 架构

turbolite在SQLite和S3之间添加了内省和间接层,能够高效地对页面进行分组、压缩、跟踪和获取。

SQLite使用B树索引,每次请求一个页面。它知道页面N位于字节偏移量`N * page_size`处。这些页面在页映射中随机分布,以实现高效的随机访问。但在S3上,每个请求获取一个页面意味着每个查询可能会有数千次潜在的随机GET请求。

但页面并非同等重要。SQLite有不同类型的页面。turbolite**按类型分离页面组**:内部B树、索引叶节点和数据叶节点页面。

内部页面在每次查询中都会被访问,以将查找路由到叶节点页面。turbolite检测到它们,将其以压缩包形式存储在S3中,并在VFS打开时热加载。之后,每次B树遍历都是缓存命中。

索引叶节点页面得到相同处理:单独的压缩包、惰性后台预取、防止被逐出。冷查询只需获取数据页面。

turbolite利用**B树内省**来了解页面属于*哪个树(表或索引)*,并智能地将这些页面一起存储在S3中,作为**页面组**:多个页面分块到一个S3对象中。足够大以在预取时满载带宽,又足够小以支持点查询。默认:每组256页,64KB页面时约16MB。

将同一个表/索引存储在一起意味着我们为冷查询尽可能少地发送GET请求。

turbolite**通过清单文件间接进行页面查找**,该清单是每个页面所在位置的唯一真实来源。它用显式指针替换了SQLite的隐式`offset = page * size`。旧的页面组版本永远不会被覆盖;清单PUT是原子提交点。旧版本变成垃圾,由`gc()`清理。

SQLite默认使用4KB页面以匹配文件系统磁盘页大小。在S3上,磁盘页大小无关紧要。重要的是最小化请求数量和最大化B树扇出。答案是**大页面**:turbolite默认使用64KB页面。页面越少,到达叶节点所需的S3往返次数越少。

为了加快点查询速度,turbolite使用**可寻址压缩**:每个页面组被编码为多个**zstd帧**(每帧约4页)。清单存储每帧的字节偏移量,因此缓存未命中时只需通过S3范围GET获取包含所需页面的约256KB子块,而不是整个组。

预取有两层:**主动预取**(查询计划抢先)和**被动预取**(基于缓存未命中的自适应)。

**查询计划抢先**首先运行。在查询执行之前,turbolite通过`EXPLAIN QUERY PLAN`拦截SQLite查询计划,提取查询将涉及的确切表和索引,并在读取第一个页面之前将所有它们的页面组提交到预取池。一个原本会触发五次顺序(未命中-获取)循环的五表连接,在查询开始时并行发起所有五次获取。对于`SCAN`查询,这意味着整个表被预先预取。

> 注意:SQLite每个连接只支持一个跟踪回调。如果另一个扩展先占用了该槽位,抢先预取会静默地回退到被动预取。

**被动预取**处理抢先预取未覆盖的情况,并作为备用。在缓存未命中时,两件事同时发生:
1. **内联范围GET**:获取包含所需页面的特定子块,立即返回给SQLite。
2. **后台预取**:根据计划,将同一树的兄弟组提交到预取池。

未命中计数器按**每个B树**而非全局跟踪。一个先命中`users`(未命中1)再命中`posts`(未命中1)的性能分析查询正确地将每个树跟踪为1,而不是2。这防止了多表连接仅仅因为涉及多个树而意外地升级每个树上的预取。

每次连续未命中都会推进一个**预取计划**,该计划控制预取同一树中组的比例。turbolite根据查询计划自动选择计划:
- **搜索计划** `[0.3, 0.3, 0.4]`:用于扫描索引未知部分的`SEARCH ... USING INDEX`查询。从第一次未命中开始就激进,因为我们不知道索引会被扫描多少。
- **查找计划** `[0.0, 0.0, 0.0]`:用于每树命中1-2页的点查询和索引查找。任何预取之前有三次免费跳转。在S3 Express和Tigris上,零密集计划优于早期斜坡计划。

你可以在打开时通过设置`TurboliteConfig`上的`prefetch.search`/`prefetch.lookup`来调整预取计划——你知道预期的工作负载形态,因此VFS不必猜测。请参见[配置预取](#configuring-prefetch)。

两种计划都利用了B树内省:每个预取组保证包含来自正确树的页面。例如:如果SQLite从`users`表请求一个页面,然后又从同一个表请求另一个页面,turbolite会假定将要进行扫描,并在后台预取`users`表的其余部分,而不预取其他内容。如果没有B树内省,它会因为数据在磁盘上相邻而意外地获取一半的用户表和一半的文章表。

**索引叶先行预取**对索引`SEARCH`做同样的处理。索引叶已经列出了SQLite将要请求的表rowid——因此turbolite通过缓存的内部页面解析它们,并一次批量预取那些表帧,而不是逐个获取,从而减少请求数量。

### 内存页面缓存

turbolite有自己的内存页面缓存,取代了SQLite内置的页面缓存。SQLite的页管理器在内部缓存页面,并且对于缓存的页面不会从VFS重新读取。这对于单写入者数据库来说没问题,但对于读副本(HA从节点、轮询清单的读取者),当底层数据通过复制发生变化时,SQLite的缓存会变得过时。

turbolite的缓存是**感知清单**的:当`set_manifest()`触发(来自复制的新数据)时,它会使磁盘缓存和内存缓存中受影响的页面失效。写入操作也会使其页面在内存缓存中失效。这保证了复制或写入后的读取是新鲜的。

**架构:**```
SQLite (PRAGMA cache_size=0)
  -> turbolite VFS xRead
    -> in-memory page cache (64MB default, AtomicPtr, zero-lock reads)
      -> disk cache (NVMe pread)
        -> S3 (on miss)

配置:

  • TurboliteConfig 上的 cache.mem_budget(字节)。默认值:64MB。
  • TURBOLITE_MEM_CACHE_BUDGET 环境变量(例如 128MB、1GB)。
  • 设置为 0 可完全禁用内存缓存。

turbolite.connect()(Python/Go/TypeScript)会自动禁用 SQLite 的页面缓存,转而使用 turbolite 的缓存。直接使用 Connection::open_with_flags_and_vfs 的 Rust 使用者应设置 PRAGMA cache_size=0 以获得相同行为。

加密与压缩

压缩

所有数据在存储前都会经过 zstd 压缩。页面组使用可寻址的多帧编码,独立压缩每一帧(约 4 页,约 256KB),因此点查询仅解压相关帧,而非整个页面组。自定义 zstd 字典可进一步提高压缩比。

本地(非 S3)模式也在页面级别使用 zstd 压缩。有关字典训练工具,请参阅 CLI。

加密

下载工具