以下文章来源于云加社区 ,作者董友康
腾讯云官方社区公众号,汇聚技术开发者群体,分享技术干货,打造技术影响力交流社区。
导语 | 后台服务架构经过了集中式、SOA、微服务和服务网格四个阶段,目前互联网界大都使用微服务和服务网格。服务从集中式、中心化向分布式、去中心化不断演进,服务也变得更灵活,能够自动扩缩容、快速版本迭代等。但是分布式架构也将集中式下一些问题放大,比如通信故障、请求三态(成功、失败、超时)、节点故障等,这些问题会导致一系例数据不一致的问题,也是计算机领域的老大难问题。本文将与大家一起学习分布式一致性算法,因作者水平有限,若文中有不正处,还请多多指导。文章作者:董友康,腾讯PCG研发工程师。
一、CAP理论和BASE理论
如果要保证C(一致性),那么它需要把消息复制到所有节点,但是网络分区导致无法成功复制到n3~n5,所以它只能返回"处理失败"的结果给客户端。(这时系统就处于不可用状态,即丧失了A)
如果要保证可用性A,那么n1就只能把消息复制到n2,而不用复制到n3~n5(或者无视复制失败/超时),但n3同时也可能在处理客户端请求,n3也为了保证A而做了同样的处理。那么 [n1、n2]和[n3~n5]的状态就不一致了,于是就丧失了C(一致性)。
如果不容忍网络分区,则P(分区容忍性)不能满足。
基本可用(Basically Available):是指分布式系统在出现不可预知故障的时候,允许损失部分可用性:比如响应时间、功能降级等;
软状态( Soft State):也称为弱状态,是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点之间进行数据同步的过程存在延时;
最终一致性( Eventual Consistency):强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达成一致的状态。
二、经典分布式算法
提案者:对key的值提出自己的值;
决议者:对提案者的提议进行投票,选定一个提案,形成最终决策;
学习者:学习决议者达成共识的决策。
本小节将通过推导来引出Paxos算法的约束条件,故事灵感来自于分布式理论:深入浅出Paxos算法【1】,在原文基础上优化了可读性。 https://my.oschina.net/u/150175/blog/2992187
P0. 当集群中,超过半数的Acceptor接受了一个议案,那我们就可以说这个议案被选定了(Chosen)
T2:一次选举必须只选定一个议案(不能出现两个议案有不同的值,却都被选定的情况)。
P1:一个Acceptor必须接受它收到的第一个议案。
P2:如果一个值为v的议案被选定了,那么被选定的更大编号的议案,它的值必须也是v。
a:如果一个值为v的议案被选定了,那么Acceptor接受的更大编号的议案,它的值必须也是v。
b:如果一个值为v的议案被选定了,那么Proposer提出的更大编号的议案,它的值必须也是v。
P2c: 在所有Acceptor中,任意选取半数以上的集合,称这个集合为S。Proposal新的提案Pnew (Nnew , Vnew )必须符合下面两个条件之一: 1)如果S中所有Acceptor都没有接受过议案,那么Pnew的编号保证唯一性和递增,Pnew的值可以是任意值。 2)如果S中有Acceptor曾经接受过议案,找出编号最大的议案PN (N,V) 。那么Pnew的编号必须大于N,Pnew的值必须等于V。
P3:议案(n,v)在提出前,必须将自己的编号通知给半数以上的Acceptor。收到通知的Acceptor将n跟自己之前收到的通知进行比较,如果n更大,就将n确认为最大编号。当半数以上Acceptor确认n是最大编号时,议案(n,v)才能正式提交。
P4:Acceptor收到一个新的编号n,在确认n比自己之前收到的编号大时,必须承诺不再接受比n小的议案。
如果Acceptor 收到一个编号为 N 的 Prepare 请求,且 N 大于该 Acceptor 已经响应过的所有 Prepare 请求的编号,那么它就会将它已经接受过的编号最大的提案(如果有的话)作为响应反馈给 Proposer,同时该Acceptor 承诺不再接受任何编号小于 N 的提案。否则拒绝返回。
如果超过半数Acceptor回复promise,Proposer向Acceptor发送accept消息。注意此时的V:V 就是收到的响应中编号最大的提案的,如果响应中不包含任何提案,那么V 就由 Proposer 自己决定;
Acceptor检查accept消息是否符合规则,只要该 Acceptor 没有对编号大于 N 的 Prepare 请求做出过响应,它就接受该提案。
PBFT(实用拜占庭容错)算法:是一种共识算法,较高效地解决了拜占庭将军问题;
Multi-Paxos算法:优化了prepare阶段的效率,同时允许多个Leader并发提议;以及FastPaxos、EPaxos等,这些演变是针对某些问题进行的优化,内核思想还是依托于Paxos。
Leader选举:当前leader跪了或集群初始化的情况下,新leader被选举出来。
日志复制:leader必须能够从客户端接收请求,然后将它们复制给其他机器,强制它们与自己的数据一致。
安全性:如何保证上述选举和日志复制的安全,使系统满足最终一致性。
Leader:处理与客户端的交互和与follower的日志复制等,一般只有一个Leader;
Follower:被动学习Leader的日志同步,同时也会在leader超时后转变为Candidate参与竞选;
Candidate:在竞选期间参与竞选;
增加本地节点的Current Term值;
将状态切换为Candidate;
该节点投自己一票;
批量向其他节点发送拉票请求(RequestVote RPC)。
在一个任期Term中只能投一张票;
候选人的Term值大于Current Term,且候选人已执行的Log序号不低于本地Log(Log及已执行的概念见《日志复制》小节),则拉票请求是合法的;
只选择首先到达的合法拉票请求;
If two identical, deterministic processes begin in the same state and get the same inputs in the same order, they will produce the same output and end in the same state.
本地追加日志信息;
并行发出 AppendEntries RPC请求;
等待大多数Follower的回应。收到查过半数节点的成功提交回应,代表该日志被复制到了大多数节点中(committed);
在状态机上执行entry command。既将该日志应用到状态机,真正影响到节点状态(applied);
回应Client 执行结果;
确认Follower也执行了这条command;如果Follower崩溃、运行缓慢或者网络丢包,Leader将无限期地重试AppendEntries RPC,直到所有Followers应用了所有日志条目。
raft step by step入门演示: http://thesecretlivesofdata.com/raft/
raft 官方演示: https://raft.github.io/
一个节点某一任期内最多只能投一票;而节点B的term必须比A的新,A才能给B投票。
只有获得多数投票的节点才会成为leader。
不同机器的日志中如果有两个entry有相同的偏移和term号,那么它们存储相同的指令。
如果不同机器上的日志中有两个相同偏移和term号的日志,那么日志中这个entry之前的所有entry保持一致。
三、总语
“这个世界上只有一种一致性算法,那就是 Paxos”
https://my.oschina.net/u/150175/blog/2992187
https://zh.wikipedia.org/wiki/Paxos算法
https://web.stanford.edu/~ouster/cgi-bin/papers/raft-atc14
https://raft.github.io/
http://thesecretlivesofdata.com/raft/
https://www.cnblogs.com/xybaby/p/10124083.html