您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

这一次,彻底搞懵 CRDT

时间:2024-05-15 13:33:30  来源:微信公众号  作者:前端西瓜哥

我是前端西瓜哥,今天我们来简单入门一下 CRDT。

CRDT 是什么?

CRDT,全称为 conflict-free replicated data type(无冲突复制数据类型),它是一种数据类型,或者说是方案,确保在网络中的不同副本最后数据保持一致的,可以用协同编辑领域。

CRDT 在 2011 年在论文中被正式提出,虽相比 OT 算法(1989年)起步晚了很长的时间,但实现难度低很多,且出现了高性能的 CRDT 库 Y.js,越来越多产品选择使用 CRDT 来实现协同编辑功能。

CRDT 有以下特性:

每个客户端可独自操作副本,即支持并发,不需要和其他副本协同沟通。

这是一种乐观复制(Optimistic replication)的策略。

各个副本可以独立地在本地编辑,不用把更新提交到服务器,等待服务端返回最新的状态,用这个新状态覆盖掉旧状态。即可做到离线编辑,本地更新了状态后再同步到服务端。

算法能够自动地处理不一致的问题。

一个副本和另一个副本通常是不同的,当其他副本同步过来时,有可能会出现冲突(不一致)的地方,比如两个副本同时删除和新增一个元素。

这个需要 CRDT 算法使用特定的策略去自动处理,而不是像 git merge 那样去手动处理冲突。

同一时刻不同副本的状态可能不同,但同步后它们能最终收敛(converge),达到相同的状态(最终一致性)。

CRDT 的类型

CRDT 主要分为两大类型:Operation-based 和 State-based。

Operation-based

Operation-based CRDTs,基于操作的 CRDT。

副本进行同步时,只会把 新增的本地操作(operation) 发送出去。

另一个副本拿到这个 operation 会将其应用到自己的状态上,operatAIon 需要满足交换律(commutative)。

交换律,指的是交换运算顺序,最后的结果不变。比如加法就满足交换律,a+b 和 b+a 的结果是相等的。

operataion 之所以要满足交换律,是因为网络并不可知。

假设有两个副本 a 和 b 要同步过来给其他副本,你不知道到底谁先到达。对于一些副本可能是先 a 后 b,另一些可能是先 b 后 a,我们需保证在不同顺序下,结果是一致的。

通常我们是通过 Generator 函数生成新的 opreation,发送给其他副本,然后这些副本通过  Effector 函数应用这些副本。

因为交换律这个特性,Operation-based CRDTs 还有另一个名字 commutative replicated data types(CmRDTs)。

基于操作的 CRDT 的优点是, 传输的数据量较少。

State-based

State-based CRDTs,基于状态的 CRDT。

一个副本进行同步时,会将 整个完整的本地状态(state) 发送出去。另一个副本需要支持将其他副本进行合并(merge)的操作,这个 merge 方法需要满足交换律、分配律,以及幂等性。

基于状态的 CRDT 的问题是,在文档很大时,需要传输大量的数据,会耗费大量的带宽,且花费时间长。所有实际生产很少会使用它。

优点是实现更简单,如果数据量不大,是可以考虑使用的。

State-based CRDTs 同样也有另一个名字:Convergent Replicated Data Types(CvRDTs)。Convergent 是收敛的意思。

一些 CRDT

CRDT 做到数据最终一致性,是基于数学上的特性来保证的。

我们来看几个简单的 CRDT 模型。

AWSet

AWSet(Add-wins set),一种新增优先于删除的集合数据结构。

假如刚开始的时候,副本 A 和 副本 B 的状态是一致的,有一个 a 在集合中。

副本 A 删除了 a,然后再新增 a。

副本 B 删除了 a。

副本 A 的新增 a 和 副本 B 的删除 a 同时发生。

此时我们会选择新增,忽略删除,最后两个副本的状态还是 a 在集合中。

为判断两个操作是否是 “同时” 的,我们会附加一个和时序相关的元数据,比如时间戳、版本向量。

