分布式架构
分布式&集中式
集中式特点
由一台或者多台计算机组成中心节点
数据几种存储在中心节点
系统中所有业务单元几种部署在中心节点,系统所有功能有中心节点集中处理集中式部署结构简单,集中式系统基于底层卓越的大型主机
无需考虑多节点部署,不用考虑多节点之间的分部署协作问题
分布式特点
分布式系统:一个硬件或软件组分布在不能网路计算机上。彼此之间仅仅通过消息传递进行通信和协调
分布式系统中的计算机在空间上可以随意分布,可以任意机柜、机房、升值分布在不同的地域|
分布式特征
-
分布性
分布式系统中计算机在空间上随意分布、机器分布情况随时变动 -
对等性
分布式系统中计算机没有主从之分
组成分布式系统的所有计算机节点都是对等的副本
:分布式系统对数据和服务提供一种冗余方式,为了提供高可用服务常常需要对数据和服务进行副本处理数据副本
:指不同节点上持久化同一份数据,某一节数据丢失可以从副本上读取到改数据,数据副本是解决数据丢失问题的最有效手段服务副本
:多节点提供同样服务,每个节点都有能力接收和处理请求并进行相应的处理 -
并发性
分布式系统中多个节点并发操作一些共享资源,
如何准确高效的协调分布式并发操作是分布式架构设计中最大的挑战 -
缺乏全局时钟
分布式系统中很难定义两个事件的先后,
原因是分布式系统缺乏一个全局时钟序列控制 -
故障总会发生
一个被大量工程实践所检验黄金定理:任何在设计阶段考虑到的异常,一定会在系统实际运行中发生,且实际中会遇到很多在设计时并未考虑到的异常故障
所以在系统设计时不能放过任何异常情况-
通信异常
网络的不可靠性
通信延迟、消息丢失 -
网络分区
分布式系统中网络异常、延时等原因导致分布式系统集群中只有部分节点之间正常通信,另外一拨几点之间不能正常通信—这种现象称为网络分区,俗称:脑裂,出现小集群(局部之间正常通信)
-
三态
成功、失败、超时
由于网络原因请求并没有成功发送到接收方,在发送过程中发生了消息丢失现象
请求成功被接收方接收后,进行处理,但是响应反馈给发送方时候发生了消息丢失,
发送无法确认消息被处理 -
节点故障
分布式系统几点出现宕机或僵死现象
-
ACID–>CAP/BASE
再谈ACID(强一致性)
-
原子性
最小且不可拆分的执行单元 -
一致性
执行成功的事务使数据库的数据从一个确定一致性的状态到另一个确定一致性的状态 -
隔离性
-
持久性
-
事务一旦被提交对应数据状态的变更是持久的
CAP定理
一个分布式系统不可能同时满足一致性、可用性、分区容错性
最对只能满足其中两项
-
一致性
多个节点副本之间保持一致性
分布式系统中对一个数据的更新操作后所有的用户都可以读取到最新的数据称之为强一致性 -
可用性
分布式系统对用户的每一个请求能够在有限的时间内返回明确的结果 -
分区容错性
分布式系统在遇到任何网络分区故障时候,仍然能够满足一致性和可用性
除非整个网络环境发生故障
BASE理论
BASE是基本可用、软状态、最终一致性
Basically Available、Soft state、Eventually consistentBASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网分布式时间的总结
是基于CAP定理逐步演化而来BASE核心思想:
即使无法做到强一致性,但每个应用都可以根据吱声业务特点采用适当的方式使系统最红达到一致性
基本可用
-
分布式系统出现不可预知的故障时,允许损失部门可用性
-
软状态(弱状态)
允许系统在不同节点上数据副本之间进行数据同步时存在延时 -
最终一致性
强调系统中所有副本经过一点时间同步,最终能达到一个一致状态,不需要实时保证系统数据的强一致性
-
因果一致性
我理解两个动作之期间数据传递具有先后、可见性 -
读已之做些
我理解自己能读取自己最后更新数据而不是旧数据 -
会话一致性
我理解是用户同一个会话数据访问的一致性,用户总是在当前会话中访问到同会话中之前操作最新数据 -
单调读一致性
一个进程访问数据总是最新的(有效最新的)
-
单调写一致性
分布式系统保证同一个进程写操作被顺序执行
-
一致性协议
2PC、3PC
2PC、3PC及其应用
分布式系统中,每个节点能够明确知道自己进行事务曹锁过程中的结果的成功和失败
无法知道其他节点分布式节点的操作结果,因此跨越多个分布式节点需要引入协调者
来统一调度所有节点(参与者
)的执行逻辑协调者
负责调度参与者
并最终决定是否把参与者
事务进行提交
2PC
2PC,Two-Phase Commit
二阶段提交协议使分布式系统下所有节点进行事务处理过程中保持原子性和一致性,
用来保证分布式系统数据的一致性绝大部分关系型数据库采2PC完成分布式事务处理,完成分布式事务参与者的协调
统一决定事务的提交或回滚
-
2PC 协议说明
2PC将事务提交过程分成两个阶段进行-
提交事务请求(事务开始前投票阶段)
-
执行事务提交(事务执行–提交、回滚)
-
优点
-
原理节点实现方便
-
缺点
同步阻塞
参与者等待其他参与者响应的过程中是处于阻塞状态,无法进行其他任何操作
限制了分布式的性能单点问题
协调者处于一个重要的角色,且存在单点问题脑列、数据不一致
参与者不确保都能收到协调者执行事务的命令,造成只有局部一部分参与者收到命令执行事务OK
会出现脑列问题造成数据不一致当协调者向参与者发送commit请求之后,
发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,
这会导致只有一部分参与者接受到了commit请求。
而在这部分参与者接到commit请求之后就会执行commit操作。
但是其他部分未接到commit请求的机器则无法执行事务提交。
于是整个分布式系统便出现了数据不一致性的现象。太过保守
2PC没有完善的容错机制,任意一个参数者节点施暴都会导致整个事务失败
3PC
3PC,Three-Phase Commit
2PC 协议改进,
三阶段提交协议在协调者和参与者中都引入超时机制,
并且把两阶段提交协议的第一个阶段分成了两步: 询问,然后再锁资源,最后真正提交
3PC提交事务请求分为
CanCommit、PreCommit、DoCommit
canCommit阶段
-
3PC的canCommit阶段其实和2PC的准备阶段很像。
协调者向参与者发送commit请求,参与者如果可以提交就返回yes响应,否则返回no响应 -
preCommit阶段(增加了)
协调者根据参与者canCommit阶段的响应来决定是否可以继续事务的preCommit操作。
根据响应情况,有下面两种可能:-
协调者从所有参与者得到的反馈都是yes:
那么进行事务的预执行,协调者向所有参与者发送preCommit请求,并进入prepared阶段。
参与者接收到preCommit请求后会执行事务操作,并将undo和redo信息记录到事务日志中。
如果一个参与者成功地执行了事务操作,则返回ACK响应,同时开始等待最终指令 -
协调者从所有参与者得到的反馈有一个是No或是等待超时之后协调者都没收到响应:
那么就要中断事务,协调者向所有的参与者发送abort请求。
参与者在收到来自协调者的abort请求,或超时后仍未收到协调者请求,执行事务中断。
-
-
doCommit阶段
协调者根据参与者preCommit阶段的响应来决定是否可以继续事务的doCommit操作。
根据响应情况,有下面两种可能:-
协调者从参与者得到了ACK的反馈:
协调者接收到参与者发送的ACK响应,那么它将从预提交状态进入到提交状态,
并向所有参与者发送doCommit请求。
参与者接收到doCommit请求后,执行正式的事务提交,并在完成事务提交之后释放所有事务资源,并向协调者发送haveCommitted的ACK响应。
那么协调者收到这个ACK响应之后,完成任务。 -
协调者从参与者没有得到ACK的反馈, 也可能是接收者发送的不是ACK响应,也可能是响应超时:
执行事务中断。
-
2PC VS 3PC
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。
在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。
PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。也是状态一种记录
三阶段提交是“非阻塞”协议。
三阶段提交在两阶段提交的第一阶段与第二阶段之间插入了一个准备阶段,
使得原先在两阶段提交中,参与者在投票之后,由于协调者发生崩溃或错误,而导致参与者处于无法知晓是否提交或者中止的“不确定状态”所产生的可能相当长的延时的问题得以解决。
举例来说,假设有一个决策小组由一个主持人负责与多位组员以电话联络方式协调是否通过一个提案,以两阶段提交来说,主持人收到一个提案请求,打电话跟每个组员询问是否通过并统计回复,然后将最后决定打电话通知各组员。
要是主持人在跟第一位组员通完电话后失忆,而第一位组员在得知结果并执行后老人痴呆,那么即使重新选出主持人,也没人知道最后的提案决定是什么,也许是通过,也许是驳回,不管大家选择哪一种决定,都有可能与第一位组员已执行过的真实决定不一致,老板就会不开心认为决策小组沟通有问题而解雇。
三阶段提交即是引入了另一个步骤,主持人打电话跟组员通知请准备通过提案,
以避免没人知道真实决定而造成决定不一致的失业危机。
为什么能够解决二阶段提交的问题呢?
回到刚刚提到的状况,在主持人通知完第一位组员请准备通过后两人意外失忆,即使没人知道全体在第一阶段的决定为何,全体决策组员仍可以重新协调过程或直接否决(有记录),不会有不一致决定而失业。
那么当主持人通知完全体组员请准备通过并得到大家的再次确定后进入第三阶段,
当主持人通知第一位组员请通过提案后两人意外失忆,这时候其他组员再重新选出主持人后,
仍可以知道目前至少是处于准备通过提案阶段,表示第一阶段大家都已经决定要通过了,此时便可以直接通过。
Paxos 一致性算法
基于消息传递且具有高度容错特性的一致性算法
目前公认的解决分布式一致性问题最有效的算法之一Paxos需要解决的问题是如何在一个可以发生异常的分布式系统中快速且正确的在集群内部对某个数据的值达成一致,并且确保无论发生以上任何异常都不会破坏整个系统的一致性。
也可以理解成分布式系统中达成状态的一致性。
Paxos算法的原理及过程透彻理解
个人理解是:不要把这个Paxos算法达到的目的和分布式事务联系起来,而是针对Zookeeper这样的master-slave集群对某个决议达成一致,也就是副本之间写或者leader选举达成一致。我觉得这个算法和狭义的分布式事务不是一样的。
对Paxos保证一致性换一种理解
paxos 算法是分布式一致性算法用来解决一个分布式系统如何就某个值(决议)达成一致的问题。
一个典型的场景是,在一个分布式数据库系统中,如果各节点的初始状态一致,
每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。
为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个”一致性算法”以保证每个节点看到的指令一致。
分布式系统中一般是通过多副本来保证可靠性,而多个副本之间会存在数据不一致的情况。
所以必须有一个一致性算法来保证数据的一致,描述如下:
假如在分布式系统中初始是各个节点的数据是一致的,每个节点都顺序执行系列操作,然后每个节点最终的数据还是一致的。
Paxos算法就是解决这种分布式场景中的一致性问题。对于一般的开发人员来说,只需要知道paxos是一个分布式选举算法即可。多个节点之间存在两种通讯模型:共享内存(Shared memory)、消息传递(Messages passing)
Paxos是基于消息传递的通讯模型的
拜占庭问题
拜占庭将军问题:
拜占庭帝国有许多支军队,不同的军队的将军之间必须定一个统一的行动计划,从而做出进攻或者撤退的决定,同时,各个将军在地理上都是被分隔开来的,只能依靠军队的通讯员来进行通讯。然而在所有的通讯员中可能会存在叛徒,这些叛徒可以任意篡改消息,从而到达欺骗将军的目的,叛徒可以欺骗某些将军采取进攻行动;促成一个不是所有将军都同意的决定,如当将军们不希望进攻时促成进攻行动;或者迷惑某些将军,使他们无法做出决定。Paxos算法的前提假设是不存在拜占庭将军问题,
即:信道是安全的(信道可靠),发出的信号不会被篡改,因为Paxos算法是基于消息传递的。
此问题由Lamport提出,它也是 Paxos算法的提出者。从理论上来说,在分布式计算领域,试图在异步系统和不可靠信道上来达到一致性状态是不可能的。
因此在对一致性的研究过程中,都往往假设信道是可靠的,
而事实上,大多数系统都是部署在一个局域网中,因此消息被篡改的情况很罕见;
另一方面,由于硬件和网络原因而造成的消息不完整问题,只需要一套简单的校验算法即可。
因此,在实际工程中,可以假设所有的消息都是完整的,也就是没有被篡改
Paxos算法三种角色
-
Proposer
-
Acceptor
-
Learners
在具体的实现中,一个进程可能同时充当多种角色。
比如一个进程可能既是Proposer又是Acceptor又是Learner。
Proposer负责提出提案,Acceptor负责对提案作出裁决(accept与否),learner负责学习提案结果。
还有一个很重要的概念叫提案(Proposal)。最终要达成一致的value就在提案里。
只要Proposer发的提案被Acceptor接受(半数以上的Acceptor同意才行),Proposer就认为该提案里的value被选定了。Acceptor告诉Learner哪个value被选定,Learner就认为那个value被选定。
只要Acceptor接受了某个提案,Acceptor就认为该提案里的value被选定了。
为了避免单点故障,会有一个Acceptor集合,Proposer向Acceptor集合发送提案,
Acceptor集合中的每个成员都有可能同意该提案,且每个Acceptor只能批准一个提案,
只有当一半以上的成员同意了一个提案,就认为该提案被选定了。
Paxos算法解决的问题描述
假设有一组可以提出(propose)value(value在提案Proposal里)的进程集合。
一个一致性算法需要保证提出的这么多value中,只有一个value被选定(chosen)。
如果没有value被提出,就不应该有value被选定。
如果一个value被选定,那么所有进程都应该能学习(learn)到这个被选定的value。
一致性算法,安全性要求
-
只有被提出的value才能被选定。
-
只有一个value被选定
-
如果某个进程认为某个value被选定了,那么这个value必须是真的被选定的那个。
Paxos的目标:保证最终有一个value会被选定,当value被选定后,进程最终也能获取到被选定的value。
Paxos算法的过程
Paxos算法类似于两阶(2PC)段提提交,其算法执行过程分为两个阶段。具体如下:
-
阶段一(prepare阶段)
-
Proposer选择一个提案编号N,然后向半数以上的Acceptor发送编号为N的Prepare请求。Pareper(N)
-
如果一个Acceptor收到一个编号为N的Prepare请求,
如果小于它已经响应过的请求,则拒绝,不回应或回复error。
若N大于该Acceptor已经响应过的所有Prepare请求的编号(maxN),
那么它就会将它已经接受过(已经经过第二阶段accept的提案)的编号最大的提案(如果有的话,如果还没有的accept提案的话返回{pok,null,null})作为响应反馈给Proposer,
同时该Acceptor承诺不再接受任何编号小于N的提案。
-
-
阶段二(accept阶段)
-
如果一个Proposer收到半数以上Acceptor对其发出的编号为N的Prepare请求的响应,
那么它就会发送一个针对[N,V]提案的Accept请求给半数以上的Acceptor。
注意:V就是收到的响应中编号最大的提案的value(某个acceptor响应的它已经通过的{acceptN,acceptV}),如果响应中不包含任何提案,那么V就由Proposer自己决定。 -
如果Acceptor收到一个针对编号为N的提案的Accept请求,只要该Acceptor没有对编号大于N的Prepare请求做出过响应,它就接受该提案。如果N小于Acceptor以及响应的prepare请求,则拒绝,不回应或回复error(当proposer没有收到过半的回应,那么他会重新进入第一阶段,递增提案号,重新提出prepare请求)。
-
所有proposer经过上边的步骤
注意:有几个约定:
-
每一个Acceptor最多就只能批准一个提案(就是第二阶段accept的),那么就能保证只有一个提案被选定了???Accept之后就不能改了???如果不能改的话,那Acceptor肯定不是一致的,而且这样能达到多数??但是,如果能改的话,倒是能达成一致,但是这样真的可以??我感觉是可以accept多个的,但是书上又写了每一个Acceptor最多就只能批准一个提案。但后边也写了改变accept的值,不懂。。。。。。。最后,我觉得是只能accept一个,proposer会达成一致的value1,所以选出了唯一的value。应该不会出现那个始终达不成过半情况,因为毕竟发送时有先后的。所以,下边的图画的还是不那么准确。
我理解是在Acceptor accept后,在这些accept中一个值的达到大多数
-
因为获取那些已经通过的提案比预测未来可能会通过的提案来的简单。当Acceptor对一个N的prepare的提案响应后,他就会作出保证,不再接受任何小于N的提案号的提案。
Paxos具体实例理解
prepare阶段
-
-
每个server向proposer发送消息,表示自己要当leader,
假设proposer收到消息的时间不一样,顺序是: proposer2 -> proposer1 -> proposer3,消息编号依次为1、2、3
紧接着,proposer将消息发给acceptor中超过半数的子成员(这里选择两个),
如图所示:
proposer2向acceptor2和acceptor3发送编号为1的消息
proposer1向acceptor1和accepto2发送编号为2的消息
proposer3向acceptor2和acceptor3发送编号为3的消息 -
假设首先,proposer1发送的消息先到达acceptor1和acceptor2,
它们都没有接收过请求,所以接收该请求并返回【pok,null,null】给proposer1,
同时acceptor1和acceptor2承诺不再接受编号小于2的请求;
-
紧接着,proposer2的消息到达acceptor2和acceptor3,
acceptor3没有接受过请求,所以返回proposer2 【pok,null,null】,
acceptor3并承诺不再接受编号小于1的消息。
而acceptor2已经接受proposer1的请求并承诺不再接收编号小于2的请求,
所以acceptor2拒绝proposer2的请求;
最后,proposer3的消息到达acceptor2和acceptor3,
它们都接受过提议,但编号3的消息大于acceptor2已接受的2和acceptor3已接受的1,
所以他们都接受该提议,并返回proposer3 【pok,null,null】;
此时,proposer2没有收到过半的回复,所以重新取得编号4,并发送给acceptor2和acceptor3,
此时编号4大于它们已接受的提案编号3,所以接受该提案,并返回proposer2 【pok,null,null】。
-
accept阶段
-
Proposer3收到半数以上(两个)的回复,并且返回的value为null,所以proposer3提交了【3,server3】提案。
Proposer1也收到过半回复,返回的value为null,所以proposer1提交了【2,server1】的提案。
Proposer2也收到过半回复,返回的value为null,所以proposer2提交了【4,server2】的提案。
(这里要注意,并不是所有的proposer都达到过半了才进行第二阶段,这里只是一种特殊情况) -
Acceptor1和Acceptor2接收到proposer1的提案【2,server1】,
Acceptor1通过该请求,acceptor2承诺不再接受编号小于4的提案,所以拒绝;
Acceptor2和acceptor3接收到proposer2的提案【4,server2】,都通过该提案;
Acceptor2和acceptor3接收到proposer3的提案【3,server3】,它们都承诺不再接受编号小于4的提案,所以都拒绝。
-
所以proposer1和proposer3会再次进入第一阶段,但这时候 Acceptor2和acceptor3已经通过了提案(AcceptN = 4,AcceptV=server2),并达成了多数,所以proposer会递增提案编号,并最终改变其值为server2。最后所有的proposer都肯定会达成一致,这就迅速的达成了一致。
此时,过半的acceptor(acceptor2和acceptor3)都接受了提案【4,server2】,learner感知到提案的通过,learner开始学习提案,所以server2成为最终的leader。
Learner学习被选定的value
Paxos算法的活锁问题(保证算法活性)
介绍了Paxos的算法逻辑,但在算法运行过程中,可能还会存在一种极端情况,
当有两个proposer依次提出一系列编号递增的议案,那么会陷入死循环,无法完成第二阶段,也就是无法选定一个提案。
通过选取主Proposer,就可以保证Paxos算法的活性。
选择一个主Proposer,并规定只有主Proposer才能提出议案。“
这样一来,只要主Proposer和过半的Acceptor能够正常进行网络通信,
那么肯定会有一个提案被批准(第二阶段的accept),则可以解决死循环导致的活锁问题。
Paxos算法的过半依据
在Paxos算法中,采用了“过半”理念,也就是少数服从多数,
这使Paxos算法具有很好的容错性。那么为什么采用过半就可以呢?
Paxos基于的过半数学原理:我们称大多数(过半)进程组成的集合为法定集合,两个法定(过半)集合必然存在非空交集,即至少有一个公共进程,称为法定集合性质。例如A,B,C,D,F进程组成的全集,法定集合Q1包括进程A,B,C,Q2包括进程B,C,D,那么Q1和Q2的交集必然不在空,C就是Q1,Q2的公共进程。如果要说Paxos最根本的原理是什么,那么就是这个简单性质。也就是说:两个过半的集合必然存在交集,也就是肯定是相等的,也就是肯定达成了一致。
Paxos是基于消息传递的具有高度容错性的分布式一致性算法。
Paxos算法引入了过半的概念,解决了2PC,3PC的太过保守的缺点,且使算法具有了很好的容错性,另外Paxos算法支持分布式节点角色之间的轮换,这极大避免了分布式单点的出现,因此Paxos算法既解决了无限等待问题,也解决了脑裂问题,是目前来说最优秀的分布式一致性算法。
其中,Zookeeper的ZAB算法和Raft一致性算法都是基于Paxos的。
Paxos精简理解
Paxos算法解决的是一个分布式系统如何就某个值(决议)达成一致。
一个典型的场景是,在一个分布式数据库系统中,如果各个节点的初始状态一致,每个节点执行相同的操作序列,那么他们最后能够得到一个一致的状态。为了保证每个节点执行相同的命令序列,需要在每一条指令上执行一个“一致性算法”以保证每个节点看到的指令一致。zookeeper使用的zab算法是该算法的一个实现。
在Paxos算法中,有三种角色:Proposer (提议者),Acceptor(接受者),Learners(记录员)
-
Proposer提议者:
只要Proposer发的提案Propose被半数以上的Acceptor接受,Proposer就认为该提案例的value被选定了。 -
Acceptor接受者:
只要Acceptor接受了某个提案,Acceptor就认为该提案例的value被选定了 -
Learner记录员:
Acceptor告诉Learner哪个value就是提议者的提案被选定,Learner就认为哪个value被选定。
Paxos算法分为两个阶段,具体如下:
-
阶段一 (准leader 确定 ):
-
Proposer 选择一个提案编号 N,然后向半数以上的Acceptor 发送编号为 N 的 Prepare 请求。
-
如果一个 Acceptor 收到一个编号为 N 的 Prepare 请求,且 N 大于该 Acceptor 已经响应过的所有 Prepare 请求的编号,那么它就会将它已经接受过的编号最大的提案(如果有的话)作为响 应反馈给 Proposer,同时该Acceptor 承诺不再接受任何编号小于 N 的提案。
-
-
阶段二 (leader 确认):
-
如果 Proposer 收到半数以上 Acceptor 对其发出的编号为 N 的 Prepare 请求的响应,那么它就会发送一个针对[N,V]提案的 Accept 请求给半数以上的 Acceptor。注意:V 就是收到的响应中编号最大的提案的 value ,如果响应中不包含任何提案,那么V 就由 Proposer 自己决定。
-
如果 Acceptor 收到一个针对编号为 N 的提案的 Accept 请求,只要该 Acceptor 没有对编号
大于 N 的 Prepare 请求做出过响应,它就接受该提案。
-
Zookeeper
ZK Install
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | wget http://archive.apache.org/dist/zookeeper/zookeeper-3.3.3/zookeeper-3.3.3.tar.gz tar zxvf zookeeper-3.3.3.tar.gz cd zookeeper-3.3.3 cp conf/zoo_sample.cfg conf/zoo.cfg #配置 vi conf/zoo.cfg tickTime=2000 initLimit=10 syncLimit=5 dataDir=/home/dubbo/zookeeper-3.3.3/data clientPort=2181 #启动: ./bin/zkServer.sh start #停止 ./bin/zkServer.sh stop #测试 telnet 127.0.0.1 2181 ./zkCli.sh -server localhost:2181 |