CRDT宝典 - Delta-state AWOSet

背景

看完AWORSet,它有一个致命的缺点:元信息很大,大到远超数据本身,比如

ts 复制代码
A.AWORSet = [
    {
        'element1': {
            [A.id]: 1,
            [B.id]: 2,
            [C.id]: 5,
            [D.id]: 1,
            [E.id]: 8,
            [F.id]: 3,
            [G.id]: 7,
            [H.id]: 4,
            [I.id]: 9,
            [J.id]: 2,
            [K.id]: 6,
            [L.id]: 5,
        },
    },
    {
    }
]

我们为了表示出不同节点添加element1的操作,其元数据本身远远超过了element1本身,这是我们不能容忍的,这会导致以下的问题

  1. 不同节点的CRDT需要将自身的整个CRDT推送到远端用于合并,这数据量太大了
  2. 合并CRDT时,耗时太长了

我们需要一个减少元数据的方式

思维链

flowchart A["1. 每个节点都会间隔性地拉取远端节点的AWORSet,然后和自身的AWORSet进行合并,\n合并后的结果会覆盖掉原来的AWORSet。\n同样也会间隔性的将自身的AWORSet推送到远端节点,用于同步。"] A --> B["2. 同时,节点自身会产生许多对AWORSet的操作。\n`记住,这些操作只代表该节点对AWORSet的操作`"] B --> C["3. 我们聚焦节点A,其实它只需要将自身对AWORSet产生的增删操作同步出去就可以了,\n我们完全可以用delta来表达这些操作"] C --> D["4. 很明显,delta = `添加集` + `删除集` = 一个AWORSet,\n所以将delta合并到AWORSet中 = 两个AWORSet的合并"] D --> E["5. 通过delta的方式,我们能很显著的解决`背景`里提出的两个问题"]

实现

这个CRDT如下,我们称之为Delta-state-AWORSet,我们简称一下:Delta-AWORSet

ts 复制代码
A.Delta-AWORSet = {
    values: [
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
            'element3': {
                [A.id]: 1,
                [B.id]: 2
            },
        },
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
        }
    ],
    delta:[
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
        },
        {
            'element2': {
                [A.id]: 1,
            },
        }
    ]
}

代表节点从上一次同步delta后,进行了新增element1删除element2的操作

某个节点添加元素,比如A节点添加了element1,即A.Delta-AWORSet.delta.add(element1),并且A.Delta-AWORSet.values.add(element1)

某个节点删除元素,比如A节点删除了element2,即A.Delta-AWORSet.delta.remove(element2),并且A.Delta-AWORSet.values.remove(element2)

某个节点的Delta-AWORSet的值,是A.Delta-AWORSet.values.value()

同步其他节点的Delta-AWORSet,比如将B节点的Delta合并到A节点中,只需要将A.Delta-AWORSet.values.merge(B.Delta-AWORSet.delta)

合并两个Delta-AWORSet,比如合并A.Delta-AWORSet和B.Delta-AWORSet,只需要将A.Delta-AWORSet.values.merge(B.Delta-AWORSet.values),且A.Delta-AWORSet.delta.merge(B.Delta-AWORSet.delta)

代码如下(伪代码):

ts 复制代码
A.Delta-AWORSet:<{values: AWORSet, delta: AWORSet}> = {
    values: [
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
            'element3': {
                [A.id]: 1,
                [B.id]: 2
            },
        },
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
        }
    ],
    delta:[
        {
            'element1': {
                [A.id]: 3,
                [B.id]: 2
            },
        },
        {
            'element2': {
                [A.id]: 1,
            },
        }
    ]
}

// 添加元素的代码示例
function addElement(node: Delta-AWORSet, element) {
    node.values.add(element);
    node.delta.add(element);
}

// 删除元素的代码示例
function removeElement(node: Delta-AWORSet, element) {
    node.values.remove(element);
    node.delta.remove(element);
}

// 值的获取
function getValue(node: Delta-AWORSet) {
    return node.values.value();
}

// 同步其他节点的Delta
function mergeDelta(node: Delta-AWORSet, delta: Delta-AWORSet) {
    node.values.merge(delta.values);
}

// 合并两个Delta-AWORSet的代码示例
function mergeDelta(node: Delta-AWORSet, delta: Delta-AWORSet) {
    node.values.merge(delta.values);
    node.delta.merge(delta.delta);
}

QA

问:都有delta了,为什么还需要合并两个Delta-AWORSet?

答:因为你业务决定的,可能会存在需要全量同步的需求。

问:为什么合并别的节点的delta的操作里,只需要合并values,不需要合并delta?

答:你问到delta的精髓了,A.Delta-AWORSet.delta代表着A节点对Set的操作,而这个操作绝对是最新的(无论是离线还是在线,且别的节点里不可能有比这个delta还新的操作,因为A节点是A.Delta-AWORSet.delta的唯一产生者),也就算说即便A.Delta-AWORSet.values合并了别的节点的delta,A.Delta-AWORSet.delta里的操作也能保证是最新的。

问:什么时候delta可以重制

答:看业务,比如A节点将自身的delta同步出去后就可以重制delta了,因为这代表着A对Set的操作都同步出去了,没必要保留delta了。对,所以delta完全没必要在硬盘中,它可以在内存中(性能又高了一截)。

总结

很复杂,需要看好几遍,有问题的评论区见

相关推荐
九.九2 分钟前
CANN HCOMM 底层机制深度解析:集合通信算法实现、RoCE 网络协议栈优化与多级同步原语
网络·网络协议·算法
夏幻灵7 分钟前
CSS三大特性:层叠、继承与优先级解析
前端·css
C++ 老炮儿的技术栈10 分钟前
Qt Creator中不写代如何设置 QLabel的颜色
c语言·开发语言·c++·qt·算法
杜子不疼.13 分钟前
CANN集合通信库HCCL的大规模分布式训练通信优化与拓扑感知实践
分布式
子春一20 分钟前
Flutter for OpenHarmony:构建一个 Flutter 数字消消乐游戏,深入解析网格状态管理、合并算法与重力系统
算法·flutter·游戏
小杨同学呀呀呀呀24 分钟前
Ant Design Vue <a-timeline>时间轴组件失效解决方案
前端·javascript·vue.js·typescript·anti-design-vue
草履虫建模7 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
华玥作者9 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
naruto_lnq9 小时前
分布式系统安全通信
开发语言·c++·算法
Mr Xu_9 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js