RWSet

RWSet(Remove-win set),一种删除优先新增的集合数据结构。

AWSet 类似,但对于并发的操作,会保留删除,丢弃新增。

LWW

LWW(Last-writer-wins),最后写入者优先。

所有的操作会有一个时间戳元数据,副本会对比同步操作的时间戳。

如果大于当前状态时间戳,覆盖掉原来的状态;如果小于当前状态时间戳,则忽略。

2P-Set

Two-Phase Set。

此模型会维护两个集合,一个是新增集合,保存新增的元素,另一个是删除集合,保存被删除的元素。

模型的最终状态为新增集合和删除集合的差集。

另外,集合比较特殊,它是只增集合(grow-only set),只能往集合里加元素,不能从集合里移除元素。

这意味着一个元素如果被删除了,就再也不能添加回来。所以删除集合也被叫做 tombstone set(墓碑集合),人噶不能复生。

2P-Set 也算是一种 RW-Set(删除优先),特别的点在于元素被删除后不能新增回来。

G-Counter

G-Counter,Grow-only Counter,只增计数器,一个只能增加计数的计数器。

此模型使用 n 个节点的容器(一个整数数组),每个副本会分配一个 id,某个副本给计数器 +1,其实就会给对应的数组元素 +1。

计数器的值为数组的求和。

PN-Counter

PN-Counter,Positive-Negative Counter,一个支持增减的计数器。

多个 CRDT 可以组合成一个更复杂的 CRDT。

类似 G-Counter,但 PN-Counter 使用两个 G-Counter,一个保存新增数(新增操作),另一个保存减少数(减少操作)。

计数器的值为新增数组求和减去减少数组的和。

YATA

最后我们看看复杂点的,简单介绍一下 Y.js 的 YATA(Yet Another Transformation Approach)模型。

假设我们有值为 "ABCD" 的字符串。

YATA 模型会将其拆分成一个个字符,加上元数据,然后按顺序首尾相连组成一个双链表。

// 大概这样子
{
  id: '2:0', // 客户端 ID + clock ID
  val: 'B',
  left: a, // 当前节点的左节点
  right: c, // 右节点
  origin: a, // 节点创建时的左节点
  rightOrigin: c // 节点创建时的右节点
}

操作有 “插入” 和 “删除”。

假设本地在 AB 之间插入 E,此时没有发送同步,然后收到其他副本传过来的 F,也是要插入到 AB 之间。

此时 E 和 F 是冲突的,我们会对唯一的 id(某种意义上的时间戳)使用特定的规则来决定先后顺序。

至于删除操作,因为插入操作需要找到在左右节点的位置,所以节点即使被删除了也是不能从双链表中移出的。

对此,YATA 选择使用墓碑机制。YATA 将对应节点标记为删除(item.deleted 设置为 true),并将节点记录到删除集合 DeleteSet 里。

这里其实可以看到,CRDT 通常是需要加很多元数据的,尤其是复杂数据结构且数据量较大的场景,所以这也是 CRDT 起初被诟病占用内存高的原因。

但 Y.js 通过一系列手段(比如将多个节点合并为一个大节点),将性能优化到足够面对大多数场景,证明了用 CRDT 是做协同编辑的是不用担心性能问题的,如果有,一定是你没优化好。

结尾

本文只是简单介绍一些 CRDT 是什么,并感受了一些简单的 CRDT 模型,希望对你有所帮助。



