java实现zookeeper的领袖选举

来源:互联网 发布:图像分析软件 编辑:程序博客网 时间:2024/05/30 05:40

Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。而且也是诸如hbase,hadoop,dubbo等诸多分布式项目的基础技术,本篇主要介绍zookeeper中最常用的一个场景,领袖选举。

领袖选举,由于分布式环境往往是由多台server组成的集群,而集群环境下就需要一个"主管"来管理集群上的每台机器的服务状态,但是如果一个"主管"有一天宕机了,但是为了已有的机器能正常运行,如何能让集群自动选取一台机器成为新的"总管"呢?答案就是本篇要讲的领袖选举。

本篇假设读者已经基本了解zookeeper的基本安装及配置和使用方法,如果还不了解可以看这篇文章:http://www.cnblogs.com/wuxl360/p/5817405.html

领袖选举的基本原理是创建一个永久节点/leader,然后每台机器在启动的时候,创建一个/leader 下的临时顺序节点,如/leader/chiren-000000001,/leader/chiren-000000002...    由于临时节点会随着zookeeper客户端的过期而失效,所以每个机器启动的时候,打开一个zookeeper客户端并创建一个临时节点,当服务器宕机的时候,客户端会随着服务器宕机而失效,而临时节点也会因此失效,所以只要通过getChildren方法监听/leader节点,然后/leader下临时节点有变化,由于顺序节点是每次创建自动递增的,所以只要取临时节点中的最小值作为"领袖"即可。

以下是代码实现。

public class LeaderElectionTest{   public static void main(String[] args) throws IOException, KeeperException, InterruptedException {      MyWatch myWatch = new MyWatch();      ZooKeeper zk = new ZooKeeper("localhost:" + 2181,            1000,myWatch);      myWatch.setZooKeeper(zk);      //先创建一个节点存储创建过的机器节点      try {         zk.create("/leader", ("主机").getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);      }catch (KeeperException.NodeExistsException e){         System.out.println("主机节点已创建");      }      //模拟新加入一台机器      Random r = new Random();      String num = r.nextInt(100000)+"";      String sequentialPath = zk.create("/leader/children",("运行server的ip:"+num).getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);      System.out.println("同步创建临时顺序节点成功:" + sequentialPath);      //注册监听事件      zk.getChildren("/leader",true);      //此处模拟机器持续运行着      while(true){      }   }}

首先程序会创建一个zookeeper客户端,然后尝试去创建一个/leader永久节点,如果别的服务器已经创建,就不必创建。然后用了一个随机数模拟本台机器的ip,并在/leader/children下创建一个临时顺序节点,然后zk客户端调用getChildren方法,注册监听事件(对zookeeper监听机制不是很了解的可以看这篇文章:https://www.cnblogs.com/programlearning/archive/2017/05/10/6834963.html)。然后用一个while循环防止程序终止。

public class MyWatch implements Watcher{   private ZooKeeper zk;   private List<String> oldSlaveList;   public void setZooKeeper(ZooKeeper zk){      this.zk = zk;   }   public void process(WatchedEvent event) {      if (Watcher.Event.EventType.None == event.getType() && null == event.getPath()) {         System.out.println("Zookeeper session established");         try {            List<String> stringList =  zk.getChildren("/leader",true);            oldSlaveList = stringList;            if(stringList.size()==0){               System.out.println("您现在是唯一一台机器,您就是领袖");            }            else{               System.out.println("您的机器被创建,当前领袖为:"+findMaster(stringList));            }         } catch (Exception e) {            e.printStackTrace();         }      }      if (Event.EventType.NodeChildrenChanged == event.getType()) {         try {            List<String> stringList =  zk.getChildren("/leader",true);            //如果当前机器列表大于旧的机器列表说明增加了            if(stringList.size()>oldSlaveList.size()){               System.out.println("一台机器被创建,当前领袖为:"+findMaster(stringList));               oldSlaveList = stringList;            }            else{               System.out.println("一台机器被删除,当前领袖为:"+findMaster(stringList));               oldSlaveList = stringList;            }         } catch (Exception e) {            e.printStackTrace();         }      }   }   private String findMaster(List<String> stringList){      Integer min = Integer.MAX_VALUE;      Integer index = 0;      for(int i=0;i<stringList.size();i++){         Integer num = Integer.parseInt(stringList.get(i).substring(8));         if(num<=min){            min = num;            index = i;         }      }      return stringList.get(index);   }}

然后MyWatcher中实现了Watcher接口,实现的process方法中,主要监听了自己zookeeper客户端创建的事件,和子节点改变的事件(main方法中已经注册了/leader节点的监听事件,不注册无法接收到消息),当自己zookeeper客户端创建的时候如果子节点列表为空说明当前只有一台机器,自己就是领袖。在子节点改变事件中,判断了节点是增加还是减少,并调用findMaster方法,找到当前节点中的最小值,也就是领袖。然后作为"领袖"的机器就可以由此管理其他机器的状态了。

运行结果:









(完)



参考文章:http://www.cnblogs.com/wuxl360/p/5817405.html
           
https://www.cnblogs.com/programlearning/archive/2017/05/10/6834963.html