5.2.1
org.apache.curator
curator-framework
${curator.version}
org.apache.curator
curator-recipes
${curator.version}
几个关键代码:
package com.xxx.common.zk;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import lombok.Setter;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Date 2023/8/25 14:10
*/
@Setter
public class ZkClient {
private final Logger logger = LoggerFactory.getLogger(ZkClient.class);
private CuratorFramework client;
private String zookeeperServer;
private int sessionTimeoutMs;
private int connectionTimeoutMs;
private int baseSleepTimeMs = 1000;
private int maxRetries = 3;
LeaderSelector selector = null;
public ZkClient(String zookeeperServer, int connectionTimeoutMs, int sessionTimeoutMs) {
this.zookeeperServer = zookeeperServer;
this.sessionTimeoutMs = sessionTimeoutMs;
this.connectionTimeoutMs = connectionTimeoutMs;
init();
}
public void init() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries);
client = CuratorFrameworkFactory.builder()
.connectString(zookeeperServer)
.retryPolicy(retryPolicy)
.sessionTimeoutMs(sessionTimeoutMs)
.connectionTimeoutMs(connectionTimeoutMs)
.build();
client.start();
try {
assert client.getState().equals(CuratorFrameworkState.STARTED);
client.blockUntilConnected();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public CuratorFramework getClient() {
return client;
}
public List getChildren(String path) {
List childrenList = new ArrayList<>();
try {
childrenList = client.getChildren().forPath(path);
} catch (Exception e) {
logger.error("##获取子节点出错##", e);
e.printStackTrace();
}
return childrenList;
}
public int getChildrenCount(String path) {
return getChildren(path).size();
}
public List getInstances() {
return getChildren("/services");
}
public int getInstanceCount() {
return getInstances().size();
}
/**
* 监听某个路径,几个服务竞争用此方法
* @param path
*/
public void listenerPath(String path, String id, LeaderSelectorListener listener){
try {
selector = new LeaderSelector(client, path, listener);
selector.setId(id);
selector.start();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 判定是不是leader
* @return
*/
public boolean isLeader(){
return selector.hasLeadership();
}
/**
* 获取leader里面存的data,获取leader状态的服务器用此方法
* @return
*/
public String getLeader(String path) {
List childrenList;
try {
childrenList = client.getChildren().forPath(path);
System.out.println("childrenList " + childrenList.size());
childrenList.sort(new ChildrenComparator());
String leaderPath = path + "/" + childrenList.get(0);
return new String(client.getData().forPath(leaderPath));
} catch (Exception e) {
logger.error("##获取子节点数据出错##", e);
e.printStackTrace();
}
return null;
}
public void stop() {
if(selector != null){
CloseableUtils.closeQuietly(selector);
}
if(client != null){
CloseableUtils.closeQuietly(client);
}
}
static class ChildrenComparator implements Comparator {
@Override
public int compare(String o1, String o2) {
int oo1 = getSequential(o1);
int oo2 = getSequential(o2);
return Integer.compare(oo1, oo2);
}
}
private static int getSequential(String s){
return Integer.parseInt(s.substring(s.lastIndexOf("-") + 1));
}
/**
* 创建临时节点,临时节点名是备份队列的名字,便于master做故障恢复
* @param path
*/
public void createPath(String path) {
try {
String s = client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);
logger.info("######创建临时节点["+s+"]成功######");
}catch (Exception e){
logger.error("######创建临时节点["+path+"]失败######", e);
}
}
}
package com.xxx.etl.master.common;
import java.lang.management.ManagementFactory;
import java.util.concurrent.CountDownLatch;
import lombok.Getter;
import lombok.Setter;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListener;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.utils.CloseableUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @Date 2023/8/21 20:25
*/
@Setter
@Getter
public class LeaderSelectorListenerImpl implements LeaderSelectorListener {
private static Logger log = LogManager.getLogger(LeaderSelectorListenerImpl.class);
private CountDownLatch countDownLatch;
public LeaderSelectorListenerImpl(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
// 被选举为Leader时调用
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
log.info("##获取到了leader权##");
countDownLatch.countDown();
while(true); //阻塞,一直持有leader,不加的话会释放
}
// 当连接状态发生变化时调用
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
if(!newState.equals(ConnectionState.CONNECTED)){
//状态改变,直接杀掉
log.info("##连接新状态: {}##", newState.name());
CloseableUtils.closeQuietly(client);
try {
//杀掉程序,写个shell脚本再拉起来
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
Runtime.getRuntime().exec("kill -9 " + pid);
log.warn("## 即将关闭Master程序(当前节点) ##");
System.exit(0);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
上面是两个核心代码:
下面是使用方式:
/**
* zk的启动,监听等
*/
public static boolean zkStart(){
//连接信息
ZkClient zkClient = new ZkClient(PropertiesService.getProperty("ETL.LOG.ZOOKEEPER"),
Integer.parseInt(PropertiesService.getProperty("zk.connectionTimeoutMs")),
Integer.parseInt(PropertiesService.getProperty("zk.sessionTimeoutMs")));
//添加监听器
CountDownLatch isLeader = new CountDownLatch(1);
LeaderSelectorListener listener = new LeaderSelectorListenerImpl(isLeader);
log.info("##等待获取leader##");
try {
//主机ip作为存储的data
String hostAddress = InetAddress.getLocalHost().getHostAddress() + ":" + System.getProperty("rmi.port");
zkClient.listenerPath(PATH, hostAddress, listener);
isLeader.await();//上面获取执行权后才执行下面的步骤
return zkClient.isLeader();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
使用的时候 if(zkStart()) {
}
有问题留言交流,互相学习。