背景

atom 编辑器新增一个 teletype 的功能,可以实现多人在线编辑代码。效果看起来挺炫酷,想了解一下是怎么实现的,于是研究了一下。

抽象一下文本文档的协同编辑这个问题,就是同步多个设备之间的操作合并,最后都能达到最终一致的结果。现在解决文本文档的协同编辑有两种方案,一种是 Google Doc 使用的 Operational transformation (OT),还有一种就是 Atom teletype 使用的 Conflict-free replicated data type (CRDT)。

Operational transformation (OT)

Operational transformation 翻译过来就是操作转化,流程也是分为两个部分操作和转换。

Operational 操作

将设备的编辑转换成操作(Operational),发送到服务端。

insert(index, char)
delete(index, char)

transformation 转换

装换是为了确保不同设备的操作,同步到其他设备的时候,最后会得到一致的结果。服务端接受 Operational,转换Operational,发送到对应客户端,客户端合并操作,得到一致结果。

Conflict-free replicated data type (CRDT)

CRDT 翻译过来就是无冲突可复制数据类型。

CRDT 有两种形式:

  • 基于状态:即将各个节点之间的CRDT数据直接进行合并,所有节点都能最终合并到同一个状态,数据合并的顺序不会影响到最终的结果。
  • 基于操作:将每一次对数据的操作通知给其他节点。只要节点知道了对数据的所有操作(收到操作的顺序可以是任意的),就能合并到同一个状态。

CRDT 必须符合可交换性,结合性,还有幂等性,所以 CRDT 数据类型合并最终会收敛到相同状态。为什么要符合可交换性,结合性,还有幂等性三个特性呢?因为可以解决分布式达到最终一致会遇到的问题:

  • 网络问题导致发送接收顺序不一致(幂等性)
  • 以及多次发送(可交换性)

OT 和 CRDT 区别

OT主要用于文本,CRDT 不仅仅应用在协同编辑,还有分布式系统的最终一致性上也有应用。OT操作必须通过服务器的转换才可以合并,而 CRDT 由于其数据结构特性,不通过服务器也可以合并。

CRDT 实现协同编辑

为什么选择 CRDT,因为 OT 中的 transformation 流程太复杂,OT 概念不是很清楚,而 CRDT 很好理解,实现起来也不难。

Lamport timeStamp

在因果关系的事件需要知道事件的先后顺序,并且能够按照正确的顺序处理这些事件,所以需要 Lamport timeStamp 来确定事件发生的事件,Lamport timeStamp 只需要保证两个规则就好了。

newTimeStamp[local] = Max(timeStamp[local], timeStamp[receive])
​
newTimeStamp[local] = timeStamp[local] + 1

  • 本地 Lamport timeStamp 为收到事件的 Lamport timeStamp 和本地 Lamport timeStamp 中最大值
  • 生成事件 Lamport timeStamp 时候加一就可以了。

UUUID

每个客户端都有一个唯一 UUUID,再加上 Lamport timeStamp 就可以为每个操作添加唯一可排序的 ID。

因果树

每个操作都有唯一的 ID,接下来就是定义操作的数据结构,并且符合 CRDT 的特性,ID的唯一性可以保证操作的幂等性,操作可以排序保证了交换性,接下来只要保证每个操作都可以被合并就可以了。

id U0@T1 insert 'a' at index 0
id U0@T2 insert 'b' at index 1
id U0@T3 insert 'c' at index 2
id U0@T4 delete 'c' at index 2
id U0@T5 delete 'd' at index 2

一般会这样定义操作,但是这样的操作是线性依赖的,每个操作都是依赖前一个操作的结果,并发的时候,必须确保执行的顺序是一致的,有些操作可能合并会得到不一致的结果。

id U0@T1 insert 'a' at id null
id U0@T2 insert 'b' at id U0@T1
id U0@T3 insert 'c' at id U0@T2
id U0@T4 delete 'c' at id U0@T3
id U0@T5 insert 'd' at id U0@T2

其实每个操作的 ID,就可以作为这个字符的 ID,这样可以将每次操作的依赖定位到之前的字符,这样仅仅只依赖单个字符,而不是之前的依赖前一个操作的结果,即是并发也可以合并,其中比较特殊的操作就是删除操作,删除操作只是将字符使用墓碑标记为删除,并不真的删除,这是防止一个设备删除了字符,而其他设备依然依赖,而导致操作不可合并。这样的数据结构就是有操作依赖生成的一颗 因果树。要获取显示的字符,只要深度遍历树就可以得到。数据结构明确了以后前后端实现就很方便了。

前端实现

  • 前端接受服务器生成的初始 UUUID , Lamport timeStamp,actions,初始化前端状态。
  • 前端接受用户输入,产生初始操作,比如 index 10 insert 'a'在位置10插入字母a,之后通过位置 10 深度遍历因果树,找到操作依赖字母的 id,并且生成操作 id,生成操作,然后发送到服务器。
  • 前端接受服务器广播操作,更新前端 timestamp,插入因果树,生成最新字符串,更新前端状态。

服务端实现

服务端实现就比较简单了,只要提供 UUUID 还有 Lamport timeStamp 生成,还有就是接受客户端的操作,并且广播给其他客户端,因为后端使用 node 写的,还可以和前端公用一部分代码,实现就更方便。

