219 lines
16 KiB
Plaintext
219 lines
16 KiB
Plaintext
[TOC]
|
||
# 两阶段提交协议(2PC)
|
||
|
||
保证多个节点操作的原子性,实现事务操作。
|
||
|
||
包含两类节点:协调者(coordinator)和参与者(participants),协调者只有一个,参与者可以有多个。
|
||
|
||
**Phase1:**请求阶段,协调者通知事务参与者准备提交或者取消事务,然后进入表决过程。在表决过程中,参与者告知协调者自己的决策:如果事务在本地执行成功,就告知同意,否者告知取消。
|
||
|
||
**Phase2:**提交阶段,协调者将基于表决阶段的投票结果进行决策,当且仅当所有参与者同意提交事务,决策结果才为同意,否者为取消。协调者把决策结果通知所有的参与者,参与者接收到协调者发来的消息后执行相应的操作。
|
||
|
||
# Paxos协议
|
||
|
||
Paxos用于确保多个节点对某个投票达成一致。常用来选举主节点,当主节点出现故障时,使用Paxos协议就可以从备节点中选举出新的主节点。也用来构建高可用的全局服务,例如分布式锁服务,全局命名和配置服务等,Apache Zookeeper就实现了Paxos。
|
||
|
||
Paxos协议涉及两类节点:提议者(proposer)和接受者(acceptor)。
|
||
|
||
在只有一个proposer的情况下,Paxos协议执行步骤如下:
|
||
|
||
1. 批准:proposer发送提议给acceptor,acceptor决定接受或者拒绝这个提议;
|
||
2. 确认:如果超过一半的acceptor接受,则提议生效,proposer发送acknowledge消息通知所有的acceptor提议生效。
|
||
|
||
如果存在网络分区的情况下,可能会存在多个proposer,用提议号来控制每个提议,只有提议号最大的才会被接受。
|
||
|
||
![](index_files/f257d633-48e9-431e-9206-625ec36bfab5.jpg)
|
||
|
||
# Raft协议
|
||
|
||
Raft和Poxas同为一致性协议,但是更容易理解,也更容易实现。
|
||
|
||
[Raft可视化](http://thesecretlivesofdata.com/raft/)
|
||
|
||
有三种节点:Follower、Candidate和Leader。
|
||
|
||
Leader会周期性的发送消息给Follower。每个Follower都设置了一个随机的竞选超时时间,一般为150ms~300ms,如果在这个时间内没有收到Leader的消息,则节点就会变成Candidate,进入竞选阶段。最开始系统只有Follower。
|
||
|
||
![](index_files/5.gif)
|
||
|
||
Candidate会请求其它所有节点的投票,如果一个Candidate获得多数票,则它成为Leader。
|
||
|
||
所有来自客户端的修改都会被传到Leader,每个修改被作为一个entry添加到节点的日志。Leader先不会修改其节点值,而是把entry都赋值到所有的Follower,只有所有的Follower都写入这个entry,Leader才会修改节点值,并且通知所有的Follower也修改节点值。
|
||
|
||
![](index_files/4.gif)
|
||
|
||
该协议也可以用来处理网络分区的问题。
|
||
|
||
![](index_files/3.gif)
|
||
|
||
# 拜占庭将军问题
|
||
|
||
该问题主要用于保证分布式系统的一致性和可用性。
|
||
|
||
## 问题场景
|
||
|
||
拜占庭帝国想要进攻一个强大的敌人,为此派出了10支军队去包围这个敌人。这个敌人虽不比拜占庭帝国,但也足以抵御5支常规拜占庭军队的同时袭击。基于一些原因,这10支军队不能集合在一起单点突破,必须在分开的包围状态下同时攻击。他们任一支军队单独进攻都毫无胜算,除非有至少6支军队同时袭击才能攻下敌国。他们分散在敌国的四周,依靠通信兵相互通信来协商进攻意向及进攻时间。困扰这些将军的问题是,他们不确定他们中是否有叛徒,叛徒可能擅自变更进攻意向或者进攻时间。在这种状态下,拜占庭将军们能否找到一种分布式的协议来让他们能够远程协商,从而赢取战斗?这就是著名的拜占庭将军问题。
|
||
|
||
## 相关问题:两军问题
|
||
|
||
拜占庭将军问题中并不去考虑通信兵是否会被截获或无法传达信息等问题,即消息传递的信道绝无问题。如果需要考虑信道是有问题的,这涉及到了另一个相关问题:两军问题。
|
||
|
||
![](index_files/a8ec729f-cb9b-4daa-93a4-c6851db6e111.jpg)
|
||
|
||
白军驻扎在沟渠里,蓝军则分散在沟渠两边。白军比任何一支蓝军都更为强大,但是蓝军若能同时合力进攻则能够打败白军。他们不能够远程的沟通,只能派遣通信兵穿过沟渠去通知对方蓝军协商进攻时间。是否存在一个能使蓝军必胜的通信协议,这就是两军问题。通信兵得经过敌人的沟渠,在这过程中他可能被捕,也就是说,两军问题中信道是不可靠的,并且其中没有叛徒之说,这就是两军问题和拜占庭将军问题的根本性不同。
|
||
|
||
倘若1号蓝军(简称1)向2号蓝军(简称2)派出了通信兵,若1要知道2是否收到了自己的信息,1必须要求2给自己传输一个回执,说“你的信息我已经收到了,我同意你提议的明天早上10点9分准时进攻”。然而,就算2已经送出了这条信息,2也不能确定1就一定会在这个时间进攻,因为2发出的回执1并不一定能够收到。所以,1必须再给2发出一个回执说“我收到了”,但是1也不会知道2是否收到了这样一个回执,所以1还会期待一个2的回执。但在这个系统中永远需要存在一个回执,这对于两方来说都并不一定能够达成十足的确信。更要命的是,我们还没有考虑,通信兵的信息还有可能被篡改。由此可见,经典情形下两军问题是不可解的,并不存在一个能使蓝军一定胜利的通信协议。
|
||
|
||
不幸的是,两军问题作为现代通信系统中必须解决的问题,我们尚不能将之完全解决,这意味着你我传输信息时仍然可能出现丢失、监听或篡改的情况。但我们能不能通过一种相对可靠的方式来解决大部分情形呢?这需要谈到TCP协议。
|
||
|
||
![](index_files/10a84b72-c2fe-470b-b10c-07720c7380d1.jpg)
|
||
|
||
TCP协议中,A先向B发出一个随机数x,B收到x了以后,发给A另一个随机数y以及x+1作为答复,这样A就知道B已经收到了,因为要破解随机数x可能性并不大;然后A再发回y+1给B,这样B就知道A已经收到了。这样,A和B之间就建立一个可靠的连接,彼此相信对方已经收到并确认了信息。而事实上,A并不会知道B是否收到了y+1;并且,由于信道的不可靠性,x或者y都是可能被截获的,这些问题说明了即使是三次握手,也并不能够彻底解决两军问题,只是在现实成本可控的条件下,我们把TCP协议当作了两军问题的现实可解方法。
|
||
|
||
## 问题形式化
|
||
|
||
只要忠诚的将军能够让别的将军接受到自己真实意图,并且所有忠诚将军能够达成一致的决定,就能解决该问题。
|
||
|
||
定义一个变量vi,作为其他将军收到的第i个将军的命令值;之后,定义一个函数来处理向量(v1,v2,…,vn),各将军用这个函数的结果作为自己最终采用的命令。
|
||
|
||
**一致性条件**:每一个忠诚的将军必须得到相同的(v1,v2,…,vn)。这意味着,忠诚的将军并不一定使用i将军送来的信息作为vi,i将军也可能是叛徒。
|
||
|
||
**正确性条件**:若i将军是忠诚的,其他忠诚的将军必须以他送出的值作为vi。
|
||
|
||
改写一致性条件如下:无论i将军是忠诚或是叛徒,任何两个忠诚的将军都使用相同的vi。这是很巧妙的一步转换,如此一致性条件)和正确性条件都只涉及一个将军i如何帮别的将军接受自己送出的值vi,所以可以将问题改为司令-副官模式来简化问题,即一个司令把自己的命令传递给n-1个副官。
|
||
|
||
**IC1:**所有忠诚的副官遵守一个命令,即一致性。
|
||
|
||
**IC2:**若司令是忠诚的,每一个忠诚的副官遵守他发出的命令,即正确性。
|
||
|
||
司令-副官模式只要将司令遍历各个将军,就可以变成完整问题,而他们采用的算法可以是完全一致的。在这种模式下,司令副官的形式下达成的一致意味着司令的命令得到了有效传达,若出现了异议,有异议的将军会作为司令发起新的司令副官模式寻求自己的观点表达,以协商达成一致。
|
||
|
||
有两种解决方法:口头协议和书面协议。
|
||
|
||
**4.4 口头协议**
|
||
|
||
口头协议满足以下条件:
|
||
|
||
**A1:**每个被发送的消息都能够被正确的投递
|
||
|
||
**A2:**信息接收者知道是谁发送的消息
|
||
|
||
**A3:**能够知道缺少的消息
|
||
|
||
**4.4.1 OM(m)**
|
||
|
||
采用口头协议,若叛徒数少于1/3,则拜占庭将军问题可解。这个结论说明了,对于拜占庭将军问题,由于叛徒可以做出各种各样的判断,就必须四模冗余系统才足够容错。
|
||
|
||
**OM(0)算法**
|
||
|
||
**(1)**司令将他的命令发送给每个副官。
|
||
|
||
**(2)**每个副官采用从司令发来的命令;如果没有收到命令,则默认为撤退命令。
|
||
|
||
**OM(m)算法**
|
||
|
||
**(1)**司令将他的命令发送给每个副官。
|
||
|
||
**(2)**对于每个i,vi是每个副官i从司令收到的命令,如果没有收到命令,则默认为撤退命令。副官i在OM(m-1) 中作为发令者将之发送给另外n-2 个副官。
|
||
|
||
**(3)**对于每个i,和每个j ≠ i,vj 是副官i 从第2步中的副官j (使用OM(m-1)算法)发送过来的命令,如果没有收到第2步中副官j 的命令,则默认为撤退命令。最后副官i 使用majority(v1,…,vn-1)得到命令。
|
||
|
||
这个算法是一个递归算法,在OM(m)中需要采用OM(m-1)得到相关结果。m代表的是叛徒数量,从m到0,意味着对于每个将军,需要m+1轮的算法才能完成。
|
||
|
||
该算法是关于m的,意味着使用该算法必须知道有多少个叛徒。
|
||
|
||
对于任意k<m,在第m-k+1步中OM(k)的vi,都是利用OM(k-1)得来的,即每个将军将会在OM(k-1)中询问其他人,i将军传给他们的是什么,而其他人传递回来的信息则是利用OM(k-2)得到。
|
||
|
||
**4.4.2 实例**
|
||
|
||
**1. m=1,n=3**
|
||
|
||
首先考虑司令忠诚而副官2是叛徒的情况,司令把进攻命令传给了两个副官1和副官2,但是由于副官2为了不让他们达成一致,将司令的命令改成了撤退。那对于副官1来说,他应该如何判断?他无法知道是司令是叛徒还是副官2是叛徒,从而无法判断。
|
||
|
||
![](index_files/eb40b5ed-2e0c-42bd-a9ba-ef5893f697fb.jpg)
|
||
而如果司令是叛徒,两个副官忠诚,司令会发送两个不同的命令。当两个副官对照命令时,他们又凌乱了,无法判断司令是叛徒或者对方是叛徒,从而又无法判断。这个情形非常简易的说明了三模冗余是无法动态容错的。
|
||
|
||
![](index_files/694b777f-6ba5-453a-9390-63965a66f30f.jpg)
|
||
|
||
**2. m=1,n=4**
|
||
|
||
首先考虑司令忠诚而副官3是叛徒的情况,倘若司令在OM(1)中给各副官发送的消息都是进攻(A),之后OM(0)时,叛徒副官3给副官1和副官2说他收到的消息是撤退(R)。那么对于副官1(或副官2)来说,他综合司令、副官3和副官2(或副官1)后得到的消息向量都将会是(A,A,R),利用majority函数之后,将会采用A。
|
||
|
||
![](index_files/35164829-097c-40be-85da-9cf3cb800056.jpg)
|
||
|
||
倘若司令是叛徒,那么我们已经不需要满足IC2。为方便,我们假设叛徒司令在OM(1)会给三个副官发送的信息是(x,y,z),其中x,y,z都可以是A或R的任意一种。之后,三位忠诚的副官将会按照OM(0)要求的那样,交换他们收到的信息。对于副官1,他综合司令、副官2和副官3后得到的消息向量将会是(x,y,z),可以发现对于其他两个忠实的副官,他们得到的消息向量也将是(x,y,z)。不管x,y,z如何变化,majority(x,y,z)对于三人来说都是一样的,所以三个副官将会采用一致的行动。
|
||
|
||
**3. m=2,n=7**
|
||
|
||
我们先讨论司令忠诚的情形,假设叛徒为副官5和副官6。在OM(2)中,司令将攻击命令(A)传给各个副官。在OM(1)中,忠诚的副官们将会发送他们收到的消息(A),但由于副官5和副官6是叛徒,他们将会发送别的信息(比如R)。
|
||
|
||
![](index_files/0726f364-95e6-46f4-8303-38cd6d4c8f9f.jpg)
|
||
|
||
对于副官1,他收到了司令传来的命令,他会直接采用majority函数综合司令和其他将军传来的信息吗?他不会,因为这还在OM(1)中,他并不知道司令是不是叛徒,他会利用询问别人的方式来确认将军的命令,但是按照算法他会把司令的命令作为v1(即v1=A)并传给其他人。接下来他会努力取得其他的v2~v6的值,这时已经在OM(1)中了,副官1绝不会轻易相信别人传来的消息,比如副官2给他传来了命令A,但是他会怀疑副官2传来的消息,所以他用OM(1)大法,问其他人副官2传给了他们什么,副官3和副官4诚实的告诉副官1,副官2给他们传的是A,而这时副官5和副官6又要撒谎了,他们又乱说,我们姑且假定他们传来的是x’和y’吧。这样,终于进入到了OM(0),这时副官1将会综合其他副官对于v2的反馈,得到向量(A,A,A,x’,y’),再利用majority函数,得到了v2=A。如下图,
|
||
|
||
![](index_files/16acc962-4021-49cb-9d91-19b2ee923ddc.jpg)
|
||
|
||
我们就可以得到副官1的v1~v6向量为(A,A,A,A,x,y),利用majority函数,副官1最终采用的行动会是A。 类似的,我们可以发现,其他几个忠诚的副官得到的命令向量都会是(A,A,A,A,x,y),利用majority函数后采用的行动都会是A。
|
||
|
||
**4.5 书面协议**
|
||
|
||
除了A1,A2和A3以外,我们在口头协议之上添加一个条件A4,使之成为书面协议
|
||
|
||
**A4**:(a)签名不可伪造,一旦被篡改即可发现,而叛徒的签名可被其他叛徒伪造;(b)任何人都可以验证签名的可靠性。
|
||
|
||
**4.5.1 SM(m)**
|
||
|
||
不管将军总数n和叛徒数量m,只要采用该算法,忠诚的将军总能达到一致.用集合Vi来表示i副官收到的命令集,这是一个集合,也就是满足互异性(没有重复的元素)等集合的条件。类似的,我们定义choice(V)函数来决定各个副官的选择,这个函数可以有非常多种形式,他只要满足了以下两个条件:
|
||
|
||
**(1)**如果集合V只包含了一个元素v,那么choice(V)=v
|
||
|
||
**(2)**choice(o)=RETREAT,其中o是空集
|
||
|
||
SM(m)算法并不是一个递归算法,我们只要让各个副官收到的V集相同,choice(V)也一定能够得到相同的值。
|
||
|
||
初始化Vi=空集合。
|
||
|
||
**(1)**将军签署命令并发给每个副官;
|
||
|
||
**(2)**对于每个副官i:
|
||
|
||
(2.1)如果副官i从发令者收到v:0的消息,且还没有收到其他命令序列,那么他
|
||
|
||
(2.1.1)使Vi为{v};
|
||
|
||
(2.1.2)发送v:0:i给其他所有副官。
|
||
|
||
(2.2)如果副官i收到了形如v:0:j1:…:jk的消息且v不在集合Vi中,那么他
|
||
|
||
(2.2.1)添加v到Vi;
|
||
|
||
(2.2.2)如果k<m,那么发送v:0:j1:…:jk:i 给每个不在j1,..,jk 中的副官。
|
||
|
||
**(3)**对于每个副官i,当他不再收到任何消息,则遵守命令choive(Vi)。
|
||
|
||
值得注意的是,如果司令忠诚,由于其签名不可伪造,所有忠诚的副官都将得到一个单点集{v},他们采用的命令集Vi相同,得到的choive(Vi)也为v,满足了IC1和IC2。如果司令并非忠诚,只需要满足IC1,但是算法SM(m)使得所有忠诚的副官得到相同的Vi,使用choice()函数后采用的命令也就一定相同。
|
||
|
||
**4.5.2 实例**
|
||
|
||
司令是叛徒的状况稍难想象,举个例子,n=3,m=1,其中司令是叛徒,这是口头协议不能解决的状况。
|
||
|
||
![](index_files/c4179847-3183-40a5-95f8-cb429295c2bc.jpg)
|
||
|
||
很显然,副官1得到的V1={A,R},副官2得到相同的V2={A,R}。他们采用choice函数后得到的命令一定相同。
|
||
|
||
相似的,n=4,m=2,其中司令是叛徒,这同样是口头协议不能解决的状况。
|
||
|
||
![](index_files/98fc99f4-0edf-431a-88d5-e96f8bfe899f.jpg)
|
||
|
||
副官1和副官2得到的V1=V2={A,R},他们采用choice函数后得到的命令也相同。
|
||
|
||
# 参考资料
|
||
|
||
- 杨传辉. 大规模分布式存储系统: 原理解析与架构实战[M]. 机械工业出版社, 2013.
|
||
- [简单解释 MapReduce 算法](http://www.cnblogs.com/wuyudong/p/mapreduce-principle.html)
|
||
- [拜占庭将军问题深入探讨](http://www.8btc.com/baizhantingjiangjun)
|
||
- [区块链技术指南](https://www.gitbook.com/book/yeasy/blockchain_guide/details)
|
||
- [如何浅显易懂地解说 Paxos 的算法?](https://www.zhihu.com/question/19787937/answer/26584242)
|
||
- [图解 Paxos 一致性协议](http://blog.jobbole.com/106327/?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com)
|
||
- [raft-zh_cn](https://github.com/maemual/raft-zh_cn)
|
||
- [Raft: Understandable Distributed Consensus](http://thesecretlivesofdata.com/raft) |