首页 › programming › 删不掉才不打架:CRDT靠墓碑实现协作

删不掉才不打架:CRDT 靠"墓碑"实现协作

两个人同时改一个文档,为什么不会把文件改炸?这是协作软件每天都在默默回答、却极少有人深究的问题。YouTube 上 pixperk 频道的这期 《CRDTs Explained: Building a Collaborative Whiteboard from Scratch》,用 20 分钟从零手搓一个多人协作白板,把"协作不冲突"这件事从直觉拉到了数据结构层面。它的真正价值,不是教你画白板,而是揭示了一个反直觉的工程真相:多人协作的根本解法,不是加锁、不是抢顺序、不是让服务器当裁判,而是让"删除"这件事变得不可能。

这听起来荒谬,但正是这层荒谬,撑起了 Figma、Notion、Linear、Excalidraw、tldraw 这一整代协作产品的底层。今天这篇,我们就顺着这期视频,把 CRDT(Conflict-free Replicated Data Type,无冲突复制数据类型)的内核彻底拆开。

视频背景卡片

项目 内容
视频标题 CRDTs Explained: Building a Collaborative Whiteboard from Scratch (System Design)
频道 pixperk(yashaswi mishra)
时长 约 20 分钟
核心主题 从零构建协作白板,理解 CRDT 如何解决并发编辑冲突
适合人群 想搞懂 Figma/Notion 这类协作产品底层的中高级开发者

核心内容拆解

1. 协作的真正难题不是网络延迟,是"同时"

视频一上来就把问题摆正了。多数人以为协作软件的难点是"网络不稳""消息丢了",其实那些都是工程问题,早有重传和 ACK 解决。真正的硬核难点是 concurrency(并发)——两个用户在通信往返的那段时间窗口里,各自基于旧状态做出了相互矛盾的决定。

举个视频里反复出现的典型场景:一块白板上有个圆形,A 把它拖到左上角,几乎同一时刻 B 把它拖到右下角。两条"移动"指令最终都到达服务器,到底听谁的?这不是 bug,这是分布式系统里 同时性没有绝对定义 的必然结果。爱因斯坦的相对论在工程世界里同样成立:在没有全局时钟的网络里,"谁先谁后"本身就无法判定。理解这一点,是理解后面一切的前提。

2. 老办法 OT——让服务器当唯一的裁判

在 CRDT 普及之前,整个行业的标准答案叫 OT(Operational Transformation,操作变换),Google Docs 就是靠它跑了几十年。OT 的思路很直白:既然无法避免冲突,那就让一台中心服务器把所有人的操作排成一个唯一的全局顺序,再对"并发的操作"做数学变换,让它们相互兼容。

这套机制能跑,但代价巨大。第一,它强依赖中心服务器,服务器挂了协作就死,也无法真正离线工作。第二,OT 的变换函数出了名的难写对,业内有个梗叫"OT is hard",多家大厂都栽过跟头。本质上,OT 是在用"抢一把全局锁"的思路解决冲突——只不过这把锁是一台服务器的时间序权威。视频把这条路当作对照组,是为了衬托 CRDT 的颠覆性。

3. CRDT 的反直觉内核:不抢顺序,而是让顺序无所谓

(这是视频和整个 CRDT 理论的核心论点) CRDT 直接掀桌子:既然抢顺序这么痛苦,那能不能让"顺序根本不重要"?

办法是设计数据结构时,让合并操作满足三条数学性质:交换律(a⊕b = b⊕a)、结合律、幂等性(a⊕a = a)。只要这三条成立,那么不管消息以什么顺序到达、到达几次、谁先谁后,所有副本最终都会收敛到同一个状态。这套东西在数学上叫 join-semilattice(连接半格)——你不需要懂格论,只需要记住一句话:只要合并满足交换律,就不再需要裁判。

这套理论在 2011 年由 Marc Shapiro、Nuno Preguiça、Carlos Baquero、Marek Zawirski 四人在论文里正式定义,最初动机正是协作文本编辑和移动端弱网场景。某百科的 CRDT 词条把它概括为三大特征:任意副本可独立并发更新、算法自动消解不一致、所有副本保证最终收敛。注意是"最终一致",不是"强一致"——CRDT 牺牲了瞬时一致性,换来了去中心化和离线能力。

4. 删不掉才不打架——墓碑是 CRDT 的灵魂

