searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

多人协同编辑技术初探

2023-06-29 01:32:22
39
0

这是一个多人协同的场景,即多个客户端同时编辑同一份数据。

目前比较常用的技术方案有三类(从易到难):

第一类,编辑锁,思路就是避免冲突,即禁止多人同时编辑,只允许抢到锁的用户编辑和提交数据。

最简单粗暴的做法就是加个锁状态,用户点击“编辑”按钮时进行抢锁,抢锁成功才能进入编辑模式和提交数据,抢锁失败就只能干着看,等锁释放;另外需要考虑锁超时自动释放问题。

这种方法交互上不太友好,进阶版的做法就是允许其他用户抢锁,例如:开始编辑10分钟内不允许抢锁,但超过10分钟就允许其他用户抢锁

在此基础上,还可以在用户抢锁时,通过websocket通知正在编辑中的用户,即上图中的张三,张三可以选择拒绝或者立即保存退出。

第二类,diff-patch工具,即允许多人同时编辑,在用户提交数据的时候在后端使用diff-patch工具对数据进行对比和合并,尽可能保留每个用户的修改内容;

这种方式在交互上跟非协同编辑没什么区别,数据的对比和合并全交给后端,用户可能并不知道数据有合并过(除非数据合并出问题了)。

diff-patch工具通常包括两个命令:diff命令和apply命令。diff命令用于对比数据A和数据B的差异,产出patch结果(补丁),patch表示数据A如果想转换成数据B,它需要经过的最简操作;apply命令用于将patch应用于指定数据上。所以理论上,用数据A和数据B生成的patch,应用在数据A上,就能得到数据B。

diff-patch的算法/工具有很多,

  1. GNU diff-patch,即Linux/Unix上常用的命令,特点是只能做行级别的对比

  2. JSON diff-patch,针对JSON数据,常用的有 https://github.com/flipkart-incubator/zjsonpatch
  3. Myers diff-patch,针对字符级别的算法

使用JSON diff-patch处理数据冲突流程如下

  • 服务器上需要保留数据每一个版本的副本
  • 客户端提交数据时,需要附带数据的源版本
  • 服务器端对比此数据的当前版本和源版本
  • 如果服务器上当前版本跟源版本一致,则直接覆盖数据,生成一个新版本
  • 如果服务器上当前版本跟源版本不一致,则将此数据和源版本的数据做diff,生成patch,然后将patch应用于当前版本的数据,生成一个新版本

因为缺少人工的干预,diff-patch合并的结果可能不尽人意,特别是同时编辑人数较多时,修改过的内容很可能就被其他人“悄悄地”覆盖了。

第三类,实时操作同步,即实时将用户的操作传递到其他客户端进行合并,这样每个用户都能及时看到其他用户更新的内容,用户可以根据实时的合并结果再进行人为修正。

目前比较流行的有OT算法和CRDT

OT,Operational Transformation,即操作转换,其核心是两个转换函数:transform(client_operation, server_operation) 和 transform(server_operation, client_operation),用于将客户端和服务器端的操作进行合并。OT可以实时性地将多个用户的操作进行合并,确保在不同客户端上的数据始终保持一致,同时也使得协同编辑的体验更加友好。

CRDT,Conflict-free Replicated Data Type,即冲突无关数据类型。与OT类似,CRDT也可以实时地合并多个用户的操作,但OT强依赖中心服务器,而CRDT是在客户端之间互相传递操作,更适合分布式场景。

OT和CRDT都是强调数据的最终一致性,对网络要求较高,网络延迟时会出现数据不符合预期的情况。

总结

如果用户量较少,或者对数据准确性要求极高,可以使用编辑锁方案;

如果有一定用户量,对数据准确性要求一般,可以考虑使用diff-patch方案,然后根据数据格式特点,采用合适的工具;

如果用户量较大,对数据准确性要求也较高,可以考虑使用OT或CRDT方案。

0条评论
0 / 1000