celld vs Litestream深度对比:同样的LTX格式,两种复制目标
2026/9/16 16:32:58 网站建设 项目流程

celld vs Litestream深度对比:同样的LTX格式,两种复制目标

【免费下载链接】celldself-hosted, distributed Durable Objects项目地址: https://gitcode.com/GitHub_Trending/ce/celld

celld 与 Litestream 是两个“说同一种语言”的开源项目:它们都把 SQLite 的写前日志(WAL)转成LTX 文件格式,流式复制进对象存储。但两者复制的目标截然不同——Litestream 守护的是单个数据库,celld 则把同样的 LTX 格式用作自托管 Durable Objects 集群的持久性底座,做到每次写入 RPO=0。本文对比两者的定位、围栏(fencing)与压缩策略,帮你判断该用哪个。

🧭 一句话结论:同一种格式,两种使命

  • Litestream:单库的“备份卫士”。把一份 SQLite 数据库持续流式复制为 LTX 文件,故障时可从副本恢复出完整数据库。
  • celld:自托管的分布式 Durable Objects 守护进程。每个 Durable Object(称一个cell)自带一个 SQLite 数据库,整个节点集群只共享一个你拥有的 bucket(S3 兼容或 GCS);celld 把每个 cell 的数据库持续复制到该 bucket——bucket 是持久的真相源,节点可替换

两者写出字节级兼容的 LTX 文件(下文会讲它如何被证明),但解决的工程问题不在一个量级:单库备份vs分布式协调 + 数据持久化

📦 LTX 格式:两者的“共同语言”

LTX 文件(Version 3)是 SQLite 数据库的“快照 + 增量日志”序列化,每个文件由四段组成:

区段内容
头部(100 字节)魔数LTX1、页大小、事务 ID 区间(MinTXID/MaxTXID)、WAL 位置、滚动校验和
页块每页独立 LZ4 压缩(6 字节页头 + 4 字节长度 + 压缩块)
页索引各页偏移与大小的 varint 编码
尾部(16 字节)应用后校验和 + 整文件校验和(CRC64-ISO)

文件命名规则是<minTXID>-<maxTXID>.ltx:MinTXID 为 1 时是全量快照,否则是覆盖某段事务的增量日志。完整字节布局见 ltx-format.md,核心类型(TXID、Pos、Checksum)定义在 lib.rs。

🔒 Litestream:守护单个 SQLite 数据库

Litestream v0.5 的复制模型非常直接——单副本、L0-only

  • 快照(MinTXID=1)与所有增量文件全部平铺在ltx/0/目录下;
  • replicate负责捕获与上传,restore按 TXID 顺序回放 LTX 链,重建出数据库文件;
  • 定位是被动的备份工具:源库照常运行,副本用于灾难恢复。没有节点间仲裁,不存在多写者问题,因此它也不需要协调协议。

celld 复制引擎的 sync 与 restore 逻辑正是从这一模型移植而来,replica.rs 顶部明确标注了“L0-only、single replica”的作用域说明。

⚡ celld:当每个对象都是自己的数据库

当一个集群有成千上万个 cell(官方测试场景:10 个节点承载 10,000 个驻留 cell 和 20,000 条并发 WebSocket),"一个库 → 一个副本"就不够用了。celld 在同一 LTX 格式之上加了三层机制:

1. 纪元围栏(epoch fence):新旧主一目了然

每个 cell 在 bucket 里有一条所有权记录,靠对象存储的条件写(CAS)获取,每次激活都会推进 epoch。数据写在cells/<cell>/ltx/e<epoch>/这个纪元前缀下,且是普通 PUT——因为围栏就是 key 里的 epoch 本身:失去所有权的旧节点即使继续写,也只写进被废弃的前缀,恢复时只会选当前血缘,脏数据进不来,数据路径也零条件写开销。详见 fencing.md。

2. RPO=0:数据落桶后才回包

