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完全没必要在硬盘中,它可以在内存中(性能又高了一截)。

总结

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

相关推荐
loop lee8 分钟前
Redis - 集合 Set 及代码实战
java·数据库·redis·mysql·算法
Rossy Yan39 分钟前
【数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
数据结构·c++·算法·线性表
eternal__day41 分钟前
数据结构(链表)JAVA方法的介绍
java·数据结构·算法·链表·推荐算法
雅妮yyn2 小时前
数据结构期末算法复习:树、查找、排序
数据结构·算法
东离与糖宝2 小时前
谈谈es6 Map 函数
前端·ecmascript·es6
yasuo562 小时前
前端防抖实现
前端
搏博3 小时前
在优化算法中常见哪些数学函数(根据数学性质分类)
人工智能·算法
柒月的猫4 小时前
蓝桥杯数列求值(2019试题C)
c语言·算法·蓝桥杯
Cachel wood4 小时前
Vue.js前端框架教程4:Vue响应式变量和指令(Directives)
前端·vue.js·windows·python·单元测试·django·前端框架