CRDT 可变树 · 多副本层级如何无冲突收敛
文件目录、大纲笔记的缩进、设计稿的图层面板、思维导图 —— 大量真实数据是一棵会变结构的树:不只叶子内容能改,节点本身还能换父节点。一旦这棵树要被多个副本离线各自编辑再合并 (本地优先、协同编辑),普通的 last-writer-wins 就不够了:两个副本并发地把对方移到自己下面,朴素合并会拼出一个环,树就不再是树。
本系列沿着 Kleppmann 等人的 move 算法 (2021 年预印本,2022 年发表于 IEEE TPDS),把一棵可复制可变树拆开来看:先把层级建模成「虚拟 root 加单亲森林加 trash」,把增删移统一成唯一原语 move(child, parent);再逐一演示并发会制造的畸变、应用前的祖先检查如何挡住成环、以及 undo-do-redo 如何让乱序到达的操作也收敛;最后一页是可亲手投递的多副本模拟器。每页都能改输入、单步播放、随时校验。
把层级建模成可复制的树
一个虚拟 root 把森林收成一棵树、每个节点恰好一个 parent、删除改为移进 trash,于是增删移全部归一成唯一原语 move。
move 原语与并发畸变
两个副本从同一棵树各发一个 move,朴素合并会拼出三类畸变:成环、双亲分歧与孤儿。本页把问题暴露出来,修法留给后两页。
应用前的祖先检查
应用 move 前从新 parent 沿 parent 链上行,若撞到 child 或两者相同则必然成环,这步退化成 no-op:记进 log 但不改树。
undo-do-redo 重放
每个副本维护一份按时间戳升序的 op log。时间戳较小的 op 迟到时,先把更大的 entry 依次 undo、do 新 op、再按升序 redo 回来。
多副本与可控网络
三个副本各持一棵树与一份 log,op 先本地生效再投进网络缓冲区。无论按什么顺序投递,缓冲区清空后三个副本收敛到同一棵树。
它真实跑在哪里
原始论文与实现
- A highly-available move operation for replicated trees · Kleppmann, Mulligan, Gomes, Beresford (2021) martin.kleppmann.com 本系列的算法基石。提出 undo-do-redo 的 move 操作与「应用前祖先检查 → 成环则 no-op」, 证明任意投递顺序下副本收敛、单亲森林永不成环 (IEEE TPDS)。
- Automerge — a CRDT library for building local-first apps automerge.org Kleppmann 参与的本地优先 CRDT 库, move 操作的工程实现取自上述论文。
- crdt.tech — Conflict-free Replicated Data Types crdt.tech CRDT 的总览门户: state-based / op-based、各类数据结构与论文索引, 树 CRDT 在更大图景中的位置。
- Local-first software · Ink & Switch inkandswitch.com 「本地优先」理念的奠基长文, 阐明为什么离线可编辑 + 多副本收敛是 CRDT 的核心动机。