Master选举也是分布式系统中常见的场景,在分布式架构中,为了保证服务的可用性,通常会采用集群模式,也就是当其中的一个机器宕机后,其他节点会接替有故障的机器继续工作。在这种场景中需要选举一个节点为Master节点,当Master节点故障后从其他节点中选取一个节点作为Master节点继续工作。ZooKeeper有两种方式可以帮助实现Master的选举:
第一种类似于分布式锁的场景,由Master创建一个临时节点,其他机器监听该节点,一旦Master宕机,该临时节点被删除,其他服务机器监听到节点被删除,则创建临时节点,根据ZooKeeper节点的唯一性,创建临时节点成功的机器将选举为新的Master。
第二种使用临时有序节点的特性来实现。所有参与选举的客户端在ZooKeeper服务的/Master节点下创建一个临时有序节点,编号最小的表示Master,后一个节点监听前一个节点的删除事件,用于重新触发选举,如下图,一旦最小的节点被删除,client03将会被选举为Master。
用ZooKeeper自己实现选举还是比较复杂的,索性有前人造的轮子,同样Curator也实现了选举的功能。Curator提供了两个类用于Master分别为LeaderLatch和LeaderSelector,其中LeaderSelector比LeaderLatch多了重复选举的功能。下面将会使用代码进行展示。
LeaderLatch 提供了监听器LeaderLatchListener用于监听Master的选举,代码如下所示,我们可以使用一份代码创建两个类模拟两个进程Master选举:
/创建Leader实例,构造参数为Zookeeper客户端与,选举Path
LeaderLatch leaderLatch = new LeaderLatch(ClientUtil.getFramework(), "/leader1");
//添加选举监听器,选举成Master则调用isLeader方法
leaderLatch.addListener(new LeaderLatchListener() {@Overridepublic void isLeader() {System.out.println("I am Leader");}@Overridepublic void notLeader() {System.out.println("I am Not Leader");}
});
//调用start()开始选举
leaderLatch.start();
//保证选举进程不结束
System.in.read();
上面的代码中,我们同时启用多个main进程运行,最终只会有一个线程被选举为Master进程,如果杀掉其中一个main进程,则会继续选举,选举出第二个Master,即临时有序节点中序列号最小的客户端为Master节点。
除了LeaderLatch类外,LeaderSelector也可以用于选举与LeaderLatch方法不同的是,LeaderSelector的监听回调执行返回之后会释放Leader权,由其他进程继续选举。除此之外还可以调用autoRequeue()方法重复参加选举。代码如下所示:
public class LeaderSelectorDemo1 {//用于阻止回调方法返回private static CountDownLatch latch = new CountDownLatch(1);public static void main(String[] args) throws Exception {//创建LeaderSelector实例,传入ZooKeeper客户端,选举path 和Selector监听器LeaderSelector leaderSelector = new LeaderSelector(ClientUtil.getFramework(), "/leader1", new LeaderSelectorListener() {@Overridepublic void takeLeadership(CuratorFramework curatorFramework) throws Exception {//与LatchLeader不同的是,该方法返回,即该方法内逻辑处理完,就会释放Leader权,LatchLeader//需要调用close()主动释放System.out.println("I am a leader 1");//如果没有该调用,会失去Leader权latch.await();}@Overridepublic void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {}});//调用该方法可以重复参与选举leaderSelector.autoRequeue();//调用start()参与选举leaderSelector.start();//保证选举进程不结束System.in.read();}
}
Curator除了提供了分布式锁和Master选举功能的封装,还提供了分布式队列DistributedIdQueue,群组管理:GroupMember;DistributedBarrier、以及分布式原子类的使用。感兴趣的可以查看Curator的API的使用,这些内容不作介绍。