🚀 一、背景:协同同步问题是什么?
在多人协作(比如多人编辑文档、白板、会议笔记)中,多个客户端同时修改同一份数据 。
这会带来典型的并发冲突问题:
A 和 B 同时编辑同一段文字:
- A:插入「Hello」
- B:删除第 3 个字符
如果同步机制不合理,最终文档状态可能不一致。
这类场景要求系统满足以下目标:
需求 | 说明 |
---|---|
实时性 | 多端编辑几乎同步显示 |
一致性 | 所有用户最终看到同一个结果 |
无冲突 | 同时编辑不同位置时,不覆盖对方改动 |
可回放 / 撤销 | 支持历史版本与撤销操作 |
容错 | 临时离线、断网恢复后仍可正确合并 |
为了解决这个问题,业界主要有两类核心算法体系:
✅ OT(Operational Transformation)
✅ CRDT(Conflict-free Replicated Data Type)
🧩 二、OT(Operational Transformation)操作变换
Google Docs、腾讯文档、飞书文档、石墨文档等广泛采用。
1️⃣ 思想核心
- 客户端在本地立即执行操作(实现"低延迟")。
- 同步到服务器后,服务器将该操作与其他并发操作进行变换(Transform) 。
- 最终所有客户端应用同样的操作序列后,文档状态一致。
2️⃣ 基本机制
📘 举个例子:
假设文档初始内容为:
abc
- 用户 A:在第 1 个位置插入 "X" → 操作:
Insert(1, "X")
- 用户 B:删除第 2 个字符 → 操作:
Delete(2)
两者同时发出操作。
🚦 如果服务器直接按顺序执行:
- 若先执行 A:文档变成
"aXbc"
- 再执行 B:删除第 2 个字符(现在是 "X")→
"abc"
✅ - 若先执行 B:文档变成
"ac"
- 再执行 A:插入第 1 个字符 →
"aXc"
❌ 结果不一致!
✅ 解决方案:Transform 操作
OT 核心是定义一个 Transform 函数:
scss
T(op1, op2) = 调整 op1 以适配 op2 的影响
例如:
- 若 B 在 A 之后删除的字符位置发生了偏移,则需要调整 B 的操作位置。
这样最终每个客户端都能在不同的操作顺序下,得到相同的最终状态。
3️⃣ 特点总结
特性 | 说明 |
---|---|
核心思想 | 对并发操作进行位置变换(Transform)以保持最终一致性 |
适合场景 | 文本协作、文档编辑、白板笔记 |
优点 | 实现简单、性能好、兼容中心化服务器 |
缺点 | Transform 规则复杂、需中心协调、离线冲突合并较难 |
🧮 三、CRDT(Conflict-free Replicated Data Type)
Figma、Notion、Peer-to-Peer 协同系统中广泛使用。
1️⃣ 思想核心
CRDT 是一种数学上可证明"无冲突"的数据结构 。
不同节点上的操作可以 任意顺序应用 ,最终数据自动收敛一致。
换句话说:
每个客户端都可以独立编辑、离线修改,之后同步时系统自动合并结果,无需服务器参与 Transform。
2️⃣ 常见 CRDT 类型
CRDT 类型 | 作用 | 示例 |
---|---|---|
G-Counter / PN-Counter | 分布式计数器 | 在线人数、点赞数 |
G-Set / 2P-Set | 集合类型 | 标签列表、在线用户集合 |
RGA / LSEQ / Yjs | 顺序型结构 | 文本编辑(字符序列) |
Map CRDT | Key-Value 映射 | 文档字段、JSON 对象 |
3️⃣ 文本编辑中的 CRDT
以 RGA (Replicated Growable Array) 为例:
每个字符分配一个唯一 ID(时间戳+客户端ID) ,即使并发插入同一位置,也能通过 ID 比较确定顺序。
less
初始: [a][b][c]
客户端 A 插入 X(在 b 后)
客户端 B 插入 Y(在 b 后)
A 插入位置ID: b.A
B 插入位置ID: b.B
合并后根据ID顺序排列:
[a][b][X][Y][c]
无需服务器协调,自动保持一致。
4️⃣ 特点总结
特性 | 说明 |
---|---|
核心思想 | 数据结构内建"可并发合并"的数学属性 |
适合场景 | 去中心化/离线编辑(如 Figma、Notion) |
优点 | 天然支持离线、分布式同步、一致性收敛 |
缺点 | 存储与传输开销较大,算法复杂(ID膨胀) |
⚙️ 四、OT vs CRDT 对比总结表
维度 | OT(Operational Transformation) | CRDT(Conflict-free Replicated Data Type) |
---|---|---|
核心思想 | 并发操作的"位置变换" | 数据结构内建"无冲突合并" |
一致性保证 | 通过中心化服务器协调 | 通过数学可交换性自动保证 |
实时性 | 依赖服务器调度 | 客户端本地立即生效 |
离线支持 | 弱(需冲突重放) | 强(天然支持离线编辑) |
复杂度 | Transform 算法复杂 | 数据结构复杂 |
典型应用 | Google Docs、腾讯文档、飞书 | Figma、Notion、Jupyter、Yjs |
实现难度 | 低中 | 高 |
性能 | Transform 成本较低 | 元数据较多、内存开销大 |
🔄 五、在文档/会议协同系统中的实际架构
典型协同架构示意图:
arduino
┌──────────┐
│ Client A│───┐
└──────────┘ │
▼
┌─────────────┐
│ Sync Server │
│ (OT / CRDT)│
└─────────────┘
▲
┌──────────┐ │
│ Client B│───┘
└──────────┘
协同流程:
1️⃣ 客户端生成本地操作(插入、删除、修改)
2️⃣ 客户端立即应用(乐观更新)
3️⃣ 同步到服务器(或直接 P2P 合并)
4️⃣ 服务器执行 OT / CRDT 合并逻辑
5️⃣ 广播给其他客户端
6️⃣ 所有端最终状态一致
💡 六、面试回答建议(高级开发视角)
面试官可能会问:「你了解协同编辑机制吗?OT / CRDT 有何区别?」
你可以这样答👇:
文档和会议类应用的协同同步机制主要有两类:
- OT(Operation Transformation) :通过服务器对并发操作做位置变换,使得最终结果一致。它实现相对简单,适合中心化架构,如 Google Docs。
- CRDT(Conflict-free Replicated Data Type) :通过在数据结构层面内建可交换性,保证各节点操作最终一致,天然支持离线编辑,比如 Figma 和 Notion。
在协同产品中,通常选择 OT + 缓存合并实现在线协作,或者使用基于 CRDT 的新一代算法(如 Yjs、Automerge)支持 P2P 协同。
📘 七、推荐资料与开源实现
名称 | 技术 | 说明 |
---|---|---|
Google Wave / Docs | OT | 最早的 OT 实践 |
ShareDB | OT | Node.js 实现的协同框架 |
Yjs | CRDT | Web 协同编辑框架 |
Automerge | CRDT | JS 实现的文档协同引擎 |
ProseMirror | 可扩展编辑器 | 可接入 OT 或 CRDT |