同步不再将就
上个月,一个朋友在群里吐槽:他们的在线文档产品要加多人协作功能,技术负责人评估了一下,给了个方案——用 WebSocket 广播所有编辑操作,冲突了就提示用户"文档已被他人修改,请刷新后重试"。
我问他,你们打算让用户刷新多少次才能写完一段话?
这不是段子。在我见过的技术选型里,"广播 + 冲突提示"仍然是很多团队处理实时协作的第一反应。理由很简单——实现成本低,逻辑好理解。但这条路的尽头,是一个永远填不完的坑。
冲突不是边缘情况
想象一个场景:两个人同时编辑同一份文档的同一行。A 把"用户协议"改成了"服务条款",B 在同一位置加了个逗号。两个操作几乎同时发生,网络延迟让它们到达服务器的顺序不确定。
传统做法要么让 A 的修改覆盖 B 的(后到的覆盖先到的),要么把文档锁住让 B 等 A 改完。前者丢数据,后者体验差。
CRDT(Conflict-free Replicated Data Type,无冲突复制数据类型)提供了第三条路:从数学上保证,只要操作满足交换律和结合律,无论网络传输顺序如何、延迟多长,所有客户端最终都会收敛到同一份数据。不需要中心服务器仲裁,不需要锁,不需要用户手动解决冲突。每个操作本身就是一个独立的、可传播的、可合并的单元。
从论文到产品的距离
CRDT 不是新东西,2011 年就有论文。但过去十年它一直停留在学术圈,原因很实际——实现复杂度太高,而且大部分产品不需要这么重的方案。
情况正在变化。实时协作从加分项变成了必选项。Figma、Notion、Linear 的成功,把用户的期待拉到了一个很高的水位——打开文档看到光标在跳动是正常体验,如果需要点"编辑"按钮然后等锁释放,用户会觉得这个产品停留在上个时代。
阮一峰最近推荐的 Loro 是一个有意思的项目。用 Rust 写的 CRDT 库,提供 JavaScript 绑定,采用类似 Git 的 DAG 结构组织操作历史。每次编辑都有唯一标识,合并时基于因果关系图而非简单的时间戳。这种设计在处理"分叉后合并"的场景时特别有价值——三个人同时改了同一个表格的不同列,合并结果应该是三者改动的并集,而不是某个人的改动覆盖其他人。
为什么大部分团队还在将就
心智成本是第一道坎。CRDT 的思维方式跟习惯请求-响应模型的开发者差距很大。你需要理解操作的可交换性,理解为什么"删除"不能简单地删掉数据而是要用墓碑标记,理解并发操作在所有可能的交错顺序下都能收敛。这个学习曲线是真实的,不是文档能解决的。
工程成本是第二道坎。CRDT 库只解决了数据合并问题,但产品需要的远不止于此:持久化、权限控制、历史回放、冲突的可视化呈现。每一项都需要大量工程投入。Yjs 生态相对成熟,但文档里到处都是"这个场景还不支持"的警告。
还有一个被低估的原因:很多团队根本没意识到自己需要 CRDT。"先做个单人版,后面再加协作"这种迭代策略听起来很务实,但数据模型一旦定型,再想加无冲突合并能力,改造成本跟重写差不多。列表用普通数组和用 RGA 算法存储,表面上没区别,但要加协作功能时,前者需要全部推翻。
AI Agent 正在改变权重
如果说实时协作之前是"有了更好",AI Agent 的普及正在改变这个优先级。
当 Agent 能自动编辑文档、批量修改代码、同步更新知识库,它本质上就是一个超级协作者。区别在于:人类协作者最多同时在线十几个人,Agent 可以有成百上千个实例同时操作同一份资源。人类遇到冲突可以理解提示并手动解决,Agent 需要程序化的、确定性的合并结果。
CRDT 的无锁特性在这种场景下价值被放大了。Agent 不会"等一下"——它们的并发操作密度远超人类。传统锁机制在高并发下会变成瓶颈,乐观锁在冲突频繁时会陷入无限重试,而 CRDT 天然就是为这种高频并发设计的。
从产品架构的角度看,协作能力正在从"锦上添花"变成"基础设施"。这意味着数据模型的设计需要从第一天就考虑并发和合并,而不是事后打补丁。数据结构的底层选择,决定了后续扩展的天花板。
在实时协作这个领域,没有"先凑合后优化"——凑合的方案,从写第一行代码开始就在制造一个没法修补的洞。
添加新评论