Hotdry.

Article

用 FUSE 虚拟文件系统将 SQLite WAL 页流式实时备份到 S3:零停机、秒级 RPO

基于 Litestream VFS 的 LTX 格式与 S3 Range-Get,实现秒级 RPO、秒级 RTO 的 SQLite 热备份方案,无需修改应用代码。

2025-12-12systems-engineering

SQLite 的备份故事一向简单:复制文件、定时快照,或者借助 WAL 模式下的 .backup。当数据库膨胀到数十 GB、且业务要求 “零停机、秒级 RPO” 时,传统脚本就显得力不从心。Litestream 在 2025 年发布的 VFS 插件给出了一条新路径 —— 把备份数据当成 “远程只读副本”,通过 FUSE 虚拟文件系统直接挂载到本地,让 SQLite 在查询时按需拉回最新页面,而写入端仍以秒级频率把 WAL frame 流式推送到 S3。结果是:不中断业务、不占用本地全量空间,却能在一行 SQL 内回到任意秒级快照。

1. 从 “文件级拷贝” 到 “页级流式复制”

传统备份的粒度是 “整个文件”,而 Litestream VFS 把粒度拆成 “页面”。

  • 写入侧:Litestream 进程监听 -wal 文件,每凑满一批帧就封装成 LTX(LiteStream Transaction)对象上传。默认 L0 层 1 s 刷盘,L1 层 30 s 合并,L2 层 1 h 再合并,每日一次完整快照。
  • 读取侧:VFS 插件拦截 SQLite 的 xRead(),把 “页号 + 页大小” 映射成 “对象键 + 偏移”,用 S3 Range-Get 拉取 4 KiB 页面,LRU 缓存热页,索引仅 1 % 对象体积,首次查询即可在秒级完成。

由于 LTX 文件内部已做 compaction,同一页面的旧版本会被丢弃,因此 S3 上实际存储量 ≈ 数据库体积 + 7 天内增量,网络流量与费用可控。

2. 架构拆解:LTX 格式与反向索引

LTX 文件由 Header、Page Data、Trailer 三段组成:

字段 长度 含义
page_size 2 B SQLite 页面大小,默认 4096
page_count 4 B 本文件包含的页面数
max_txid 8 B 最大事务 ID,用于一致性判断
page_offset[] page_count × 4 B 每页在文件内的偏移数组,构成 “小索引”
checksum 8 B Trailer 校验和

VFS 在启动时只拉取所有 LTX 的 Trailer(约 1 % 大小),即可在内存拼出一张 <page_no → (file_key, offset, version)> 的反向表;后续查询直接按 page_no 命中对应 Range,省去整文件下载。

3. 秒级 RPO 落地:配置与参数

以下 litestream.yml 可直接用于生产,RPO ≤ 1 s,RTO ≤ 10 s(首次查询需预热索引):

dbs:
  - path: /var/lib/app/prod.db
    replicas:
      - type: s3
        bucket: myapp-litestream
        path: prod/
        region: us-east-1
        retention: 720h          # 30 天
        sync-interval: 1s        # L0 层 1 秒刷盘
        checkpoint-interval: 30s # L1 层合并
        compression: gzip        # 页面级压缩

客户端加载 VFS:

$ sqlite3
sqlite> .load /usr/local/lib/litestream.so
sqlite> .open "file:///var/lib/app/prod.db?vfs=litestream"

关键可调参数:

参数 默认值 说明
litestream_vfs_page_cache_size 4096 页缓存数,16 MiB 内存
litestream_vfs_index_prefetch 8 并行拉取 Trailer 的线程数
litestream_vfs_range_size 262144 Range-Get 字节数,建议 256 KiB

监控点:

  • litestream_replication_lag_seconds > 5 触发告警;
  • S3 RangeLatency P99 > 200 ms 需考虑就近接入点或 CDN 边缘缓存。

4. 场景、成本与限制

适用场景

  • 读多写少、分析查询占主导,例如报表、日志检索、配置中心;
  • 边缘节点需要 “离线副本”,但本地磁盘不足;
  • 开发调试阶段,快速拉取生产快照而无需全量 restore。

成本估算 以 50 GB 库、日新增 1 GB、查询热点 5 % 为例:

  • 存储:50 GB × 2(多版本)× 0.023 USD/GB = 2.3 USD / 月;
  • 请求:5 % 页面 × 1 k 查询 / 天 × 30 天 ≈ 15 k Range-Get,0.0004 USD / 千次 ≈ 0.06 USD / 月;
  • 出流量:热点 2.5 GB × 0.09 USD/GB = 0.23 USD / 月; 总计约 2.6 USD / 月,远低于同规格 RDS 只读实例。

限制与权衡

  • 只读:写入仍需回源主库;若需双写,需引入 LiteFS 或 rqlite;
  • 冷查询放大:随机扫描全表时,Range 请求可能暴涨,需配合索引或分区;
  • 网络隔离:边缘节点离线时,首次查询会失败,可提前本地缓存一份最新快照作为兜底。

5. 结论:嵌入式数据库的云级备份最短路径

Litestream VFS 把 “备份” 从运维脚本升级为 “可挂载的远程副本”,让 SQLite 在保持嵌入式零运维优势的同时,获得云级存储的持久性与弹性。只需加载插件、改一行连接串,就能在本地命令行里查询云端任意秒级快照 ——RPO 秒级、RTO 秒级、零停机、零改造。对于读密集型业务,这是一条成本最低、复杂度可控、且可立即落地的流式备份方案。


资料来源
[1] Fly.io Blog: Litestream VFS — Hot SQLite queries off S3, 2025-07
[2] Litestream 官方文档:LTX 文件格式与 VFS 插件实现,2025-11

systems-engineering