集群管理-leader选举/选主
所谓集群管理无在乎两点:是否有机器退出和加入、选举 master:
第一点,所有机器约定在父目录下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper 的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道了;新机器加入也是类似,所有机器收到通知:新兄弟目录加入;
第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为 master 就好。
在分布式系统中集群节点,leader election是很重要的一个功能,这个选举过程是这样子的:指派一个进程作为组织者,将任务分发给各节点。在任务开始前,哪个节点都不知道谁是leader。当选举算法开始执行后,每个节点最终会得到一个唯一的节点作为任务leader。
除此之外,选举还经常会发生在leader意外宕机的情况下,新的leader要被选举出来,如下图所示,这个就是所谓的leader选举,而zookeeper作为leader选举的功能,在很多中间件中都有使用,比如kafka基于zookeeper实现leader选举
除了作为集群节点的leader选举之外,leader选举还可以用在其他的场景。
比如在分布式调度任务系统中,从可靠性角度出发,集群也是必不可少的。但往往,为了保证任务不会重复分配,分配任务的节点只能有一个,这种情况就需要从集群中选出一个Leader(老大)去执行任务。
Curator实现leader选举
Curator基于Zookeeper封装的Leader选举工具类LeaderLatch与LeaderSelector,
两种选举LeaderSelector和Leader Latch最大的差别在于,leader可以释放领导权以后,还可以继续参与竞争。
public class SelectorClient2 extends LeaderSelectorListenerAdapter implements
Closeable {
private final String name;
private final LeaderSelector leaderSelector;
public SelectorClient2(CuratorFramework client, String path, String name) {
this.name = name;
// 利用一个给定的路径创建一个leader selector
// 执行leader选举的所有参与者对应的路径必须一样
// 本例中SelectorClient也是一个LeaderSelectorListener,但这不是必须的。
leaderSelector = new LeaderSelector(client, path, this);
// 在大多数情况下,我们会希望一个selector放弃leader后还要重新参与leader选举
leaderSelector.autoRequeue();
}
public void start(){
leaderSelector.start();
}
@Override
public void close() throws IOException {
leaderSelector.close();
}
@Override
public void takeLeadership(CuratorFramework curatorFramework) throws
Exception {
System.out.println(name + " 现在是leader了,持续成为leader ");
//选举为master,
System.in.read();//阻塞,让当前获得leader权限的节点一直持有,直到该进程关闭
}
private static String CONNECTION_STR="192.168.221.112:2181";
public static void main(String[] args) throws IOException {
CuratorFramework curatorFramework= CuratorFrameworkFactory.builder().
connectString(CONNECTION_STR).sessionTimeoutMs(5000).
retryPolicy(new ExponentialBackoffRetry(1000,3)).build();
curatorFramework.start();
SelectorClient2 sc=new
SelectorClient2(curatorFramework,"/leader","ClientB");
sc.start();
System.in.read();
}
}