zookeeper基础整理

zookeeper简述

        ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件

        ZooKeeper 使用 Java 所编写,但是支持 Java 和 C 两种编程语言。

提供的功能包括:
        配置管理:集群中配置文件的同步
        分布式锁:解决分布式环境中数据同步问题
        集群管理:负载均衡,容灾处理等。
        命名服务:
        其他等等

1、zookeeper工作原理

        Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

        为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

        每个Server在工作过程中有三种状态:
                LOOKING:当前Server不知道leader是谁,正在搜寻
                LEADING:当前Server即为选举出来的leader
                FOLLOWING:leader已经选举出来,当前Server与之同步

2、zookeeper数据同步过程:

选完leader以后,zk就进入状态同步过程。
1. leader等待server连接;
2 .Follower连接leader,将最大的zxid发送给leader;
3 .Leader根据follower的zxid确定同步点;
4 .完成同步后通知follower 已经成为uptodate状态;
5 .Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。
流程图如下所示:
这里写图片描述

3、zookeeper工作流程

1、Leader工作流程

Leader主要有三个功能:
        1 .恢复数据;
        2 .维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;
       3 .Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。
        PING消息是指Learner的心跳信息;
        REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;
        ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;
        REVALIDATE消息是用来延长SESSION有效时间。

        Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。
这里写图片描述

2、Follower工作流程

Follower主要有四个功能:
        1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
        2 .接收Leader消息并进行处理;
        3 .接收Client的请求,如果为写请求,发送给Leader进行投票;
        4 .返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:
        1 .PING消息:心跳消息;
        2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;
        3 .COMMIT消息:服务器端最新一次提案的信息;
        4 .UPTODATE消息:表明同步完成;
        5 .REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;
        6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

        Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的。
这里写图片描述
        observer流程和Follower的唯一不同的地方就是observer不会参加leader发起的投票。

4、zookeeper中session的状态

        我们知道ZooKeeper允许客户端创建两种类型的节点:persistent、ephemeral,ephemeral类型的节点是与创建它的客户端一起共存亡的。

        那么这中间就有问题,ZooKeeper是如何知道客户端还存不存在呢?

        ZooKeeper是使用session来解决这个问题的,这也是为什么我们在客户端创建ZooKeeper实例时需要传入一个sessionout的参数。当客户端与Follower连接时,实际上是成功创建了一个session,Follower和Leader都保存了这个session信息(实际上Session的建立也是需要Leader同意的)。一方面,客户端会定期的向Follower发送Ping包来告诉这个Follower我还活着;另一方面,Leader也会定期向Follower发送ping包,一则检测它的Follower们是否至少有超过一半还活着,二则Follower们返回他们各自正在服务的客户端(未超时的session),来告诉Leader那些客户端还活着,这样Leader就可以删除那些客户端已经不存在的ephemeral类型的节点

5、zookeeper中的选举算法

        我们有一个zookeeper集群,有好几个节点。每个节点都可以接收请求,处理请求。那么,如果这个时候分别有两个客户端向两个节点发起请求,请求的内容是修改同一个数据。比如客户端c1,请求节点n1,请求是set a = 1; 而客户端c2,请求节点n2,请求内容是set a = 2;
那么最后a是等于1还是等于2呢? 这在一个分布式环境里是很难确定的。解决这个问题有很多办法,而zookeeper的办法是,我们选一个总统出来,所有的这类决策都提交给总统一个人决策,那之前的问题不就没有了么。

        如何在zookeeper集群中选举出一个leader,zookeeper使用了三种算法,具体使用哪种算法,在配置文件中是可以配置的,对应的配置项是”electionAlg”,其中1对应的是LeaderElection算法,2对应的是AuthFastLeaderElection算法,3对应的是FastLeaderElection算法.默认使用FastLeaderElection算法.

logicalclock -》逻辑时钟
Epoch -》 epoch,zxid的高32,表示leader的变动,选举的轮数,即逻辑时钟。Epoch会随着选举轮数的增加而递增。
zxid -》 事务id号,每个操作都有一个zxid, 64位
server id -》配置的myid,服务器编号

