zookeeper整理:paxos算法学习
贴大佬的博客:大佬整理的paxos解析
分布式逃不开的问题
CAP原则
也叫CAP定理,指的是在一个分布式系统中,有三个非常重要的特性:一致性C、可用性A、分区容错性P
-
一致性(Consistency)
分布式系统中的所有主机在同一时刻是否可以保证具有完全相同的数据备份,若具有,则该分布式系统具有一致性
-
可用性(Availability)
在集群中,部分节点发生故障后,是否会影响对客户端读写请求的响应,注意,若在短时间内会影响,其也不具有这里说说的"可用性"
-
分区容错性(Partition tolerance)
分布式系统中的一台主机称为一个分区,分布式系统中各个主机无法保证数据的一致性,即不具有一致性是一种错误;
分布式系统无法及时响应客户端请求,即不具有可用性也是一种错误;
对于分布式系统,必须要具有对这些错误的"包容性",即容错性,这是必须得!!!!!!!!!!
不可兼得
上面已经说明,分区容错性是分布式系统必须考虑的
为了保证可用性,肯定要增加节点,此时可用性确实提升。但节点的增多带来的问题是,这么多的节点之间的数据同步是一个很多的消耗,极其容易造成数据不一致。
当我们强调一致性的时候,节点越少,数据同步的消耗就小,但带来的节点少却又造成服务的可用性差。
所以一致性和可用性是不可兼顾的,他们处于一个对立面!
组合
明白了基本的原理,可以知道可能的组合有3
CA :单点应用的选择,因为没有分区
以下两种就是分布式系统的取舍选择组合,无论是CP还是AP都不代表完全放弃了另外一个,只是弱支持
CP:强调一致性,放弃一些可用性,如Zookeeper,选举过程会短暂的使系统不可用,如银行系统必须要求数据一致
AP:强调可用性,放弃一些一致性,比如一些退款业务,2小时内到账这样,在用户接受的范围内满足要求
主角Paxos
前面都是铺垫,为了引出paxos,zookeeper遵循CP原则,强调一致性
那么问题来了,如何保证分布式系统一致性?
paxos算法!目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致。
zookeeper的底层原理ZAB协议就是基于paxos提出的
所以要先搞懂paxos算法
拜占庭将军问题
网上抄来的介绍:
是指拜占庭帝国军队的将军们必须全体一致的决定是否攻击某一支敌军。问题是这些将军在地理上是分隔开来的,只能依靠通讯员进行传递命令,但是通讯员中存在叛徒,它们可以篡改消息,叛徒可以欺骗某些将军采取进攻行动;促成一个不是所有将军都同意的决定,如当将军们不希望进攻时促成进攻行动;或者迷惑某些将军,使他们无法做出决定。
一句话:你的集群内网络是安全的,不存在通信的消息被篡改的情况
而paxos算法的大前提就是你的分布式系统不存在拜占庭将军问题
当然一般情况下确实是不存在这个问题的,大多数系统都是部署在一个局域网中,因此消息被篡改的情况很罕见;另一方面,由于硬件和网络原因而造成的消息不完整问题,只需要一套简单的校验算法即可。
角色
非常有意思的是paxos算法可以通过一个简单的故事描述出来,这个故事中有三个角色:
Proposer :提议者,提出意见 (议员)
Acceptor:接受者,接受意见 or 拒绝意见 (议员)
Learner:只能接受最后的结果意见 (平民)
而paxos算法的故事也是在这几个角色之间展开的
故事背景
- 有一个叫做Paxos的小岛上面住了一批居民,岛上面所有的事情由一些特殊的人决定,他们叫做议员。
- 议员的总数是确定的,不能更改。(这是个关键点)
- 岛上每次环境事务的变更都需要通过一个提议,每个提议都有一个编号,这个编号是一直增长的,不能倒退。
- 每个提议都需要超过半数的议员同意才能生效。(非常重要)
- 每个议员只会同意大于当前编号的提议,包括已生效的和未生效的。
- 如果议员收到小于等于当前编号的提议,他会拒绝,并告知对方:你的提议已经有人提过了。这里的当前编号是每个议员在自己记事本上面记录的编号,他不断更新这个编号。整个议会不能保证所有议员记事本上的编号总是相同的。
- 现在议会有一个目标:保证所有的议员对于提议都能达成一致的看法。
过半原则
前面的故事背景里面有特别的提到 : 每个提议都需要超过半数的议员同意才能生效
这就是所谓的过半原则
Paxos基于的过半数学原理: 我们称大多数(过半)进程组成的集合为法定集合,两个法定(过半)集合必然存在非空交集,即至少有一个公共进程,称为法定集合性质。 例如A,B,C,D,F进程组成的全集,法定集合Q1包括进程A,B,C,Q2包括进程B,C,D,那么Q1和Q2的交集必然不在空,C就是Q1,Q2的公共进程。如果要说Paxos最根本的原理是什么,那么就是这个简单性质。也就是说:两个过半的集合必然存在交集,也就是肯定是相等的,也就是肯定达成了一致。
举个例子:3个人,一个提议,只要2个人同意就算通过;4个人,一个提议,要3个人同意才算通过
提议过程
一般有两阶:
-
阶段一(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对其发出的编号为N的Prepare请求的响应,那么它就会发送一个针对[N,V]提案的Accept请求给半数以上的Acceptor。
活锁
咋一看paxos没啥问题,但在极端情况下会出现活锁
解决活锁问题
选主,只有主能提Propose,其他人想提只能告诉主,让主来提出