(标题的来源,也是视频里最容易被一笔带过的深层代价) 要让所有操作都满足交换律和幂等性,CRDT 付出了一笔隐晦但巨大的代价:你几乎不能真正"删除"任何东西。

为什么?设想 A 在删除元素 X 的同时,B 正在往同一个集合里添加一个新元素 X。如果 A 的删除是"物理删除",那它会把 B 即将到达的新 X 也一并抹掉,造成丢数据。为了在并发世界里保证安全,CRDT 的删除一律是 软删除——给元素盖个"墓碑"(tombstone),标记为已死,但数据本身永远留在结构里。

这就是 CRDT 最反直觉的地方:协作越顺畅,垃圾越堆越多。一份协作文档可能删得只剩三行字,但底层数据结构里却塞满了成千上万个墓碑。所以 CRDT 的"垃圾回收与压缩"(garbage collection / compaction)是一整片独立的研究领域,Yjs、Automerge 都在这上面花了大量功夫。理解了墓碑,你才真正理解 CRDT 不是"免费午餐"。

5. 一切从计数器和集合开始——CRDT 的积木

(延伸:视频偏重白板实战,这里补全 CRDT 的理论积木) CRDT 不是一种数据结构,而是一整族,靠几个原子积木拼出来:

这些积木本身就是值得单独成篇的知识宝藏,Redis、Riak、Azure Cosmos DB 这些分布式数据库都内置了 CRDT 数据类型。

6. 文本是最难的——序列 CRDT 与"位置编号"

(延伸) 白板好做,因为它本质是"一堆独立图形的集合",天然低冲突。真正难的是文本。在一段文字里插入字符,本质是个序列问题:你按"第 5 个位置插入一个 H",可此时另一个人也在第 5 个位置插了东西,下标立刻对不上,整段文字错位。

解决思路有两种:分数索引(Logoot、LSEQ)——把每个字符的位置编成一个有理数,永远插在两个邻居之间,靠无限细分避免冲突;或者 RGA(Replicated Growable Array)——用带全局唯一 ID 的链表,并发时的"平局"用一个确定性的决胜规则(比如副本 ID 大小)来打破。WOOT、Treedoc、LSEQ、RGA 这一串名字,就是过去十几年学界啃"序列 CRDT"这块硬骨头留下的脚印。正是因为文本这么难,才催生了 Yjs、Automerge 这类工业级通用库——它们封装好了这些坑,让普通开发者不用重新发明轮子。

7. 白板为什么是 CRDT 的甜区——pixperk 的实战落点

回到视频本身。pixperk 选择白板不是偶然,而是因为白板是 CRDT 最舒服的落点。一块白板 = 一组图形,每个图形 = 一个唯一 ID + 一组属性(x、y、宽高、颜色)。映射到 CRDT:

