为什么 AFFiNE 选择 CRDT 而非 OT 来构建协作编辑器#
译者注:
AFFiNE 是一个开源的现代化协同文档编辑器项目,该项目采用了 Notion + Miro + Obsidian 的混合风格,强调:
- 支持多人协作
- 支持本地编辑
- 支持 markdown + 富文本 + 白板
- 基于 CRDT 技术实现同步
AFFiNE 目标是构建一个“本地优先、支持多人实时协作、集文档、白板、任务于一体”的全功能办公工具。

这篇文章会介绍 Affine 为什么选择 CRDT 而非 OT,用来实现更出色的实时协作,确保高可用性、强大的容错性以及轻松扩展能力,从而推动业务成功。
作为一款支持多用户实时协作的编辑器,AFFiNE 在数据可用性方面面临三大挑战:
- 数据同步:AFFiNE 需要在多个服务端和客户端节点之间进行双向数据同步。
- 最终一致性:即使在出现网络延迟或短暂中断的情况下,AFFiNE 系统中的所有节点最终也必须能够达成一致的状态。
- 冲突解决:AFFiNE 需要具备自动解决并发编辑冲突的能力。
上述问题在协作类应用中非常常见,因此其解决方案应通过某种通用的协作算法来保障可靠性。过去三十年间,研究人员提出了数百种协作算法,但大多可以归为两类:Operational Transform(OT) 或 Conflict-free Replicable Data Type(CRDT)。我们认为,当前更优的选择是 CRDT。
OT 与 CRDT 的定义与区别#
如果你把“追溯历史状态”视为最基础的协作能力之一,那么你会发现 event sourcing 设计模式几乎是所有协作能力的起点。该模式要求我们将对数据模型的操作抽象为可序列化的操作(或命令)数据结构。例如,Web 开发者熟知的 Redux 库就是 event sourcing 模式的典型实现。
在多人实时协作的场景中,挑战主要来自这样一个情况:在任意时刻,不同用户的操作可能会产生分歧。但从 event sourcing 的视角来看,我们始终在处理两类数据结构:model 和 operation。据此可以认为,OT 的核心在于对 operation 数据的转换,通过转换后的 operation 数据可以在不同客户端的普通 model 上应用;而 CRDT 的核心是设计一种对并发操作友好的 model,使得不同客户端可以在任意时间顺序下合并操作。
尽管现在有观点认为 OT 与 CRDT 在理论基础上本质一致,但我们认为,上述这种对比仍然是理解这两种机制的一个实用思维模型。
我们为何更倾向于选择 CRDT#
在 CRDT 中,每次更新都可以看作是一个“历史片段”。我们不断从其他客户端收集这些片段,并依靠片段中携带的逻辑时间戳来还原出最终一致的真实状态。我们认为,CRDT 的这种工作机制相较于 OT 具有以下三大优势。
去中心化#
由于 CRDT 的数据模型被设计为可以在任意客户端独立解决冲突,因此无需引入中心节点来唯一确定操作的合并顺序。这不仅降低了对单一服务端节点的依赖,还为构建下一代 local-first 应用架构提供了可能——这种架构融合了传统本地应用与协作应用的优点,甚至在技术上也支持端到端加密的协作方式。
性能表现#
尽管早期为学术研究而设计的 CRDT 实现曾被认为性能较差,但近年来经过业界的优化,CRDT 的吞吐量已超越传统 OT 实现,内存占用也已降至可接受的水平。同时,由于 CRDT 的去中心化特性,它具备更高的延迟容忍度,能够在更长时间离线后依然完成冲突解决。相比之下,在相同条件下 OT 的计算压力往往会给服务端带来较大负担。
灵活性与易用性#
CRDT 支持更广泛的数据类型。例如,Yjs 支持 Text、Array、Map 以及类树形结构的数据,使其适用于更多业务场景。由于支持的数据类型更多,CRDT 在扩展性方面通常也更具优势。相比之下,OT 库要求开发者将业务逻辑彻底建模为不同类型的 operation 数据结构,而使用 CRDT 库时,你只需对常见的数据结构(如 Map 和 Array)执行相同的操作,它们会被自动映射到对应的 CRDT 模型上。
在某种程度上,这就像是使用一个更强大、更易用的应用 state 管理 API,有点类似 Redux 的作用,但整体接入成本更低。
总结#
协作算法对许多开发者来说仍然比较陌生。尽管相关的概念性介绍已有不少,但关于如何实际使用这些算法的清晰说明仍然较为匮乏。如果你也正处于初创阶段,正在开发一款编辑器,并希望就此获得一些建议,我们的看法是:CRDT,特别是目前的 Yjs,实现,已经是非常值得考虑的选项。
-EOF-