Hold Off on Litestream 0.5.0

Michael Lynch

暂缓使用 Litestream 0.5.0

Litestream 是一款开源工具,可以实时将 SQLite 数据库备份到云存储。我很喜欢它,并在自己的所有项目中都使用它。

Litestream 归 Fly.io 所有,他们曾为了另一个名为 LiteFS 的替代项目而暂停了 Litestream 的开发近两年。两周前,Litestream 的创造者和首席开发者 Ben Johnson(本·约翰逊)宣布,他们已将重心转回 Litestream,并且刚刚发布了新版本 0.5.0

我试用了 Litestream 0.5.0,但我提醒其他 Litestream 用户,在将其部署到生产环境之前,最好再等一个版本发布并进行更充分的测试。我迁移到新版本 Litestream 的过程并不顺利。

更新:Litestream 0.5.1 现已发布,修复了我遇到的大部分(但并非全部)问题。

更新 2(2025-10-17):Litestream 0.5.2 修复了我遇到的所有 bug,因此我计划将其部署到我的基于 SQLite 的应用中。

说明:我并不是在抱怨 Litestream。我很喜欢 Litestream,也很高兴看到它重新恢复开发。我只是希望让其他 Litestream 用户避免踩到我遇到的同样的 bug。

预期的迁移工作

从旧版本的 Litestream 升级到 v0.5.0 及以上版本,有两项有意为之的变更:

  1. 备份格式已更改,因此 Litestream 0.5.0 无法从旧版本 Litestream 创建的备份中恢复。
  2. litestream.yml 配置文件格式略有变化。以前有一个名为 replicas 的数组字段,但 0.5.0 将其改为了名为 replica(单数)的字典。

Litestream 发布了一份实用的迁移指南,包含更多细节。

Litestream 0.5.0 的一个好处是现在有了官方 litestream Docker 镜像。(更正:读者 placardloop 指出这个 Docker 镜像并不是新出的,只是我一直没注意到。)以前我所有的 Docker 容器都需要大量样板代码来下载正确版本的 Litestream 并使其在容器中可用,但现在只需一行 Dockerfile:

COPY --from=litestream/litestream:0.5.0 /usr/local/bin/litestream /app/litestream

我向 Litestream 0.5.0 的测试迁移

为了测试 Litestream 0.5.0,我尝试将其部署到我的项目 What Got Done 上。这是一个很好的测试对象,因为:

  1. 我已经宣布要关闭这项服务,所以用户已经停止使用该网站。
  2. 服务器一直因为 Litestream 0.3.13 中的一个 bug 而不断出错,该 bug 已在 0.5.0 中修复。

上传到 Backblaze 后端不再可用

迁移开始时,我先用 Litestream 0.3.13 下载了数据的最新副本,然后尝试使用 Litestream 0.5.0 以 Litestream 的新格式将其上传回 Backblaze 的云存储。但我遇到了这个错误:

error" db=store.db replica=s3 error="write ltx file: s3: upload to db/0000/0000000000000001-0000000000000001.ltx: operation error S3: PutObject, resolve auth scheme: resolve endpoint: endpoint rule error, Custom endpoint `s3.us-west-002.backblazeb2.com` was not a valid URI"

同样的副本定义在之前的版本中一直有效,所以我有点困惑。

access-key-id: ${LITESTREAM_ACCESS_KEY_ID}
secret-access-key: ${LITESTREAM_SECRET_ACCESS_KEY}
dbs:
  - path: ${DB_PATH}
    replica:
      url: s3://${LITESTREAM_BUCKET}/db
      endpoint: ${LITESTREAM_ENDPOINT}

我尝试了几种指定 Backblaze S3 endpoint 的替代写法,但 Litestream 都把它们当作配置错误拒绝了,甚至还没开始尝试备份。我原来的配置是唯一被 Litestream 认可为有效配置的写法,但它却无法完成备份。

我提交了 Backblaze replica fails with “Custom endpoint … was not a valid URI” #789,Litestream 开发者 Cory LaNou(科里·拉努)第二天就修复了它

既然我能够以 Litestream 的新格式将数据上传到 Backblaze 了,我就扫清了将 Litestream 0.5.0 集成到 What Got Done 中的障碍。

-if-replica-exists 消失了

将 Litestream 0.5.0 部署到 What Got Done,但服务器启动失败,报出这个错误:

flag provided but not defined: -if-replica-exists

我查看了命令文档,文档说 -if-replica-exists 仍然受支持:

$ litestream restore -help | grep if-replica-exists --after-context=1
        -if-replica-exists
            Returns exit code of 0 if no backups found.

结果发现这个标志是被误删的,并且将在 0.5.1 中回归

恢复失败,报 transaction not available

我没有因为 -if-replica-exists 的缺失而气馁,把它从我的启动脚本中删掉了。但随后我的服务器启动失败,出现了一个新错误:

level=ERROR msg="failed to run" error="cannot calc restore plan: transaction not available"

这与 Litestream 的一个未关闭 issue 相符,其严重程度令人担忧:“CRITICAL - Complete Data Loss”(严重——完全数据丢失):

Litestream 不再创建目录

到了这一步,我愿意尝试任何办法来恢复运行,于是通过在我的 Docker 容器中从源码构建,运行了最新的前沿版本 Litestream。

幸运的是,最新版本绕过了我遇到的那个 transaction not available 问题,Litestream 在流程中走得更远了!

不幸的是,还有一个错误需要克服:

level=ERROR msg="failed to run" error="create temp database path: open /app/data/store.db.tmp: no such file or directory"

这个错误其实很简单,我对发生的原因有相当大的把握。在旧版本的 Litestream 中,如果我让它把 SQLite 数据库恢复到 /app/data/store.db,而 /app/data 路径不存在,Litestream 会在写文件之前尝试创建该目录。

我查看了源码,发现这段代码流程中的文件夹创建逻辑消失了,但修复起来很简单,于是我提交了一个修复:

成功了!

应用了最终的 mkdir 修复的 我的 Litestream fork 让 What Got Done 恢复了运行!

反思

我用一个预发布 fork 让 Litestream 0.5.x 跑了起来,但我打算再等一两个版本发布,才会将其部署到我的其他项目中。0.5.0 的变更似乎比 Litestream 团队预期的更具破坏性,他们仍在与一些严重的 bug 搏斗:

还有几个其他严重 bug 已在开发版本中修复,但尚未出现在生产发布中更新:这些问题现已在 0.5.1 中修复):

说明:再次强调,这不是对 Litestream 的批评。流式复制很难做对,他们所做的工作远比我能产出的要健壮。我感谢 Litestream 团队如此迅速地响应 bug 报告并修复问题。

原文由 Michael Lynch 发布

本文章由 stealth/ox-alpha 进行翻译