因为每个图形用不可变的唯一 ID 寻址,根本不存在"下标错位"那种灾难性冲突。两个人改的是不同图形?完美交换律,互不干扰。改的是同一个图形的同一属性?LWW 谁晚谁赢,干净利落。这正是 Figma、tldraw、Excalidraw 不约而同收敛到的模型。视频用从零撸代码的方式,让你亲手把这个映射走一遍,比读十篇博客都通透。(Figma 工程团队自己的博客《How Figma's multiplayer technology works》也佐证:他们对属性级冲突采用 last-writer-wins 思路,整体精神与 CRDT 高度一致。)

8. 从"在线协作"到"本地优先"——CRDT 的真正革命

(延伸:视频的格局升华) 顺着视频往远处看,CRDT 最大的红利其实不是"看到别人的光标实时动",而是 Local-First Software(本地优先软件)。

因为 CRDT 的合并不依赖顺序、不依赖中心服务器,所以你可以完全离线改一份文档,三天后联网,它照样能和别人改的版本正确合并、收敛一致。这颠覆了过去二十年"服务器是唯一真相、客户端只是个笨视图"的架构。Martin Kleppmann(《Designing Data-Intensive Applications》作者)2019 年那篇 "Local-first software" 把这定义为一场革命,而 Automerge、Yjs 就是这场革命的施工队——Linear 的同步引擎、Apple Notes、Notion 的离线能力,背后都是同一套逻辑。

知识结构图

flowchart TD
    P([并发编辑难题<br/>两人同时改同一段])
    P --> OT[OT 操作变换<br/>中心服务器排全局顺序<br/>强依赖中心 / 变换函数难写]
    P --> CR[CRDT 无冲突复制数据类型<br/>不抢顺序 让顺序无所谓]

    CR --> MATH{数学内核<br/>合并满足 交换律+结合律+幂等性<br/>= Join-Semilattice 连接半格}
    MATH --> COST[代价: 墓碑 Tombstone<br/>删不掉 只能软删除 → 需 GC 压缩]

    CR --> BLOCKS[CRDT 积木族]
    BLOCKS --> B1[G-Counter / PN-Counter<br/>计数]
    BLOCKS --> B2[G-Set / 2P-Set / OR-Set<br/>集合]
    BLOCKS --> B3[LWW-Register/Map<br/>属性级 last-writer-wins]
    BLOCKS --> B4[序列 CRDT<br/>RGA / LSEQ / Logoot<br/>文本插入最难]

    B3 --> WB[协作白板甜区<br/>图形=唯一ID+LWW属性<br/>Figma/tldraw/Excalidraw]
    B4 --> LIB[工业级库<br/>Yjs / Automerge]
    WB --> LF[Local-First 本地优先<br/>离线可改 联网收敛]
    LIB --> LF

实战启示

对开发者而言,这期视频和 CRDT 这套体系能立刻转化为几条行动指南。

第一,别再自己造协作的轮子。 任何要做实时协作、多端同步、离线编辑的产品,第一反应应该是上 Yjs 或 Automerge,而不是手写 OT。Yjs 在前端协作(富文本、白板、表格)几乎是事实标准,Automerge 在 local-first 和移动端弱网更胜一筹。OT 的变换函数坑深似海,自己写大概率会埋下"偶发性丢字"的定时炸弹。

第二,用 CRDT 友好的方式设计数据。 核心原则:一切共享状态都用不可变的唯一 ID 寻址,属性按 LWW 更新,删除一律打墓碑。 永远避免"按下标原地修改共享数组"这种反 CRDT 的写法——那是冲突的温床。哪怕你不做协作产品,这套"不可变 ID + 幂等合并"的心智模型,对任何分布式系统、异步任务、事件溯源、幂等 API 设计都直接受益。

第三,提前规划墓碑的生命周期。 CRDT 文档只增不减(逻辑上),长期协作的产品必须设计 compaction 机制——什么时候能安全回收墓碑、如何做快照压缩。这是 Yjs/Automerge 文档里专门强调、却最容易被新手忽略的部分。

第四,搞清楚你要的是 LWW 还是序列 CRDT。 如果你做的是白板、表单、看板这类"独立对象"场景,LWW-Map 足矣,简单高效;如果做的是富文本/代码这类"序列"场景,老老实实用序列 CRDT,别幻想用下标能搞定。选错积木,后面全是 bug。

延伸学习路径

  1. Martin Kleppmann 的两场经典演讲——"Conflict-free Replicated Data Types"(讲透 CRDT 数学)与 "Local-first software"(讲透愿景),B 站/YouTube 都有字幕版,是理解这领域的最佳入口。
  2. 2011 年原始论文——Shapiro 等人《A comprehensive study of Convergent and Commutative Replicated Data Types》,HAL/INRIA 开放获取,理论地基,适合想啃硬核的读者。
  3. Yjs 官方文档(yjs.dev,作者 Kevin Jahns)——工业级 CRDT 的最佳实践与 API,看完就能上手。
  4. Automerge 文档 + Kleppmann《Designing Data-Intensive Applications》第 5/9 章——前者是 local-first 工具链,后者是分布式数据系统的圣经级教材。
  5. Figma 工程博客《How Figma's multiplayer technology works》——一线大厂如何把这套理论落地到千万级用户的真实产品,配合 tldraw、Excalidraw 的同步机制文章一起看,实战味最浓。

一句话总结

CRDT 教会我们的最大洞见是:解决冲突最高明的办法,不是更强力地协调,而是把数据结构设计得"冲突根本无从发生"——代价是,你永远删不掉任何东西。

参考来源

  1. CRDTs Explained: Building a Collaborative Whiteboard from Scratch — pixperk — 本文分析的核心视频
  2. How CRDTs make multiplayer text editing part of Zed's DNA — Zed Blog — 序列 CRDT 在代码编辑器中的工程实践
  3. Understanding CRDTs: The Magic Behind Collaborative Editing — singhkunal2050 — CRDT 直观讲解补充
  4. How Figma's multiplayer technology works — Figma Engineering Blog — 一线协作产品的冲突处理实战

    本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

完成摘要

下一步

注意事项

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入