Tags:CRDT   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
这一次,彻底搞懵 CRDT
我是前端西瓜哥,今天我们来简单入门一下 CRDT。CRDT 是什么?CRDT,全称为 conflict-free replicated data type(无冲突复制数据类型),它是一种数据类型,或者说是方案,确保在网络中的...【详细内容】
2024-05-15  Search: CRDT  点击:(0)  评论:(0)  加入收藏
▌简易百科推荐
这一次,彻底搞懵 CRDT
我是前端西瓜哥,今天我们来简单入门一下 CRDT。CRDT 是什么?CRDT,全称为 conflict-free replicated data type(无冲突复制数据类型),它是一种数据类型,或者说是方案,确保在网络中的...【详细内容】
2024-05-15  前端西瓜哥  微信公众号  Tags:CRDT   点击:(0)  评论:(0)  加入收藏
Jenkins+Ansible+Gitlab 自动化部署三剑客
在快节奏的软件开发和运维环境中,自动化部署成为了提高效率、减少错误的关键环节。Jenkins、Ansible和GitLab作为自动化部署领域的佼佼者,被广大开发者亲切地称为“自动化部署...【详细内容】
2024-04-29  土豆切切切    Tags:自动化   点击:(7)  评论:(0)  加入收藏
什么是云原生,有哪些技术选型?
云原生(Cloud Native)是一种构建和运行应用程序的方法论,它代表着一种充分利用云计算模型的设计思想和工程实践。在云原生架构下,应用从设计之初就考虑到在分布式系统和云环境中...【详细内容】
2024-04-29  JaneYork    Tags:云原生   点击:(6)  评论:(0)  加入收藏
监控 Kafka,这十个指标请考虑!
使用消息队列可以帮助我们实现系统解耦、流量管控等功能。但使用过程中可能会遇到各种各样的问题,比如系统资源使用率高、集群节点宕机等,进而影响我们生产业务正常开展。为了...【详细内容】
2024-04-29  君哥聊技术  微信公众号  Tags:Kafka   点击:(15)  评论:(0)  加入收藏
引入缓存竟然会带来这么多问题?
哈喽,大家好呀,我是呼噜噜,最近很忙好久没更新了,今天我们通过缓存与数据库之间的一致性这个老生常谈的问题来切入,聊聊如何合理的设计一个缓存系统?如今互联网应用,无论是web还是...【详细内容】
2024-04-29  小牛呼噜噜  微信公众号  Tags:缓存   点击:(11)  评论:(0)  加入收藏
对DevOps的九大误解,是时候纠正了!
DevOps是开发和运维的结合,有助于集成和自动化测试过程以及部署存储库,还提供了透明度以及灵活性。DevOps的目标如下: 更快的上市时间(TTM); 减少各种修复之间的前置时间; 提高部...【详细内容】
2024-04-26  陈哥聊测试    Tags:DevOps   点击:(8)  评论:(0)  加入收藏
五种搭建LLM服务的方法和代码示例
在不断发展的大型语言模型(LLMs)领域中,用于支持这些模型的工具和技术正以与模型本身一样快的速度进步。在这篇文章中,我们将总结5种搭建开源大语言模型服务的方法,每种都附带详...【详细内容】
2024-04-23  DeepHub IMBA    Tags:LLM   点击:(15)  评论:(0)  加入收藏
DevOps已死?2024年的DevOps将如何发展
随着我们进入2024年,DevOps也随之发生变化。新兴的技术、变化的需求和发展的方法正在重新定义有效实施DevOps实践。IDC预测显示,未来五年,支持DevOps实践的产品市场继续保持健...【详细内容】
2024-04-17  陈哥聊测试    Tags:DevOps   点击:(9)  评论:(0)  加入收藏
Meta如何将缓存一致性提高到99.99999999%
介绍缓存是一种强大的技术,广泛应用于计算机系统的各个方面,从硬件缓存到操作系统、网络浏览器,尤其是后端开发。对于Meta这样的公司来说,缓存尤为重要,因为它有助于减少延迟、扩...【详细内容】
2024-04-15    dbaplus社群  Tags:Meta   点击:(9)  评论:(0)  加入收藏
SELECT COUNT(*) 会造成全表扫描?回去等通知吧
前言SELECT COUNT(*)会不会导致全表扫描引起慢查询呢?SELECT COUNT(*) FROM SomeTable网上有一种说法,针对无 where_clause 的 COUNT(*),MySQL 是有优化的,优化器会选择成本最小...【详细内容】
2024-04-11  dbaplus社群    Tags:SELECT   点击:(8)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条