前言:
隨着業務的擴大,用戶的增多,訪問量的增加,單機模式已經不能支撐,從而出現了從單機模式->垂直應用模式->集群模式,集群模式誕生了,伴隨着一堆問題也油然而生,Master怎么選舉,機器故障及時移除集群,添加機器了如何及時的感應到,Zookeeper不僅能維護當前的集群服務狀態,還能及時的選出master,它們的實現方式都是在Zookeeper上面注冊一個EPHEMERAL目錄節點,在創建目錄的父目錄上面調用getChildren(String path,boolean watch)設置watch為true,注冊watcher事件,由於是臨時節點,當服務器出現問題造成session丟失,相對應的目錄節點隨之刪除,Children節點發生變化,就會調用前面注冊的watcher,使集群內的每個節點都得到新的集群信息。反之,新增節點也是這樣。
注:master選舉,不同之處是注冊一個EPHEMERAL_SEQUENTIAL 目錄節點,我們可以選擇最小編號為master,實現了動態選擇master,避免master出現單點故障
一、架構體系

二:模擬代碼
監控類:
package com.zk.config.manager;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
public class AppRegister {
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
private ZooKeeper zooKeeper;
private Object lock = new Object();
private String ip;
private String rootConfig;
public AppRegister(String ip, String root) {
this.ip = ip;
this.rootConfig = root;
this.zooKeeper = connectZookeeper();
}
public ZooKeeper connectZookeeper() {
synchronized (lock) {
if (zooKeeper == null) {
try {
zooKeeper = new ZooKeeper("192.168.1.1:2181", 5000, new Watcher() {
public void process(WatchedEvent event) {
if (KeeperState.SyncConnected == event.getState()) {
if (EventType.None == event.getType() && null == event.getPath()) {
try {
connectedSemaphore.countDown();
zooKeeper.getChildren(rootConfig, true);
zooKeeper.create(rootConfig + "/" + ip, ip.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (EventType.NodeChildrenChanged == event.getType()) {
try {
List<String> childrenList = zooKeeper.getChildren(rootConfig, true);
System.out.println("節點變化了:" + childrenList);
Collections.sort(childrenList);
System.out.println("我是master了:" + childrenList.get(0));
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
);
connectedSemaphore.await();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return zooKeeper;
}
}
模擬程序:
package com.zk.config.manager;
public class AppMonitor {
private final static String rootConfig = "/AppCluster";
public static void main(String[] args) throws InterruptedException {
/**
* 新增機器,選舉master
*/
addHost();
Thread.sleep(Integer.MAX_VALUE);
}
private static void addHost()
{
new Thread(new Runnable() {
public void run() {
new AppRegister("192.168.1.1", rootConfig);
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
new AppRegister("192.168.1.2", rootConfig);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
運行結果:
節點變化了:[192.168.1.10000000029]
我是master了:192.168.1.10000000029
節點變化了:[192.168.1.20000000030, 192.168.1.10000000029]
我是master了:192.168.1.10000000029
節點變化了:[192.168.1.20000000030, 192.168.1.10000000029]
我是master了:192.168.1.10000000029
