深入理解zookeeper

ぐ巨炮叔叔 提交于 2020-02-21 11:30:58

看过了倪超老师的《从Paxos到Zookeeper分布式一致性原理与实践》,很受启发,所以在此记录本书的重要知识点,以便以后的重温和回顾

一、初识分布式
1、从ACID
ACID:原子性、一致性、隔离性、持久性
2、CAP定理
一个分布式系统不可能同时满足一致性、可用性和分区容错性,这三个基本需求最多只能同时满足其中两项。在分布式环境中一致性是指数据在多个副本之间能够保持一致的特性。可用性是指系统提供的服务必须一直处于可用的状态。分区容错性约束了一个分布式系统需要具有以下特性: 分布式系统在遇到任何网络分区错误的时候仍然需要能够需要保证对外提供一致性和可用性的服务,除非是整个网络环境中发生了故障。网络分区指的是在分布式系统中,不同的节点分布在不同的子网络(机房或者异地网络)中,由于一些特殊原因导致这些子系统之间出现通讯不连通的情况,但是子系统的内部网络是正常的,从而导致整个系统的网络环境被切分成若干个孤立的区域。
CAP定理应用:一个分布式系统不可能同时满足一致性、可用性和分区容错性,只能放弃其中一个从而满足另外两个特性,如图:
在这里插入图片描述
3、BASE理论
BASE理论指的是基本可用、软状态、最终一致性
基本可用:基本可用是指分布式系统出现不可预知故障的时候,允许损失部分可用性。(1)相应时间上的损失 (2)功能上的损失
软状态:指系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
最终一致性:最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终达到了一个一致的状态。

二、一致性协议
1、2PC
阶段一:(1)事务询问(2)执行事务(3)各参与者向协调者反馈事务询问响应
阶段二:执行事务提交,如果反馈全部都是YES,则提交事务,如果至少有一个是NO,则执行事务回滚
2PC存在一个非常致命的问题:数据有可能会导致不一致,在二阶段提交的第二阶段执行事务提交的时候,当协调者向所有参与者发送commit请求之后,发生了局部网络异常或者或者协调者尚未发送commit请求之前自身发生了崩溃,最终导致只有部分参与者收到了commit请求,于是这部分收到commit请求的参与者就会进行事务提交,而其他没有收到commit请求的参与者则无法进行事务提交,于是整个系统就存在不一致的现象。
2PC还存在另外一个比较严重的问题,单点故障,由于协调者十分重要,一旦协调者发生故障,参与者会一直阻塞下去
2、3PC
阶段一:CanCommit,(1)事务询问(2)各参与者向协调者反馈事务询问响应
阶段二:PreCommit,在阶段二中,协调者会根据各参与者的反馈情况来决定是否可以进行事务的PreCommit操作。
阶段三:doCommit,该阶段进行真正的事务提交
三阶段提交的优点:相比较于二阶段提交协议,三阶段提交协议最大的优点就是降低了参与者的阻塞范围,并且能够在达到了单点故障后继续达成一致,一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
三阶段提交的缺点:三阶段提交在去除阻塞的同时也引入了新的问题,那就是参与者接收到PreCommit命令后,如果网络出现分区,此时协调者所在的节点和参与者无法进行正常的网络通信。在这种情况下,参与者依然会进行事务提交,这必然出现数据不一致。
3、举例说明2PC和3PC的区别
假设有一个决策小组由一个主持人负责与多位组员以电话联络方式协调是否通过一个提案,以两阶段提交来说,主持人收到一个提案请求,打电话给每个组员询问是否通过并统计回复,然后将最后决定打电话通知给组员。要是主持人在跟第一位组员通完电话后失忆,而第一位组员在得知结果并执行后得了老年痴呆,那么即使重新选出主持人,也没人知道最后的提案决定是什么,也许是通过,也许是驳回,不管大家选择哪一种决定,都有可能与第一位组员执行的真实决定不一致,老板就会不开心觉得沟通小组有问题而解雇大家。三阶段提交即是引入另一个步骤,主持人打电话给组员通知请准备通过提案,以避免没人知道真实决定而造成不一致失业危机。为什么能解决二阶段提交的问题呢?回到刚刚提到的状况,在主持人通知完第一位组员请准备通过后两人意外失忆,即使没人知道全体在第一阶段的决定为何,全体决策组员仍可以重新协调过程或直接拒绝,不会有不一致决定而失业。那么当主持人通知完全体组员请准备通过并得到大家的再次确认后进入第三阶段,当主持人通知第一位组员请通过提案后两人失忆,这时候其他组员重新选出主持人后,仍可以知道目前至少是处于准备通过提案阶段,表示第一阶段大家都已经决定要通过了,此时便可直接通过。
4、Paxos算法
强一致性算法“多数派”无法解决并发问题,所以paxos才被提出
(1)basic paxos:
角色介绍:
Client:系统外部角色,请求的发起者。像民众
Proposer:接受Client请求,向集群提出提议(propose)。并在发生冲突时,起到冲突调节的作用。像议员,替民众提出议案。
Acceptor(Voter):提议投票和接收者,只有在形成法定人数(多数派)时,提议才会最终接受。
Learner:提议接收者,backup备份,对集群一致性没什么影响,像记录员
步骤、阶段:
1、Phase 1a:Prepare
proposer提出一个提案,编号为N,此N大于这个proposer之前提出提案的编号,请求acceptors接受
2、Phase 1b:Promise
如果N大于此acceptor之前接受的任何提案编号则接受,否则拒绝
3、Phase 2a:Accept
如果达到了多数派,proposer会发出accept请求,此请求包含提案编号N,以及提案内容
4、Phase 2b:Accepted
如果此acceptor在此期间没有收到任何编号大于N的提案,则接受此提案内容,否则忽略
成功流程:
在这里插入图片描述
单点失败流程:
在这里插入图片描述单点失败的时候,只要达到了多数派,请求就可以被接受
proposer失败:
在这里插入图片描述
当proposer失败的时候,请求不会被接受,当proposer被重新启动起来,会重新提出一个编号+1的流程