输出门(output gate)会挂起写请求的响应,直到复制器证明数据已在 bucket 中;回包前还会重读一次所有权记录——被分区的节点可以把数据写进自己废弃的前缀,但永远拿不到虚假的“成功”回执。规则与推导见 fencing.md。

3. 自围栏:到不了 bucket 的节点主动放手

一个无法续约租约、也无法复制的节点主动释放自己持有的 cell,由其他节点通过所有权记录接管。节点故障是“正常输入”而不是“恢复程序”。

⚖️ 核心差异速览

维度Litestreamcelld
定位单库备份 / 灾难恢复自托管分布式 Durable Objects 运行时
复制单元一份 SQLite 数据库每个 cell 一份独立 SQLite
协调机制无需仲裁(单写者场景)bucket 条件写 + 纪元前缀围栏
数据角色被动副本整个集群共享的真相源
写入保证事后备份RPO=0(先落桶后回包)
压缩L0-only(v0.5.11)L0 + L1 增量压缩(默认开启)
故障模型恢复单库节点可替换,cell 在 ~11 秒尾延迟内回到可用

❓ 为什么 celld 删掉了 Litestream 的“租约”机制?

Litestream 用对象存储租约(leaser)解决多实例竞争。celld 把这部分移植后,于 2026 年 8 月删除了——README 说得很直白:celld 用“带 epoch 的条件写记录”围栏所有权,用“把 epoch 盖进 LTX 前缀”围栏数据路径,“再在副本前缀下放一个租约文件会是第二套互相竞争的分层”。一句话:epoch 键控比一套独立租约文件更直接、更便宜

🧪 如何证明“说的是 Litestream”?字节级差分测试

格式兼容不是口号,是被测出来的:

  1. 黄金夹具:测试基线用真实的 Litestream v0.5.11 二进制捕获,对不上就判定是移植方出错(来源见 MANIFEST.md);
  2. 三向差分:D1 — celld 写、真 Litestream 恢复;D2 — 真 Litestream 写、celld 恢复;D3 — 两个工具恢复同一副本,输出的数据库文件必须逐字节相同(见 differential_xtool.rs);
  3. 版本锚定:格式 oracle 使用 Litestream v0.5.16(对应 LTX v0.5.2),同时继续压缩 v0.5.11 的旧格式夹具,证明新旧两代都通。

🧩 兼容边界:哪个版本能读哪种文件?

这是升级集群前必须知道的一条边界:

  • LTX 对两种页面编码都保持文件版本号 3:老的frame表示(LZ4 帧)与新的block表示(长度前缀 LZ4 块);celld 的 v0.5.2 编码器与压缩器产出精确的 block 文件;
  • celld 与 Litestream v0.5.16 都能读 block 和 frame 两种文件;而 Litestream v0.5.11 只能读旧的 frame 文件。

因此混合版本集群升级时,要先在所有节点设置CELLD_LTX_COMPACTION=0,等全部节点都具备读 block 文件的能力后再放开——典型的“先升级读者,再切换写入者”规则。

🚀 如何选择:三个典型场景

你的场景建议
把一份生产 SQLite 备份到 S3,用于灾难恢复Litestream
自托管 Cloudflare Workers / Durable Objects 等价能力,且要求写入不丢celld
研究或实现 SQLite 到对象存储的复制格式先读 ltx-format.md,再对照两份实现

总结

同样的 LTX 格式,两种复制目标:Litestream 把一个数据库复制到“备份”,celld 把成千上万个 cell 数据库复制到“协调与持久化”。celld 继承了 Litestream 的捕获、同步、恢复算法与字节级格式,又用纪元围栏替代了租约、用共享 bucket 替代了单一副本——把一个备份工具,变成了分布式运行时的底座。

【免费下载链接】celldself-hosted, distributed Durable Objects项目地址: https://gitcode.com/GitHub_Trending/ce/celld

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询