一、分布式JOB需求
1.多个服务节点只允许其中一个主节点运行JOB任务。
2.当主节点挂掉后能自动切换主节点,继续执行JOB任务
二、架构设计
node结构:
1./service-master
a./service-master/server0001:master
b./service-master/server0002:slave
c./service-master/server000n:slave
三、选举流程
1、服务启动
- 1.在tuling-maste下创建server子节点,值为slave
- 2.获取所有tuling-master 下所有子节点
- 3.判断是否存在master 节点
- 4.如果没有设置自己为master节点
2、子节点删除事件触发
- 1.获取所有tuling-master 下所有子节点
- 2.判断是否存在master 节点
- 3.如果没有设置最小值序号为master 节点
四、代码实现
public class MasterResolve {
private ZkClient zkClient;
private static final String rootPath = "/service-master";
private static final String servicePath = rootPath + "/service";
private String nodePath;
private volatile boolean master = false;
private static MasterResolve resolve;
private MasterResolve() {
String connectString = "192.168.209.4:2181";
zkClient = new ZkClient(connectString, 50*1000);
buildRoot();
createServerNode();
}
public static MasterResolve getInstance() {
if (resolve == null) {
resolve= new MasterResolve();
}
return resolve;
}
// 构建根节点
public void buildRoot() {
if (!zkClient.exists(rootPath)) {
zkClient.createPersistent(rootPath);
}
}
// 创建server节点
public void createServerNode() {
nodePath = zkClient.createEphemeralSequential(servicePath, "slave");
System.out.println("创建service节点:" + nodePath);
initMaster();
initListener();
}
private void initMaster() {
boolean existMaster = zkClient.getChildren(rootPath)
.stream()
.map(p -> rootPath + "/" + p)
.map(p -> zkClient.readData(p))
.anyMatch(d -> "master".equals(d));
if (!existMaster) {
doElection();
System.out.println("当前当选master");
}
}
private void initListener() {
zkClient.subscribeChildChanges(rootPath, (parentPath, currentChilds) -> {
doElection();// 执行选举
});
}
// 执行选举
public void doElection() {
Map<String, Object> childData = zkClient.getChildren(rootPath)
.stream()
.map(p -> rootPath + "/" + p)
.collect(Collectors.toMap(p -> p, p -> zkClient.readData(p)));
if (childData.containsValue("master")) {
return;
}
childData.keySet().stream().sorted().findFirst().ifPresent(p -> {
if (p.equals(nodePath)) { // 设置最小值序号为master 节点
zkClient.writeData(nodePath, "master");
master = true;
System.out.println("当前当选master" + nodePath);
}
});
}
public static boolean isMaster() {
return getInstance().master;
}
public static void main(String[] args) {
MasterResolve instance = MasterResolve.getInstance();
System.out.println("master"+ MasterResolve.isMaster());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这样JOB就可以在master执行啦,定时job运行的时候判断自己是否是master,如果是true就运行,否则就不运行!