1、第一阶段:数据恢复阶段
        首先,每个在zookeeper服务器先读取当前保存在磁盘的数据,zookeeper中的每份数据,都有一个对应的id值,这个值是依次递增的,换言之,越新的数据,对应的ID值就越大.
2、第二阶段:首次发送自己投票信息
        在读取数据完毕之后,每个zookeeper服务器发送自己选举的leader,这个协议中包含了以下几部分的数据:
        2.1所选举leader的id(就是配置文件中写好的每个服务器的id) ,在初始阶段,每台服务器的这个值都是自己服务器的id,也就是它们都选举自己为leader.
        2.2 服务器最大数据的id,这个值大的服务器,说明存放了更新的数据.
        2.3逻辑时钟的值,这个值从0开始递增,每次选举对应一个值,也就是说
                2.3.1 如果在同一次选举中,那么这个值应该是一致的
                2.3.2 逻辑时钟值越大,说明这一次选举leader的进程更新.
        2.4 本机在当前选举过程中的状态,有以下几种:LOOKING,FOLLOWING,OBSERVING,LEADING。
3、第三阶段:接受其他机器的选举信息
        3.1如果所接收数据服务器的状态还是在选举阶段(LOOKING 状态),那么首先判断逻辑时钟值,又分为以下三种情况:
                3.1.1:如果发送过来的逻辑时钟大于目前的逻辑时钟,那么说明这是更新的一次选举,此时需要更新一下本机的逻辑时钟值,同时将之前收集到的来自其他服务器的选举清空,因为这些数据已经不再有效了.然后判断是否需要更新当前自己的选举情况.在这里是根据选举leader id,保存的最大数据id来进行判断的,这两种数据之间对这个选举结果的影响的权重关系是:首先看数据id,数据id大者胜出;其次再判断leader id,leader id大者胜出.然后再将自身最新的选举结果(也就是上面提到的三种数据广播给其他服务器)
                3.1.2: 发送过来数据的逻辑时钟小于本机的逻辑时钟,说明对方在一个相对较早的选举进程中,这里只需要将本机的数据发送过去就是了.
                3.1.3:两边的逻辑时钟相同,此时也只是调用totalOrderPredicate函数判断是否需要更新本机的数据(首先看数据id,数据id大者胜出;其次再判断leader id,leader id大者胜出.),如果更新了再将自己最新的选举结果广播出去就是了

        3.2:三种情况的处理完毕之后,再处理两种情况:
                3.2.1:服务器判断是不是已经收集到了所有服务器的选举状态,如果是那么根据选举结果设置自己的角色(FOLLOWING还是LEADER),然后退出选举过程就是了.
                3.2.2:即使没有收集到所有服务器的选举状态,也可以判断一下根据以上过程之后最新的选举leader是不是得到了超过半数以上服务器的支持,如果是,那么尝试在200ms内接收一下数据,如果没有新的数据到来,说明大家都已经默认了这个结果,同样也设置角色退出选举过程.

        3.3: 如果所接收服务器不在选举状态,也就是在FOLLOWING或者LEADING状态,做以下两个判断:
                3.3.1:如果逻辑时钟相同,将该数据保存到recvset,如果所接收服务器宣称自己是leader,那么将判断是不是有半数以上的服务器选举它,如果是则设置选举状态退出选举过程
                3.3.2 否则这是一条与当前逻辑时钟不符合的消息,那么说明在另一个选举过程中已经有了选举结果,于是将该选举结果加入到outofelection集合中,再根据outofelection来判断是否可以结束选举,如果可以也是保存逻辑时钟,设置选举状态,退出选举过程.(从这里可以看出,当某个节点已经确定选举结果不再处于LOOKING状态时,其收到LOOKING消息时都会直接回应选举的最终结果。结合上面那个比方,相当于某次选举结束了,这个时候来了选民4又发起一次新的选举,那么其他选民就直接告诉它当前的Leader情况)

