CS-Notes/notes/笔记/一致性原理.md.txt
2018-02-22 14:47:22 +08:00

219 lines
16 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[TOC]
# 两阶段提交协议2PC
保证多个节点操作的原子性,实现事务操作。
包含两类节点协调者coordinator和参与者participants协调者只有一个参与者可以有多个。
**Phase1**请求阶段,协调者通知事务参与者准备提交或者取消事务,然后进入表决过程。在表决过程中,参与者告知协调者自己的决策:如果事务在本地执行成功,就告知同意,否者告知取消。
**Phase2**提交阶段,协调者将基于表决阶段的投票结果进行决策,当且仅当所有参与者同意提交事务,决策结果才为同意,否者为取消。协调者把决策结果通知所有的参与者,参与者接收到协调者发来的消息后执行相应的操作。
# Paxos协议
Paxos用于确保多个节点对某个投票达成一致。常用来选举主节点当主节点出现故障时使用Paxos协议就可以从备节点中选举出新的主节点。也用来构建高可用的全局服务例如分布式锁服务全局命名和配置服务等Apache Zookeeper就实现了Paxos。
Paxos协议涉及两类节点提议者proposer和接受者acceptor
在只有一个proposer的情况下Paxos协议执行步骤如下
1. 批准proposer发送提议给acceptoracceptor决定接受或者拒绝这个提议
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都写入这个entryLeader才会修改节点值并且通知所有的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发出一个随机数xB收到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将军送来的信息作为vii将军也可能是叛徒。
**正确性条件**若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**对于每个ivi是每个副官i从司令收到的命令如果没有收到命令则默认为撤退命令。副官i在OM(m-1) 中作为发令者将之发送给另外n-2 个副官。
**3**对于每个i和每个j  ivj 是副官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=1n=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=1n=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)其中xyz都可以是A或R的任意一种。之后三位忠诚的副官将会按照OM(0)要求的那样交换他们收到的信息。对于副官1他综合司令、副官2和副官3后得到的消息向量将会是(x,y,z),可以发现对于其他两个忠实的副官,他们得到的消息向量也将是(x,y,z)。不管xyz如何变化majority(x,y,z)对于三人来说都是一样的,所以三个副官将会采用一致的行动。
**3. m=2n=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 书面协议**
除了A1A2和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=3m=1其中司令是叛徒这是口头协议不能解决的状况。
![](index_files/c4179847-3183-40a5-95f8-cb429295c2bc.jpg)
很显然副官1得到的V1={A,R}副官2得到相同的V2={A,R}。他们采用choice函数后得到的命令一定相同。
相似的n=4m=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)