一、概述
原子广播是一种消息传递广播方式,他可以保证在这个系统中,所有的节点收到的消息顺序是一致的。
可见,这种协议需要保证【Hadzilacos and Toueg 1994, Chandra and Toueg 1996】:
- (VALIDITY) If a correct process TO-broadcasts a message m, then it eventually TO-delivers m.
- (UNIFORM AGREEMENT) If a process TO-delivers a message m, then all correct processes eventually TOdeliver m.
- (UNIFORM INTEGRITY) For any message m, every process TO-delivers m at most once, and only if m was previously TO-broadcast by sender(m)
- (UNIFORM TOTAL ORDER) If processes p and q both TO-deliver messages m and m0, then p TO-delivers m before m0 if and only if q TO-delivers m before m0.
二、Zookeeper
paper地址:Zab: High-performance broadcast for primary-backup systems
符号定义与解释
𝚷:{p1,p2,....,pn} 所有的节点集合
𝛒:leader,𝛒(i)表示第i个leader 。
transaction:一个transaction分为两个部分,数据域v,版本域zxid,下文中用<v,z>表示transaction
zxid:包含两个部分 纪元epoch跟这个纪元下的counter
【消息M≺N当且仅当 epoch(M)<epoch(N) || (epoch(M)=epoch(N) && counter(M)< counter(N)) || (epoch(M)=epoch(N) && counter(M)== counter(N) && myid(M)<myid(N))
论文上没有myid(M)<myid(N),工程实践上会为每个节点分配一个myid】
定义:
- ∀Q⊆𝑄:Q⊆𝚷
- ∀Q1,Q2⊆𝑄:Q1∧Q2≠∅
则𝑄称为法定投票集。
性质:
- Integrity: 对于p(j),如果接收到了消息M且M.from=i,那么p(i)必然发送过M。
- Prefix: 如果p(j)接收到了一个消息M(i,j),对于消息N(i,j) happen before M(i,j),那么p(j)会在接收M之前接收到N 。
- Single iteration:对于p(i),p(j)的通信缓存,至多只有一轮算法迭代的的消息。
性质1表明,算法不能捏造报文。依赖于算法跟通信方式
性质2约束了消息不能乱序
zookeeper采用了primary-backup的主备模型
使用这个模型,zab重新定义了上述性质
total order:If some process delivers <v,z> before <v',z'>, then any process that delivers <v',z'> must also deliver <v,z>, and deliver <v,z> before <v',z'>,
Agreement:If some process p(i) delivers <v,z> and some process p(j) delivers <v',z'>, then either p(i) delivers<v',z'> or p(j) delivers <v,z>
如果仅保证全序关系,可能存在不同的节点数完全不一致,Agreement让消息不要出现分叉
对于leader节点,定义性质如下
Local primary order:If a primary broadcasts <v,z> before it broadcasts <v',z'> then a process that delivers <v',z'> must also deliver <v,z> before <v',z'>
Global primary order: Let <v,z> and <v',z'> be as follows:
- A primary ρ(i) broadcasts <v,z>
- A primary ρ(j), ρ(i) ≺ ρ(j), broadcasts <v',z'>
If a process p(i) ∊ Π delivers both <v,z> and <v',z'>, then p(i) must deliver <v,z> before <v',z'>
简而言之:同一个纪元的消息是有序的,不同纪元之间的消息也是有序的(先被broadcast的消息,先被投递)
假设我们 Local primary order可以实现,通过local order怎么实现global order。引入下面的定义
Primary integrity :If a primary ρ(e) broadcasts <v,z> and some process delivers <v',z'> such that <v',z'> has been broadcast by ρ(e'), e' < e, then ρ(e) must deliver <v',z'> before it broadcasts <v,z>。 这一点工程实践很容易实现(参见选主算法的phase2的最后一步)
zab算法的流程参照(论文跟具体实现有差异,但基本性质保持不变)
简要说明。第一阶段用来预选epoch, 第二阶段建立预选leader,第三阶段建立leader,开始广播消息。
- f(p) Last new epoch proposal follower f acknowledged
- f(a) Last new leader proposal follower f acknowledged
- h(f) History of follower f
- f(zxid) Last accepted transaction identifier in hf
预选epoch: follower: 给假想的leader发create_epoch(f.p)消息。
leader:在接收到一个满足法定投票集所发来的create_epoch(e)后,给这个集合中的所有follower发送new_epoch(e')消息, e'大于他所收到的所有create_epoch中的纪元号
follower:一旦收到new_epoch(e'),则查看自己的f(p),如果f(p)<e',则f(p)=e'并且给出ack
leader:一旦收到这个法定投票集的所有的follwer的应答, leader选取一个transaction编号最大的h作为e'的初始化数据。
预选leader: leader:发送new_leader(e') 给这个法定投票集
follower:一旦收到new_leader(e') ,如果f(p)!=e',开启新一轮迭代 否则 设置f(a)=e' 并且accept I(e'),发送ack
leader:一旦收到过半数new_leader的ack,给所有的follower发送commit消息。(至此,leader已经建立,建立的本意就是可以commit消息)
follower:收到commit消息后,投递自己已经deliver过的信息与 I(e') 的差额。保证性质Primary integrity
消息广播:很简单,参照paper原文
三、证明部分
Zab satisfies broadcast integrity : If some follower delivers <v,z> then some primary ρ(e)∊ Π has broadcast <v,z>
这个性质只需要通讯信道保证即可
D(f):f在epoch=f.a的广播阶段投递的消息集合
Zab satisfies agreement: If some follower f delivers <v,z> and some follower f’ delivers <v',z'>, then f' delivers <v,z> or f delivers <v',z'>
证明:如果<v,z>=<v',z'>,显然成立
不失一般性z≺z': 要么epoch(z)<epoch(z'), 要么epoch(z)==epoch(z') 并且counter(z)<counter(z')
情况1:epoch(z)==epoch(z') ,不失一般性,设<v',z'>∊D(f') 对于<v,z> 要么<v,z>∊D(f') =>得证
要么 <v',z'>∊I(f'.e)=>显然成立
情况2:epoch(z)<epoch(z') 由于f’ delivers <v',z'>,则此时leader(e')已经产生 对于D(f)⊆I(e')=> <v,z>∊I(e') 根据算法phase2的最后一步,得证
Zab satisfies total order: If some follower delivers <v,z> before <v',z'>, then any process that delivers <v',z'> must also deliver <v,z> and deliver <v,z> before <v',z'>
证明: 在C(f.e) 上<v,z> ≺ <v',z'>,<v',z'>∊C(f'.e)
情况1:f'.e <f.e 那么 C(f'.e)⊂C(f.e) =><v',z'>∊C(f.e) ,并且 C(f’.e) 上<v,z> ≺ <v',z'>
情况2:f'.e≥f.e 那么 C(f.e)= CB(e)∪I(e), C(f.e)⊆C(f'.e) 首先在C(f'.e)上有 <v,z> ≺ <v',z'>
其次 ∆f'⊆C(f'.e) 并且 <v',z'>∊∆f'
至此我们证明了Zookeeper算法的agreement与integrity部分
四、总结
zab算法所需要的基础设施:
- 可靠的信道 tcp
- 可靠的本地存储系统 磁盘
- 选主算法事实上依赖了paxos算法的正确性
Zookeeper性能:
我们可以看到,算法的复杂部分是由数据写入带来的,数据读部分zk在本地内存保存了一个一致性tree。读性能>写性能,因此zk使用与读多写少的场景。论文中给定的比例大约是3:1