潜在问题:活锁问题,不停的有不同的议员来提出提案,这样导致接收者还没接受的时候,就有新提案不停的提出,解决问题是增加一个random的等待时间。basic paxos有两轮RPC,所以效率很低而且工业难实现。

(2)Multi Paxos
新概念:Leader,唯一的proposer,所有请求都经过此leader
基本流程:
在这里插入图片描述也是两轮RPC,第一轮RPC是leader竞选过程(Prepare过程),第二轮RPC是发送请求,只有leader的时候会有两轮RPC,当竞选上后就只有一轮RPC了。
减少角色,进一步简化:
在这里插入图片描述第一轮RPC从Servers中选举leader,第二轮RPC从leader向其余servers发送请求。

三、Zookeeper
1、Zookeeper是一个开源的分布式协调服务,设计的目的是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集。
2、Zookeeper将全量数据保存在内存中,一个Zookeeper集群只要半数以上的机器正常工作,那么整个集群就能正常对外服务,Zookeeper的客户端会选择和集群中的任意一台机器共同创建一个TCP连接,如果连接断开,客户端会自动连接到集群中的其他机器。对于客户端来的请求,Zookeeper会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序。
3、集群角色:
Leader、Follower、Observer
Session:服务端和客户端的一个TCP长连接,当由于各种原因连接断掉后,只要在sessionTimeout规定的时间内能够连上集群中任意一台服务器,那么当前会话仍然是有效的。
Znode:节点分为机器节点和数据节点,数据节点称之为Znode,Zookeeper将所有数据存储在内存中,数据模型是一棵树,由斜杠进行分割,Znode可以分为持久节点和临时节点两类,持久节点指一旦创建了除非主动进程Znode移除操作,否则这个节点会一直保存在Zookeepeer上,临时节点就不一样了,它的生命周期和客户端会话绑定
版本:Stat(version-当前ZNode版本,cversion-当前ZNode子节点版本,aversion-当前ZNode的ACL版本)
Watch:监听器
ACL:ACL是一个策略,用来进行权限控制,有五种权限CREATE、READ、WRITE、DELETE、ADMIN
4、Zookeeper的ZAB协议
ZAB协议是专门为Zookeeper设计的一种崩溃恢复的原子广播协议,Zookeeper使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器数据的状态变更以事务的形式广播到所有的副本进程上去。ZAB协议的这个主备模型架构保证了同一时刻集群中只能够有一个主进程来广播服务器的状态变更。
4.1 ZAB协议的具体内容:
(1)崩溃恢复
当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader服务器,当选举产生了Leader服务器并有超过半数的Follower完成了状态同步后,ZAB协议就会退出恢复模式,其中所谓的状态同步指的是数据同步。当集群中超过半数Follower服务器完成了和Leader的状态同步,那么整个架构就可以进入消息广播模式了。
(2)消息广播
ZAB协议的消息广播过程使用的是一个原子广播协议,类似于二阶段提交过程
在这里插入图片描述和传统的二阶段提交不同,ZAB的消息广播移除了中断逻辑,既如果有超过半数的Follower服务器反馈Ack,则就开始提交事务了,但是这种简化二阶段提交过程无法处理Leader服务器崩溃导致的不一致,所以在ZAB中添加了崩溃恢复模式来解决这个问题。在消息广播过程中,Leader服务器会为每一个Follower服务器都各自分配一个单独的队列,然后将需要广播的事务一次放入这些队列中,根据FIFO策略进行消息发送。每一个Follower在接收到这个事务后,都会首先以日志的形式写入到本地磁盘中去,并且在成功写入后反馈给Leader一个Ack响应
(选举算法如何保证最终一致性?)
4.2 数据同步和崩溃恢复的具体细节
一旦 Leader 节点崩溃,或者由于网络问题导致 Leader 服务器失去了过半的 Follower 节点的联系(leader 失去与过半 follower 节点联系,可能是 leader 节点和 follower 节点之间产生了网络分区,那么此时的 leader 不再是合法的 leader 了),那么就 会进入到崩溃恢复模式。
(1)Leader选举算法:
SID:服务器ID(用SID来唯一标识Zookeeper集群中的机器,每台机器都不能重复,和myid的值一致)
ZXID:事务ID,ZXID是一个事务ID,用来唯一标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID都不一定一致。ZXID由两部分组成zxid的64位,高32位是epoch编号(相当于皇帝leader的年号,每次改朝换代都会在前一个年号上面+1),低32位是counter消息计数器(每收到一条事务消息这个值就+1)。
(2)Leader选举
1、启动时候的Leader选举:
每个节点启动的时候都是looking状态,假设有三台机器server1、server2、server3。每个Server发出一个投票,由于是初始状态,Server1和Server2都会为自己作为Leader服务器来进行投票,每次投票会包含所推举的服务器的myid和ZXID,使用(myid,ZXID)来表示,此时Server1的投票为(1,0),Server2的投票为(2,0),然后各自将这个投票发给集群中其他的服务器。
集群的每个机器接收到各个服务器的投票后,首先判断投票的有效性,如检查是否是本轮的投票、是否来自Looking状态的服务器。
处理投票,针对每一个投票,服务器都需要将别人的投票和自己的投票进行pk,pk规则如下:
首先检查ZXID。ZXID比较大的服务器优先作为Leader(ZXID最大的服务器,它处理的事务一定是最新的)
如果ZXID相同,那么久比较myid,myid最大的服务器作为Leader
对于Server1和Serve2,Server1的投票是(1,0),Server2的投票是(2,0),两台机器更新自己的投票(都投出Server2),它就会向集群中所有机器再次发出上一次投票即可
统计投票,每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,如果有的话,便选出了Leader
改变服务器状态
2、运行过程中的Leader选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。
变更状态。Leader 挂后,余下的非 Observer 服务器都会将自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
每个 Server 会发出一个投票。在运行期间,每个服务器上的 ZXID 可能不同,此时假定 Server1 的 ZXID 为123,Server3的ZXID为122;在第一轮投票中,Server1和 Server3 都会投自己,产生投票(1, 123),(3, 122),然后各自将投票发送给集群中所有机器。接收来自各个服务器的投票。与启动时过程相同。
处理投票。与启动时过程相同,此时,Server1 将会成为 Leader。
统计投票。与启动时过程相同。
改变服务器的状态。与启动时过程相同
4.3 ZAB和Paxos算法的联系与区别
联系:(1)两者都存在一个类似于Leader进程的角色,由其负责协调多个Follower进程的运行
(2)Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提案进行提交
(3)在ZAB协议中,每个Proposal中都包含一个epoch值,用来代表当前的Leader周期,在Paxos算法中,同样存在这样的一个标识,只是名字变成了Ballot
区别:在Paxos算法中,一个新的选举产生的主进程会进行两个阶段的工作,第一个阶段称为读阶段,在这个阶段中,这个新的主进程会通过和所有其他进程进行通信的方式来收集上一个主进程提出的提案,并将它们提交。第二个阶段称为写阶段,在这个阶段,当前主进程开始提出它自己的提案。在Paxos算法设计的基础上,ZAB协议额外添加了一个同步阶段。在同步阶段之前,ZAB协议也存在一个和Paxos算法中的读阶段非常类似的过程,称为发现阶段,在同步阶段中,新的Leader会确保存在过半的Follower已经提交了之前Leader周期中的所有事务,这一同步阶段的引入,能够有效的保证Leader在新的周期中提出事务之前,所有的进程都已经完成了对之前所有事务的提交,一旦完成同步阶段后,那么ZAB就会执行和Paxos算法类似的写阶段。总的来说ZAB和Paxos算法的本质区别在于,两者的设计目标不太一样,ZAB协议主要用于构建一个高可用的分布式数据主备系统,例如Zookeeper,而Paxos算法则是用于构建一个分布式的一致性状态机系统。
4.4 RAFT协议
Raft协议的每个副本都会处于三种状态之一:Leader、Follower、Candidate。
(1)Leader election:投票策略,当投票被瓜分后,所有的candidate同时超时,然后有可能进入新一轮的票数被瓜分,为了避免这个问题,Raft采用一种很简单的方法:每个Candidate的election timeout从150ms-300ms之间随机取,那么第一个超时的Candidate就可以发起新一轮的leader election,带着最大的term_id给其它所有server发送RequestVoteRPC消息,从而自己成为leader,然后给他们发送心跳消息以告诉他们自己是主。
(2)Log Replication: 经过自己玩https://raft.github.io/得出结论
1、只有偏移量最高的节点能被选为leader
2、如果follower恢复了,则会自动同步偏移量
3、只有达到多数派后,日志才会真正的被写入
4、当日志在半写入状态挂掉了,再启动后发现有新的偏移量日志,则会舍弃自己半写入的日志
5、使用Zookeeper实现分布式锁
public class main {
static String lock_path = “/curator_recipes_lock_path”;
static CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(“domin1.book.zookeeper:2181”)
.retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
public static void main(String args[]) throws Exception{
client.start();
final InterProcessMutex lock = new InterProcessMutex(client, lock_path);
final CountDownLatch down = new CountDownLatch(1);
for(int i=0;i<30;i++){
new Thread(new Runnable() {
@Override
public void run() {
try{
down.await();
lock.acquire();
}catch(Exception e){
e.printStackTrace();
}
SimpleDateFormat sdf = new SimpleDateFormat(“HH:mm:ss|SSS”);
String orderNo = sdf.format(new Date());
System.out.println("生成订单号 : "+ orderNo);
try{
lock.release();
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}
down.countDown();
}
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!