在分布式系统中,ZooKeeper可用于实现领导者选举(leader election)功能,确保集群中的多个节点能够协调地选举出一个领导者来负责协调整个集群的工作。
具体还是使用zookeeper的临时顺序节点。临时节点特点是当当前服务异常挂掉(与zookeeper的连接关闭)时创建的临时节点会自动消失。
1、首先每个参与选举节点都在zookeeper固定路径下创建临时顺序节点。假设在/leader路径下。
2、当节点创建完临时顺序节点后,查询/leader下所有子节点,找到自己创建的节点的顺序号,也就是自己的位置
3、如果自己是最小的节点,则该节点成为领导者;否则监听自己前一个节点的变化,当前一个节点删除时,再次判断自己是否是最小的节点,是则成为领导者否则继续监听新的前一节点的变化,重复上面的判断操作。
一旦成为了领导者,节点就可以开始执行领导者的职责,而其他节点则作为follower来跟随领导者执行任务。
整个选举的过程大家是不是感觉有点熟悉,没错就是和前面的分布式锁的原理大致是一致的。curator有对leader选举的具体实现类:LeaderSelector。
下面使用LeaderSelector搞个简单的例子。
先定义一个选举的逻辑方法:
static void execSelect() throws InterruptedException {
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
CountDownLatch latch = new CountDownLatch(1);
LeaderSelector selector = new LeaderSelector(client, "/leader", new LeaderSelectorListener() {
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
System.out.println("I'm the leader "+Thread.currentThread().getName());
//do sth
Thread.sleep(5000);
latch.countDown();
}
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
}
});
selector.start();
latch.await();
selector.close();
client.close();
}
这里使用LeaderSelector指定在"/leader"目录下创建临时节点进行选举,注册了一个LeaderSelectorListener监听器。将当前节点选举为leader时候,会回调takeLeadership()方法。这里成为leader之后休眠5s后然后关闭当前连接,也就是leader挂掉,触发下一次选举。
LeaderSelector内部选举的过程就是用的InterProcessMutex来实现的。拿到锁就是当前节点选中leader。
下面起几个线程模拟多节点进行选举:
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executor.execute(()->{
try {
execSelect();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
最后会看到输出:
I’m the leader Curator-LeaderSelector-0
I’m the leader Curator-LeaderSelector-2
I’m the leader Curator-LeaderSelector-4
I’m the leader Curator-LeaderSelector-1
I’m the leader Curator-LeaderSelector-3