全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

理解zookeeper选举机制

zookeeper集群

配置多个实例共同构成一个集群对外提供服务以达到水平扩展的目的,每个服务器上的数据是相同的,每一个服务器均可以对外提供读和写的服务,这点和redis是相同的,即对客户端来讲每个服务器都是平等的。

这篇主要分析leader的选择机制,zookeeper提供了三种方式:

  • LeaderElection
  • AuthFastLeaderElection
  • FastLeaderElection

默认的算法是FastLeaderElection,所以这篇主要分析它的选举机制。

选择机制中的概念

服务器ID

比如有三台服务器,编号分别是1,2,3。

编号越大在选择算法中的权重越大。

数据ID

服务器中存放的最大数据ID.

值越大说明数据越新,在选举算法中数据越新权重越大。

逻辑时钟

或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。

选举状态

  • LOOKING,竞选状态。
  • FOLLOWING,随从状态,同步leader状态,参与投票。
  • OBSERVING,观察状态,同步leader状态,不参与投票。
  • LEADING,领导者状态。

选举消息内容

在投票完成后,需要将投票信息发送给集群中的所有服务器,它包含如下内容。

  • 服务器ID
  • 数据ID
  • 逻辑时钟
  • 选举状态

选举流程图

因为每个服务器都是独立的,在启动时均从初始状态开始参与选举,下面是简易流程图。

选举状态图

描述Leader选择过程中的状态变化,这是假设全部实例中均没有数据,假设服务器启动顺序分别为:A,B,C。

源码分析

QuorumPeer

主要看这个类,只有LOOKING状态才会去执行选举算法。每个服务器在启动时都会选择自己做为领导,然后将投票信息发送出去,循环一直到选举出领导为止。

public void run() {
  //.......
  try {
   while (running) {
    switch (getPeerState()) {
    case LOOKING:
     if (Boolean.getBoolean("readonlymode.enabled")) {
      //...
      try {
       //投票给自己...
       setCurrentVote(makeLEStrategy().lookForLeader());
      } catch (Exception e) {
       //...
      } finally {
       //...
      }
     } else {
      try {
       //...
       setCurrentVote(makeLEStrategy().lookForLeader());
      } catch (Exception e) {
       //...
      }      
     }
     break;
    case OBSERVING:
     //...
     break;
    case FOLLOWING:
     //...
     break;
    case LEADING:
     //...
     break;
    }
   }
  } finally {
   //...
  }
 }

FastLeaderElection

它是zookeeper默认提供的选举算法,核心方法如下:具体的可以与本文上面的流程图对照。

public Vote lookForLeader() throws InterruptedException {
  //...
  try {
   HashMap<Long, Vote> recvset = new HashMap<Long, Vote>();

   HashMap<Long, Vote> outofelection = new HashMap<Long, Vote>();
   int notTimeout = finalizeWait;
   synchronized(this){
    //给自己投票
    logicalclock.incrementAndGet();
    updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());
   }
   //将投票信息发送给集群中的每个服务器
   sendNotifications();
   //循环,如果是竞选状态一直到选举出结果
   while ((self.getPeerState() == ServerState.LOOKING) &&
     (!stop)){
    Notification n = recvqueue.poll(notTimeout,
      TimeUnit.MILLISECONDS);
    //没有收到投票信息
    if(n == null){
     if(manager.haveDelivered()){
      sendNotifications();
     } else {
      manager.connectAll();
     }
     //...
    } 
    //收到投票信息
    else if (self.getCurrentAndNextConfigVoters().contains(n.sid)) {
     switch (n.state) {
     case LOOKING:
      // 判断投票是否过时,如果过时就清除之前已经接收到的信息      
      if (n.electionEpoch > logicalclock.get()) {
       logicalclock.set(n.electionEpoch);
       recvset.clear();
       //更新投票信息
       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.get()) {
       //忽略
       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));
      //判断是否投票结束
      if (termPredicate(recvset,
        new Vote(proposedLeader, proposedZxid,
logicalclock.get(), proposedEpoch))) {
       // Verify if there is any change in the proposed leader
       while((n = recvqueue.poll(finalizeWait,
         TimeUnit.MILLISECONDS)) != null){
        if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
          proposedLeader, proposedZxid, proposedEpoch)){
         recvqueue.put(n);
         break;
        }
       }
       if (n == null) {
        self.setPeerState((proposedLeader == self.getId()) ?
 ServerState.LEADING: learningState());
        Vote endVote = new Vote(proposedLeader,
proposedZxid, proposedEpoch);
        leaveInstance(endVote);
        return endVote;
       }
      }
      break;
     case OBSERVING:
      //忽略
      break;
     case FOLLOWING:
     case LEADING:
      //如果是同一轮投票
      if(n.electionEpoch == logicalclock.get()){
       recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));
       //判断是否投票结束
       if(termPredicate(recvset, new Vote(n.leader,
           n.zxid, n.electionEpoch, n.peerEpoch, n.state))
           && checkLeader(outofelection, n.leader, n.electionEpoch)) {
        self.setPeerState((n.leader == self.getId()) ?
ServerState.LEADING: learningState());
        Vote endVote = new Vote(n.leader, n.zxid, n.peerEpoch);
        leaveInstance(endVote);
        return endVote;
       }
      }
      //记录投票已经完成
      outofelection.put(n.sid, new Vote(n.leader, 
        IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state));
      if (termPredicate(outofelection, new Vote(n.leader,
        IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state))
        && checkLeader(outofelection, n.leader, IGNOREVALUE)) {
       synchronized(this){
        logicalclock.set(n.electionEpoch);
        self.setPeerState((n.leader == self.getId()) ?
ServerState.LEADING: learningState());
       }
       Vote endVote = new Vote(n.leader, n.zxid, n.peerEpoch);
       leaveInstance(endVote);
       return endVote;
      }
      break;
     default:
      //忽略
      break;
     }
    } else {
     LOG.warn("Ignoring notification from non-cluster member " + n.sid);
    }
   }
   return null;
  } finally {
   //...
  }
 }