结语

crdt-edit​github.com

这是我自己从零实现的一个文本文档的协同编辑demo,上面是输入框,下面是数据结构的可视化。

参考

因果树和 CRDT 数据结构

xi编辑器 CRDT 引擎实现

atom teletype 博客

Google Doc OT wiki

OT 原理详解

因为某种原因阻止文本引擎初始化_文本文档的协同编辑实现相关推荐

  1. 因为某种原因阻止文本引擎初始化_网络营销外包——网络营销外包专员如何做好网站锚文本优化?...

    在网站优化工作进行期间站长们可以通过多种方式来完成优化工作,但是如果真的想要提高网站的基本排名还是需要考虑对网站锚文本得优化,毕竟只有选择正确的锚文本才能真的帮助站长们实现排名的迅速优化.那么站长们从 ...

  2. Photoshop:不能完成请求因为某种原因阻止文本引擎进行初始化

    ps软件有时会出现 "不能完成请求  因为某种原因阻止文本引擎进行初始化" 的错误.乍看起来不知道怎么回事.其实, 这是由于ps不支持你当前选中的字体,换个字体就好了.

  3. 无法完成请求,因为某种原因阻止文本引擎进行初始化

    PS: 无法完成请求,因为某种原因阻止文本引擎进行初始化 最近ps突然报错如下图: 在查阅大量解决办法后,总结如下: 方法一: 如果,完美解决则忽略下面内容. 方法二: 将PS字体改为常用的,如宋体等 ...

  4. axure原型怎么让文字自动换行_文本文档怎么创建_文本文档怎么自动换行的方法...

    在处理各种工作的时候,文本文档都是比较常见的使用工具,尤其在电脑工作者的日常工作中,这些都是不可或缺的,经常需要保存一些临时的文档或者是文本文件,那么在保存的时候要选择先建立文本文档,那么文本文档怎么 ...

  5. 在线文本文档txt编辑器_审查了6位在线文档和文本编辑者

    在线文本文档txt编辑器 Who wants to limit himself to one computer nowadays? Say hello to online editors, where ...

  6. linux编辑文档windows,1.9vim编辑器linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是...

    1.9vim编辑器 linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是用命令去操作 这个工具分为三种模式:命 ...

  7. python怎样输出多个空格_请教文本去重的方法,另外python 打印文本文档开头多了个空格...

    本意是想把打开的文本文件存到List里,类似以下斜体的记录有很多条,想去掉其中重复的.用set也是一样的结果. *RT Journal Article SR 1 A1 孔令婕;巢建国;谷巍;张莹;刘晓 ...

  8. python读取文本文档内容并存入列表内_【Python基础】文本文件读写

    作者: eavea 发表日期: 2020年04月14日 分类: 后端技术 标签: Python 阅读次数: 3,358 评论数: 0 条 [Python基础]文本文件读写 Python中常用文件读写方 ...

  9. bat 删除文件_利用电脑文本文档建立一个简单方便的删除文件的小程序

    删除文不需要的文件或者资料,是日常工作中必定会遇到了. 各种的杀毒软件或者防护软件都具备删除文件的功能,例如360.腾讯电脑管家.这些操作起来其实也不是太麻烦! 不过呢!今天来和大家分享一个更简单的方 ...

最新文章

  1. Pandas库常用函数和操作
  2. mysql proxy 读写分离 1
  3. 湖南师范大学c语言作业答案,2017年湖南师范大学物理与信息科学学院845C语言程序设计考研题库...
  4. java什么数组能村浮点数_c脚本怎样把字节数组转换成浮点数
  5. django 中的render和render_to_response()和locals()
  6. 音频光端机的几个重要指标
  7. 在VS中安装/使用 MVVMLight
  8. 8.FreeRTOS学习笔记-软件定时器
  9. 【Kafka】Kafka Schema Registry 原理
  10. Python入门--二重循环中的continue和break
  11. (1)深度学习_梯度下降与优化
  12. iis在xp3上的部署
  13. 安全培训教程之------利用IIS写权限漏洞
  14. limesurvey php5.2,Limesurvey二次开发(接入CAS统一身份认证)随笔
  15. C语言生命游戏源代码
  16. b站pink老师JavaScript的DOM案例代码——模拟京东快递单号查询
  17. related_name/related_query_name的区别
  18. A Comprehensive Measurement Study of Domain Generating Malware 原文翻译
  19. Millet谷仓:新型电商势在必行
  20. 个人资源小仓库之【工具】!

热门文章

  1. ESP8266-Arduino编程实例-LPS22HB绝压传感器驱动
  2. 店铺爆款是如何打造成功的
  3. 数列极限存在准则:夹逼准则
  4. 飞行棋(士) [窗口 控制台 自定义 版] 附源码
  5. java计算机毕业设计汽车客运站票务管理系统源码+程序+lw文档+mysql数据库
  6. 你的软件真的卸载干净了吗?最全最高效的卸载工具推荐
  7. cloudera时钟同步
  8. 那些离不开的 Chrome 扩展插件
  9. Python爬取双色球数据进行分析
  10. (翻译++)微软Hololens开发教程系列(1): Holograms 100-使用Unity构建第一个全息影像应用