《Conflict free replicated data types》 阅读笔记。
1. 最终一致性
1.1. Eventual Consistency
一个分布式系统是最终一致的,需满足以下条件:
- Eventual delivery: 在健康节点上执行的更新操作最终会被传递至所有健康节点,也就是说 f∈ci⇒◊f∈cj,∀i,j∈[1,…,n]f∈ci⇒◊f∈cj,∀i,j∈[1,…,n],其中 cici 是节点 pipi 的 causal history
- Convergence: causal history 相同的健康节点最终会收敛至相同的状态,也就是说 ◻ci=cj⇒◊◻si≡sj,∀i,j∈[1,…,n]□ci=cj⇒◊□si≡sj,∀i,j∈[1,…,n]
- Termination: 所有操作会终止
在上述说明中,◊◊ 表示 eventually,◻□ 表示 always,详见 Temporal logic。至于 causal history,可以理解为该节点已执行操作的集合。
1.2. Strong Eventual Consistency
一个分布式系统是强最终一致的,需在满足最终一致的条件下,额外满足以下约束:
- Strong Convergence: 执行相同操作集合的健康节点具有相同的状态,也就是说 ci=cj⇒si≡sj,∀i,j∈[1,…,n]ci=cj⇒si≡sj,∀i,j∈[1,…,n]
PS: 最终一致性只包含 liveness guarantee,而强最终一致对系统的中间状态进行了约束 (safety guarantee)
2. 系统模型
2.1. 符号说明
符号 | 含义 |
---|---|
pipi | process ii |
sisi | process pipi has state si∈Ssi∈S, called its payload |
s0s0 | 初始状态 |
query | |
tt | prepare-update |
uu | update |
mm | merge |
PP | communication protocol |
fki(a)fki(a) | 在节点 pipi 上执行的 kthkth 操作, ff 是 qq, uu 或 mm, aa 是参数 |
Ki(f)Ki(f) | 在节点 pipi 上操作 ff 执行的序数 |
2.2. State-based Convergent Replicated Data Type(CvRDT)
Causal History
我们定义一个对象的 causal hisatory(stated-based) 为 C=[c1,…,cn]C=[c1,…,cn],其中 cici 经历了一系列中间态 c0i,…,cki,…c0i,…,cki,…。初始时,c0i=∅,∀i∈[1,…,n]c0i=∅,∀i∈[1,…,n],在节点 pipi 上执行的 kthkth 操作分为以下三种情况:
cki={ck−1i,f=qck−1i∪{uki(a)},f=uki(a)ck−1i∪ck′i′,f=mki(sk′i′)cki=⎧⎪ ⎪⎨⎪ ⎪⎩ck−1i,f=qck−1i∪{uki(a)},f=uki(a)ck−1i∪ck′i′,f=mki(sk′i′)
Monotonic semilattice object
我们用 (S,≤,s0,q,u,m) 表示基于状态的对象,其中 ≤ 表示 partial order。若其满足以下约束,我们称其为 monotonic semilattice object:
- Poset (S,≤) 构成一个 Join-semilattice
- Merge 操作满足: s⋅m(s′)=s∨s′
- 在更新操作下状态 s 满足单调性,即 s≤s⋅u
回顾之前的知识,可以知道第 1 条约束的意思是集合 S 中任意非空子集都有 join
,第 2 条约束说明 merge 即为 join
。
CvRDT
Assuming eventual delivery and termination, any state-based object that satisfies the monotonic semilattice property is SEC.
CvRDT 使用 (S,≤,s0,q,u,m) 表示。
从上可以看出,在 CvRDT
中, 需要满足以下条件:
- 状态满足单调性,消息最终可达
- 状态更改操作为 Merge 需满足交换律,结合律,幂等
2.3. Op-based Commutative Replicated Data Type(CmRDT)
Causal History
我们定义一个对象的 causal hisatory(op-based) 为 C=[c1,…,cn],其中 ci 经历了一系列中间态 c0i,…,cki,…。初始时,c0i=∅,∀i∈[1,…,n],在节点 pi 上执行的 kth 操作分为以下两种情况:
cki={ck−1i,f=q,tck−1i∪{uki(a)},f=uki(a)
Happened-before
Update (t,u) happended-before (t′,u′) iff the former is delivered when the latter executes: (t,u)→(t′,u′)⇔u∈ck−1j, where t′ executeds at pj and k=Kj(t′).
Commutativity
Updates (t,u) and (t′,u′) commute, iff for any reachable replica state s where both u and u′ are enabled, u (resp. u′) remains enabled in state s⋅u′(resp. s⋅u), and s⋅u⋅u′≡s⋅u′⋅u.
CmRDT
Assuming causal delivery of updates and method termination, any op-based object that satisfies the commutativity property for all concurrent updates, and whose delivery precondition is satisfied by causal delivery, is SEC.
CmRDT 使用 (S,s0,q,t,u,P) 表示。
从上可以看出,在 CmRDT
中, 需要满足以下条件:
- Update 操作要么可确定明确的因果顺序,要么满足可交换
- 消息传输提供
exactly once
的保证
3. 一些结论
- CvRDTs and CmRDTs are equivalent
- SEC is incomparable to sequential consistency
4. CRDT 示例
4.1. Counters
我们使用 CvRDT 的框架来构造一个分布式计数器 (S,≤n,s0,value,inc,maxn):
符号 | 含义 |
---|---|
S | 状态集合,其中 s=→v=[v1,…,vn] 表示计数器的状态 |
≤n | →v≤n→v′⇔vi≤v′i,∀i∈[1,…,n] |
s0 | [0,…,0] |
value | value(→v)=∑ivi |
inc | 在节点 pi 上 inc(→v)=→v′,其中 $v'i = v_i + 1 \cdot \mathbb{I}{\{j\}}(i), \forall i \in [1, \dots, n]$ |
maxn | s⋅maxn(s′)=[max(v1,v′1),…,max(vn,v′n)] |
可以发现上述定义的是一个只增计数器,如果想可增可减的话,可以使用两个只增计数器构成。
4.2. Set
一个 add-only 的集合可以构造为 (S,⊆,∅,value,add(e),∪),其中 s⋅add(e)=s∪{e},很明显这也是一个 CRDT。
在 A comprehensive study of Convergent and Commutative Replicated Data Types 中作者定义了可增可减的两种 Set,但是也有较强的 assumption…
- 2P-Set:维护两个集合:add-only 和 remove-only。只能适用于集合中的元素只会被 add/remove 一次的情况
- U-Set: 维护一个支持 add/remove 的集合。需要满足两个条件:
- remove 过的元素不会再 add
- add 操作确保在 remove 前