zookeeper原理白话说明:

        Paxos描述了这样一个场景,有一个叫做Paxos的小岛(Island)上面住了一批居民,岛上面所有的事情由一些特殊的人决定,他们叫做议员(Senator)。议员的总数(Senator Count)是确定的,不能更改。岛上每次环境事务的变更都需要通过一个提议(Proposal),每个提议都有一个编号(PID),这个编号是一直增长的,不能倒退。每个提议都需要超过半数((Senator Count)/2 +1)的议员同意才能生效。每个议员只会同意大于当前编号的提议,包括已生效的和未生效的。如果议员收到小于等于当前编号的提议,他会拒绝,并告知对方:你的提议已经有人提过了。这里的当前编号是每个议员在自己记事本上面记录的编号,他不断更新这个编号。整个议会不能保证所有议员记事本上的编号总是相同的。现在议会有一个目标:保证所有的议员对于提议都能达成一致的看法。

        好,现在议会开始运作,所有议员一开始记事本上面记录的编号都是0。有一个议员发了一个提议:将电费设定为1元/度。他首先看了一下记事本,嗯,当前提议编号是0,那么我的这个提议的编号就是1,于是他给所有议员发消息:1号提议,设定电费1元/度。其他议员收到消息以后查了一下记事本,哦,当前提议编号是0,这个提议可接受,于是他记录下这个提议并回复:我接受你的1号提议,同时他在记事本上记录:当前提议编号为1。发起提议的议员收到了超过半数的回复,立即给所有人发通知:1号提议生效!收到的议员会修改他的记事本,将1好提议由记录改成正式的法令,当有人问他电费为多少时,他会查看法令并告诉对方:1元/度。

        现在看冲突的解决:假设总共有三个议员S1-S3,S1和S2同时发起了一个提议:1号提议,设定电费。S1想设为1元/度, S2想设为2元/度。结果S3先收到了S1的提议,于是他做了和前面同样的操作。紧接着他又收到了S2的提议,结果他一查记事本,咦,这个提议的编号小于等于我的当前编号1,于是他拒绝了这个提议:对不起,这个提议先前提过了。于是S2的提议被拒绝,S1正式发布了提议: 1号提议生效。S2向S1或者S3打听并更新了1号法令的内容,然后他可以选择继续发起2号提议。

        好,我觉得Paxos的精华就这么多内容。现在让我们来对号入座,看看在ZK Server里面Paxos是如何得以贯彻实施的

小岛(Island)——ZK Server Cluster
议员(Senator)——ZK Server
提议(Proposal)——ZNode Change(Create/Delete/SetData…)
提议编号(PID)——Zxid(ZooKeeper Transaction Id)
正式法令——所有ZNode及其数据

        貌似关键的概念都能一一对应上,但是等一下,Paxos岛上的议员应该是人人平等的吧,而ZK Server好像有一个Leader的概念。没错,其实Leader的概念也应该属于Paxos范畴的。如果议员人人平等,在某种情况下会由于提议的冲突而产生一个“活锁”(所谓活锁我的理解是大家都没有死,都在动,但是一直解决不了冲突问题)。Paxos的作者Lamport在他的文章”The Part-Time Parliament“中阐述了这个问题并给出了解决方案——在所有议员中设立一个总统,只有总统有权发出提议,如果议员有自己的提议,必须发给总统并由总统来提出。好,我们又多了一个角色:总统。

总统——ZK Server Leader

        又一个问题产生了,总统怎么选出来的?oh, my god! It’s a long story.
现在我们假设总统已经选好了,下面看看ZK Server是怎么实施的。
情况一:

        屁民甲(Client)到某个议员(ZK Server)那里询问(Get)某条法令的情况(ZNode的数据),议员毫不犹豫的拿出他的记事本(local storage),查阅法令并告诉他结果,同时声明:我的数据不一定是最新的。你想要最新的数据?没问题,等着,等我找总统Sync一下再告诉你。

情况二:

        屁民乙(Client)到某个议员(ZK Server)那里要求政府归还欠他的一万元钱,议员让他在办公室等着,自己将问题反映给了总统,总统询问所有议员的意见,多数议员表示欠屁民的钱一定要还,于是总统发表声明,从国库中拿出一万元还债,国库总资产由100万变成99万。屁民乙拿到钱回去了(Client函数返回)。

情况三:

        总统突然挂了,议员接二连三的发现联系不上总统,于是各自发表声明,推选新的总统,总统大选期间政府停业,拒绝屁民的请求。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值