zookeeper源码分析之leader选举
zookeeper提供顺序一致性、原子性、统一视图、可靠性保证服务
zookeeper使用的是zab(atomic broadcast protocol)协议而非paxos协议
zookeeper能处理并发地处理多个客户端的写请求,并且以FIFO顺序commit这些写操作,zab采用了一个事务ID来实现事务的全局有序性,
在Zab协议的实现时,分为三个阶段:
1、 Leader Election
2、 Recovery Phase
3、 Broadcast Phase
今天就先分析选举算法的源码实现
zookeeper默认选举算法为FastLeaderElection.java。其主要方法为FastLeaderElection.lookForLeader,该接口是一个同步接口,直到选举结束才会返回。选举的结果保存在类Vote中
选举整体过程主要流程可概括为下图:
来看源码实现
1.//首先logicalclock自增, 在这里logicalclock表示本次选举的id,逻辑时钟的值,这个值从0开始递增,每次选举对应一个值,如果在同一次选举中,这个值是一样的,逻辑时钟值越大,说明该节点上的这一次选举leader的进程更加新
- synchronized(this){
- logicalclock++;
- //如果自己不是OBSERVER,则投给自己
- updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());
- }
2.sendNotifications();向所有的node发送notification消息,其主方法:
- ToSend notmsg = new ToSend(ToSend.mType.notification,proposedLeader, proposedZxid,logicalclock,QuorumPeer.ServerState.LOOKING,sid,proposedEpoch);
- 消息格式:
- mType type 消息类型
- long leader 推荐的leader的id,就是配置文件中写好的每个服务器的id
- long zxid 推荐的leader的zxid,zookeeper中的每份数据,都有一个对应的zxid值,越新的数据,zxid值就越大
- long epoch, logicalclock
- ServerState state, 本节点的状态
- long sid 本节点的 id,即myid
发送完添加到到发送队列中
3.当该节点的状态为LOOKING且没有stop时,就一直loop到选出leader为止
- //从消息队列中接收消息
- Notification n = recvqueue.poll(notTimeout, TimeUnit.MILLISECONDS);
- //如没有接收到消息,则检查manager.haveDelivered(),如果已经全部发送出去了,就继续发送,一直到选出leader为止。否则就重新连接。
- if(manager.haveDelivered()){
- sendNotifications();
- } else {
- manager.connectAll();
- }
- int tmpTimeOut = notTimeout*2;//延长超时时间
- notTimeout = (tmpTimeOut < maxNotificationInterval? tmpTimeOut : maxNotificationInterval);
4.如果收到回应消息,则检查回应应状态,回应状态有以下四种:LOOKING、OBSERVING、FOLLOWING、LEADING
5.下面分析最核心的LOOKING状态:
- case LOOKING:
- // If notification > current, replace and send messages out
- if (n.electionEpoch > logicalclock) {//该节点的epoch大于 logicalclock,表示当前新一轮的选举
- logicalclock = n.electionEpoch;//更新本地的logicalclock
- recvset.clear();//清空接收队列recvset
- //调用totalOrderPredicate决定是否更新自己的投票,依次比较选举轮数epoch,事务zxid,服务器编号server id(myid)
- if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {
- updateProposal(n.leader, n.zxid, n.peerEpoch);//把投票修改为对方的
- } else {
- updateProposal(getInitId(),getInitLastLoggedZxid(), getPeerEpoch());
- }
- sendNotifications();//广播消息
- } else if (n.electionEpoch < logicalclock) {//如果该节点的epoch小于logicalclock,则忽略
- break;
- } else if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,proposedLeader, proposedZxid, proposedEpoch)) {
- updateProposal(n.leader, n.zxid, n.peerEpoch);
- sendNotifications();
- }
- recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));//把从该节点的信息发到recvset中,表明已经收到该节点的回应
- //通过termPredicate函数判断recvset是否已经达到法定quorum,默认超过半数就通过
- if (termPredicate(recvset, new Vote(proposedLeader, proposedZxid, logicalclock, proposedEpoch))) {
- // Verify if there is any change in the proposed leader
- while((n = recvqueue.poll(finalizeWait, TimeUnit.MILLISECONDS)) != null){//循环,一直等新的notification到达,直到超时
- if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch, proposedLeader, proposedZxid, proposedEpoch)){
- recvqueue.put(n);
- break;
- }
- }
- if (n == null) {//确定leader
- self.setPeerState((proposedLeader == self.getId()) ?ServerState.LEADING: learningState());
- Vote endVote = new Vote(proposedLeader, proposedZxid, proposedEpoch);
- leaveInstance(endVote);//清空接收队列
- return endVote;
- }
- }
- /*
- *
- * 返回true说明需要更新数据
- * We return true if one of the following three cases hold:
- * 1- New epoch is higher
- * 2- New epoch is the same as current epoch, but new zxid is higher
- * 3- New epoch is the same as current epoch, new zxid is the same
- * as current zxid, but server id is higher.
- */
- protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) {
- ...
- return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) && ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));
- }
zookeeper的leader算法类似于公民选举,每一个节点(选民),他们都有自己的推荐人(自己)。谁更适合成为leader有一个简单的规则,例如zxid(数据新)、sid/myid(服务编号大)。每个选民都告诉其他选民自己目前的推荐人是谁,当选民发现有比自己更适合的人时就转而推荐这个更适合的人。最后,过半数人意见一致时,就可以结束选举。当然,如果大多数人已经选举出了leader,那剩下的选民(无论是否参与投票)就只能接受已经选出的leader。
watch注意事项
1.Zookeeper客户端可以在znode上设置Watch。znode发生的变化会触发watch然后清除watch。当一个watch被触发,Zookeeper给客户端发送一个通知,当ZooKeeper客户端断开和服务器的连接,直到重新连接上这段时间你都收不到任何通知。如果你正在监视znode是否存在,那么你在断开连接期间收不到它创建和销毁的通知。
2.Zookeeper的客户端和服务会检查确保每个znode上的数据小于1M,因为Zookeeper为了提供高吞吐量,保存到内存里的数据量不宜过多
转载请注明来源:http://blog.csdn.net/odailidong/article/details/41855613
zookeeper源码分析之leader选举的更多相关文章
- 【Zookeeper】源码分析之Leader选举(二)
一.前言 前面学习了Leader选举的总体框架,接着来学习Zookeeper中默认的选举策略,FastLeaderElection. 二.FastLeaderElection源码分析 2.1 类的继承 ...
- 【Zookeeper】源码分析之Leader选举(一)
一.前言 分析完了Zookeeper中的网络机制后,接着来分析Zookeeper中一个更为核心的模块,Leader选举. 二.总结框架图 对于Leader选举,其总体框架图如下图所示 说明: 选举的父 ...
- 【Zookeeper】源码分析之Leader选举(二)之FastLeaderElection
一.前言 前面学习了Leader选举的总体框架,接着来学习Zookeeper中默认的选举策略,FastLeaderElection. 二.FastLeaderElection源码分析 2.1 类的继承 ...
- zookeeper源码分析二FASTLEADER选举算法
如何在zookeeper集群中选举出一个leader,zookeeper使用了三种算法,具体使用哪种算法,在配置文件中是可以配置的,对应的配置项是"electionAlg",其中1 ...
- zookeeper源码分析三LEADER与FOLLOWER同步数据流程
根据二)中的分析,如果一台zookeeper服务器成为集群中的leader,那么一定是当前所有服务器中保存数据最多的服务器,所以在这台服务器成为leader之后,首先要做的事情就是与集群中的其它服务器 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- Zookeeper 源码分析-启动
Zookeeper 源码分析-启动 博客分类: Zookeeper 本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
随机推荐
- 性能度量之Confusion Matrix
例子:一个Binary Classifier 假设我们要预测图片中的数字是否为数字5.如下面代码. X_train为训练集,每一个instance为一张28*28像素的图片,共784个features ...
- HDU 1512 Monkey King(左偏树)
Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does thi ...
- JavaScript中childNodes和children的区别
我在学习JavaScript对DOM操作的过程中,发现了使用childNodes属性,得不到我想要的结果,因此我就从JavaScript高级程序设计中了解了childNodes和children的区别 ...
- kmeans算法理解及代码实现
github:kmeans代码实现1.kmeans代码实现2(包含二分k-means) 本文算法均使用python3实现 1 聚类算法 对于"监督学习"(supervised ...
- TCP系列35—窗口管理&流控—9、紧急机制
一.概述 我们在最开始介绍TCP头结构的时候,里面有个URG的标志位,还有一个Urgent Pointer的16bits字段.当URG标志位有效的时候,Urgent Poinert用来指示紧急数据的相 ...
- C# HttpWebRequest post提交数据,提交对象
1.客户端方法 //属于客户端 //要向URL Post的方法 public void PostResponse() { HttpWebRequest req = (HttpWebRequest)Ht ...
- grid++json页面数据传入
最近遇到一个问题,就是要用Grid++做页面数据报表打印,但是翻了Grid++文档就是没有直接从页面上传数据的,都是要加载txt文档,填写txt文档的url.自己尝试直接页面上传JSON数据到Grid ...
- CentOS基础命令
为网卡配置静态IP地址建议通过交互式界面nmtui进行配置 firewalld和iptablesCentOS7使用firewald取代原来的iptables,但实际上底层还是iptables,在上层加 ...
- tcp中的发送窗口是啥意思?
初始的三次握手: 02:52:36.585412 IP 127.0.0.1.59764 > 127.0.0.1.8000: Flags [S], seq 3800457532, win 4369 ...
- Oracle基础 表分区
Oracle基础 表分区 一.表分区 (一)表分区的分类 1.范围分区(range) 2.散列分区(hash) 3.列表分区(list) 4.复合分区:范围-哈希(range-hash).范围-列表( ...