起因
我们的小型生产服务用 SQLite(部署简单 + 性能够 + 单文件备份)。
但默认备份方案最多每天 cron sqlite3 .backup + scp 异地。两次备份之间
有 24 小时 RPO(最坏丢一天数据)。
litestream 是开源工具,把 SQLite 的 WAL 日志实时增量复制到 S3 兼容
存储。RPO 降到秒级,无需改 application 代码。
解决方案
装
# 二进制安装
LITESTREAM_VERSION=0.3.13
curl -fsSL https://github.com/benbjohnson/litestream/releases/download/v${LITESTREAM_VERSION}/litestream-v${LITESTREAM_VERSION}-linux-amd64.tar.gz \
| sudo tar xz -C /usr/local/bin litestream
litestream version
或 Docker:docker run litestream/litestream。
配置
/etc/litestream.yml:
dbs:
- path: /srv/knowledge/db.sqlite3
replicas:
- type: s3
bucket: my-backups
path: knowledge
endpoint: https://s3.us-east-005.backblazeb2.com
region: us-east-005
access-key-id: ${B2_KEY_ID}
secret-access-key: ${B2_APP_KEY}
retention: 720h # 保留 30 天
snapshot-interval: 24h # 每天全量 snapshot
litestream 工作原理:
- application 写
db.sqlite3→ SQLite 写 WAL - litestream 后台读 WAL 增量帧
- 每个 WAL 帧立刻上传到 S3(默认 10s 内)
- 定期(默认 24h)做一次全量 snapshot
- retention 期外的 snapshot + WAL 自动清理
systemd service
# /etc/systemd/system/litestream.service
[Unit]
Description=Litestream
Requires=network.target
After=network.target
[Service]
User=trio
Group=trio
EnvironmentFile=/etc/litestream.env
ExecStart=/usr/local/bin/litestream replicate -config /etc/litestream.yml
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
/etc/litestream.env:
B2_KEY_ID=00abc...
B2_APP_KEY=K00...
sudo systemctl enable --now litestream
journalctl -u litestream -f
# 看到 "replicating wal frames..."
验证副本
litestream snapshots /srv/knowledge/db.sqlite3
# replica generation index size created
# s3 abc123 5 12345678 2026-05-24T03:30:00Z
litestream wal /srv/knowledge/db.sqlite3 | head
# replica generation index offset size
灾难还原
服务器全没了,新机器恢复:
# 装 litestream + 复制 /etc/litestream.yml + .env 到新机器
litestream restore -o /srv/knowledge/db.sqlite3 \
s3://my-backups/knowledge
# 从最新 snapshot + 重放 WAL 到最新状态
# 几秒-几分钟(取决数据量)
# 启动 application
sudo systemctl start knowledge
时间点恢复:
litestream restore -timestamp 2026-05-20T10:00:00Z \
-o /tmp/db-at-may-20.sqlite3 \
s3://my-backups/knowledge
恢复到任意 30 天内的时间点。
效果
- RPO 从 24h → 10s
- 灾难还原 = 一行
litestream restore - B2 存储费用:30 天保留 ~2 GB DB 约 $0.10/月
- application 零改动:litestream 在后台独立进程跑
与其它方案对比
cron .backup + scp |
litestream | PG streaming replica | |
|---|---|---|---|
| RPO | 24h | ~10s | ~ms |
| 单机部署 | ✅ | ✅ | 需主备 |
| 时间点恢复 | ❌ | ✅ | ✅ |
| 同步开销 | 0(备份时刻才有) | 极低(WAL 增量) | 中(流复制) |
| 成本 | 几乎 0 | 存储费 + 几乎免费 | 备机 + 网络 |
SQLite + litestream 在中小规模生产是性价比最高方案之一。
与之前装的 daily backup 共存
之前章节装的 knowledge-backup.timer 是每日全量本机存档;litestream
是实时异地复制。两者互补:
- 本地 daily 用于"刚才误删一条记录" 快速回滚
- litestream 用于"机器全没了" 灾难恢复
不冲突,都开就好。
性能影响
litestream 读 WAL 是只读操作,对 application 几乎无影响。
WAL 上传是后台 + 异步,application 写延迟不变。
CPU 占用通常 < 1%,内存 < 50 MB。
踩过的坑
-
SQLite 必须 WAL 模式:litestream 依赖 WAL。
sql PRAGMA journal_mode = WAL;
不是 WAL 时 litestream 报错。Django 我们已经在 settings 里开了。 -
不能两个 litestream 同时复制同一个 DB:会写坏。一个机器一个
实例。 -
同时开 cron
.backup:.backup命令本身不影响 WAL,安全;
但VACUUM/VACUUM INTO会重写 DB 让 litestream 失效,需要
重新 init。 -
B2 / R2 等 S3-兼容 endpoint URL 易写错:每个区域 endpoint
不同。出错时litestream replicate报 "no such bucket"。
curl 测试一下访问。 -
首次 restore 时 generation 不匹配:DB 被本地写过新数据,
litestream WAL 链断了。生产里数据始终从备份 restore,本地不要
手动改。
登录后参与评论。