判断是否已经胜出

默认是采用投票数大于半数则胜出的逻辑。

选举流程简述

目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:

  • 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking。
  • 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
  • 服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
  • 服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
  • 服务器5启动,后面的逻辑同服务器4成为小弟。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# zookeeper  # zookeeper的Leader选举机制源码解析  # ZooKeeper集群操作及集群Master选举搭建启动  # Zookeeper的选举机制详解  # 给自己  # 越大  # 都是  # 判断是否  # 投票数  # 这篇  # 启动时  # 过程中  # 这是  # 发送给  # 就会  # 由于服务器  # 还没有  # 多个  # 如有  # 它是  # 三种  # 均可  # 分别为  # 时就 


相关文章: ui设计制作网站有哪些,手机UI设计网址吗?  如何通过虚拟主机空间快速建站?  宁波免费建站如何选择可靠模板与平台?  高端网站建设与定制开发一站式解决方案 中企动力  昆明网站制作哪家好,昆明公租房申请网上登录入口?  攀枝花网站建设,攀枝花营业执照网上怎么年审?  制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?  用v-html解决Vue.js渲染中html标签不被解析的问题  广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?  建站之星安装路径如何正确选择及配置?  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  如何快速查询网站的真实建站时间?  如何用IIS7快速搭建并优化网站站点?  网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?  建站之星如何快速生成多端适配网站?  购物网站制作公司有哪些,哪个购物网站比较好?  ,制作一个手机app网站要多少钱?  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  如何在服务器上三步完成建站并提升流量?  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  如何在万网自助建站中设置域名及备案?  如何快速选择适合个人网站的云服务器配置?  如何在IIS中新建站点并解决端口绑定冲突?  c# 在高并发下使用反射发射(Reflection.Emit)的性能  linux top下的 minerd 木马清除方法  制作旅游网站html,怎样注册旅游网站?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  深圳网站制作案例,网页的相关名词有哪些?  C++如何将C风格字符串(char*)转换为std::string?(代码示例)  高端智能建站公司优选:品牌定制与SEO优化一站式服务  名字制作网站免费,所有小说网站的名字?  导航网站建站方案与优化指南:一站式高效搭建技巧解析  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  网站网页制作电话怎么打,怎样安装和使用钉钉软件免费打电话?  如何在Windows服务器上快速搭建网站?  建站之星安全性能如何?防护体系能否抵御黑客入侵?  贸易公司网站制作流程,出口贸易网站设计怎么做?  公司网站的制作公司,企业网站制作基本流程有哪些?  建站之星与建站宝盒如何选择最佳方案?  云南网站制作公司有哪些,云南最好的招聘网站是哪个?  网站制作的步骤包括,正确网址格式怎么写?  魔毅自助建站系统:模板定制与SEO优化一键生成指南  招商网站制作流程,网站招商广告语?  小型网站建站如何选择虚拟主机?  岳西云建站教程与模板下载_一站式快速建站系统操作指南  定制建站流程步骤详解:一站式方案设计与开发指南  赚钱网站制作软件,建一个网站怎样才能赚钱?是如何盈利的?  PHP正则匹配日期和时间(时间戳转换)的实例代码  如何确认建站备案号应放置的具体位置?  如何用免费手机建站系统零基础打造专业网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。