zookeeper:

其实,我觉得要是深度理解zookeeper的工作状态挺难的,也非常深,我学完之后又看了很多大牛的博客,觉得自己理解的也不好,只能说是对zookeeper有个浅显的概念,或者浅显都称不上,觉得只是硬生生的记住了一些概念的东西,没有做过调优的工作,实在是不能写出什么东西,但是也勉强记一些我能理解的吧,毕竟这些枯燥的概念也是比较磨练心性的,能坐下来好好看一些概念不容易。后面我再贴上一张大牛的博客,对比着学习呗~~奋斗奋斗奋斗


先说说zookeeper的作用:

zookeeper是hadoop的一个子项目,雅虎创建的。

分布式系统基本上都是主从结构,所以需要zookeeper进行协调服务,他做很多事情的,比如命名服务,配置管理,集群管理,分布式协调通知等等,下面就具体说一些功能吧~~

1.在HBase中做什么?

确保整个集群中只有一个HMaster

监控HRegionSever的宕机

存储访问控制列表

2.在Storm中做什么?

保存storm集群和作业的所有信息

负责storm两个节点的通信

3.HA机制中做什么?

zookeeper监控NN的宕机然后由故障转移器激活另外一个standby状态的NN


再说说zookeeper的选举机制:

这个是个比较复杂的过程,首先应该注意的地方时,安装zookeeper集群的时候最好的单数节点,毕竟是选举。

Leader服务器是整个zookeeper集群工作的核心,负责进行选举投票的发起和决议,更新系统状态。

Follower服务器是zookeeper集群状态的跟随者,用于接收客户端的请求并向客户端返回结果,在选举过程中参与投票。

说一下我理解的过程吧,看到有错误的大牛们请及时帮我更正,我感激不尽感激不尽~~~大笑

1.每个Sever服务器启动以后都会询问其他的Sever服务器要投票给谁

2.对于其他服务器的询问,服务器每次都会根据自己的状态恢复自己推荐的Leader的id和上一次处理事务的zxid,但是系统启动的时候每个服务器都会推荐自己的

3.自己服务器收到其他所有的服务器回复以后,就计算出zxid最大的那个服务器,并将这个服务器相关信息设置成下一次要投票的Sever

4.计算的过程中获得的票数最多,且票数要过半数的服务器就选为Leader,否则要一直继续这个选举的过程,知道Leader被选举出来

5.选出的Leader开始等待其他服务器Follower的连接

6.Follower连接Leader将最大的zxid发送给Leader

7.Leader根据Follwer的zxid来确定同步点,,完成同步后通知Follower已经成为update(现时)状态

8.Follower收到update消息后,就可以接受Client的请求服务了。


下面贴上大牛的一篇博客,学习学习~

FastLeaderElection算法通过异步的通信方式来收集其它节点的选票,同时在分析选票时又根据投票者的当前状态来作不同的处理,以加快Leader的选举进程。    
    每个在zookeeper服务器启动先读取当前保存在磁盘的数据,zookeeper中的每份数据都有一个对应的id值,这个值是依次递增的;换言之,越新的数据,对应的ID值就越大。 
    在读取数据完毕之后,每个zookeeper服务器发送自己选举的leader,这个协议中包含了以下几部分的数据: 
1)、所选举leader的id(就是配置文件中写好的每个服务器的id) ,在初始阶段,每台服务器的这个值都是自己服务器的id,也就是它们都选举自己为leader。 
2)、服务器最大数据的id,这个值大的服务器,说明存放了更新的数据。 
3)、逻辑时钟的值,这个值从0开始递增,每次选举对应一个值,也就是说:如果在同一次选举中,那么这个值应该是一致的,逻辑时钟值越大,说明这一次选举leader的进程更新。 
4)、本机在当前选举过程中的状态,有以下几种:LOOKING,FOLLOWING,OBSERVING,LEADING 

    每台服务器将自己服务器的以上数据发送到集群中的其他服务器之后,同样的也需要接收来自其他服务器的数据,它将做以下的处理: 
A、如果所接收数据服务器的状态还是在选举阶段(LOOKING 状态),那么首先判断逻辑时钟值,又分为以下三种情况: 
a) 如果发送过来的逻辑时钟大于目前的逻辑时钟,那么说明这是更新的一次选举,此时需要更新一下本机的逻辑时钟值,代码如下: 

<span style="font-size:18px;">if (n.epoch > logicalclock) { </span>
<span style="font-size:18px;">logicalclock = n.epoch; recvset.clear();</span>
<span style="font-size:18px;"> if(totalOrderPredicate(n.leader, n.zxid,getInitId(), getInitLastLoggedZxid())) </span>
<span style="font-size:18px;">updateProposal(n.leader, n.zxid); </span>
<span style="font-size:18px;">else updateProposal(getInitId(),getInitLastLoggedZxid()); </span>
<span style="font-size:18px;">sendNotifications();</span>

其中的totalOrderPredicate函数就是根据发送过来的封包中的leader id,数据id来与本机保存的相应数据进行判断的函数(首先看数据id,数据id大者胜出;其次再判断leader id,leader id大者胜出),返回true则调用updateProposal函数更新数据。 
b) 发送过来数据的逻辑时钟小于本机的逻辑时钟 
说明对方在一个相对较早的选举进程中,这里只需要将本机的数据广播出去 
c) 两边的逻辑时钟相同,此时也只是调用totalOrderPredicate函数判断是否需要更新本机的数据,将最新的选举结果广播出去 


B、如果所接收服务器不在选举状态,也就是在FOLLOWING或者LEADING状态 
a) 如果逻辑时钟相同,将该数据保存到recvset,如果所接收服务器宣称自己是leader,那么将判断是不是有半数以上的服务器选举它,如果是则设置选举状态退出选举过程 
b) 否则这是一条与当前逻辑时钟不符合的消息,那么说明在另一个选举过程中已经有了选举结果,于是将该选举结果加入到outofelection集合中,再根据outofelection来判断是否可以结束选举,如果可以也是保存逻辑时钟,设置选举状态,退出选举过程 

以一个简单的例子来说明整个选举的过程. 
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么 

1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态  
2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.  
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader.  
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了.  
5) 服务器5启动,同4一样,当小弟










Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