今天了解了下Zookeeper的主備方案
大致就是兩個應用運行后同時搶一個臨時節點,zookeeper可以保證只會有一個注冊成功這個節點,
然后都對這個節點進行watch,監聽事件NodeDeleted,如果NodeDeleted,然后另一台就可以直接注冊臨時節點成功。
這樣可以保證主備自動切換。看起來還可以...沒有在產線上用過...所以不知道具體效果是什么樣的。
實現代碼如下:非常easy。。。。
//抄的,
public class AbstractZooKeeper implements Watcher {
private static final int Session_TIME =2000;
protected ZooKeeper zookeeper ;
/*一個同步輔助類,在完成一組正在其他線程中執行的操作之前,
它允許一個或多個線程一直等待。
用給定的計數 初始化 CountDownLatch。
由於調用了 countDown() 方法,
所以在當前計數到達零之前,await 方法會一直受阻塞。
之后,會釋放所有等待的線程,await 的所有后續調用都將立即返回。
這種現象只出現一次——計數無法被重置
*/
protected CountDownLatch countDownLatch = new CountDownLatch(1);
public void connect(String hosts) throws IOException,InterruptedException{
zookeeper= new ZooKeeper(hosts,Session_TIME,this);
countDownLatch.await();
}
//監聽
public void process(WatchedEvent event) {
/* 一旦客戶端和服務器的某一個節點建立連接
* (注意,雖然集群有多個節點,
* 但是客戶端一次連接到一個節點就行了),
* 並完成一次version、zxid的同步,
* 這時的客戶端和服務器的連接狀態就是SyncConnected*/
if(event.getState() == KeeperState.SyncConnected){
countDownLatch.countDown();
System.out.println(countDownLatch.getCount());
}
}
public void close() throws InterruptedException{
zookeeper.close();
}
}
///zookeeper的一些操作。和監聽zookeeper臨時節點刪除事件。
public class ZookeeperService extends AbstractZooKeeper {
private static final String host = "helloword1";
//private static final String host = "helloword2";
private static final String rootNode="/mynode";
public void Create() throws KeeperException, InterruptedException, UnsupportedEncodingException {
//EPHEMERAL :臨時節點
this.zookeeper.create(rootNode, host.getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
}
//判斷存不存在時開始監聽
public Boolean Exist() throws KeeperException, InterruptedException {
return (this.zookeeper.exists(rootNode, true) != null);
}
//監聽事件
@Override
public void process(WatchedEvent event){
if(event.getType() == EventType.NodeDeleted){
try {
this.Create();
System.out.println(host);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(host);
}
else{
//由於第一次是阻塞的,
//如果連接成功需要調用父類的將countDownLatch阻塞去掉
super.process(event);
}
}
public Boolean getChild(String path) throws KeeperException, InstantiationException {
Boolean res = false;
try {
List<String> list = this.zookeeper.getChildren(path, false);
if (list.isEmpty()) {
System.out.println(path + "沒有節點");
} else {
res = true;
System.out.println("節點列表");
for (String child : list) {
System.out.println(child);
}
}
} catch (Exception e) {
// e.printStackTrace();
}
return res;
}
public byte[] getData(String path) throws KeeperException, InterruptedException {
return this.zookeeper.getData(path, false, null);
}
public static void main(String[] args) {
try {
ZookeeperService zookeeperService = new ZookeeperService();
zookeeperService.connect("localhost");
String zktest = "Zookeeper的JAVA API 測試";
zookeeperService.Create();
zookeeperService.getChild("/");
// zookeeperService.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//啟動方法,
public static void main(String[] args) {
SetZookeeperInfo();
SpringApplication.run(Application.class, args);
}
public static void SetZookeeperInfo()
{
ZookeeperService zookeeperService = new ZookeeperService();
try {
zookeeperService.connect("localhost");
if(!zookeeperService.Exist())
{
zookeeperService.Create();
}
zookeeperService.getChild("/");
} catch (Exception e) {
e.printStackTrace();
}
}
兩個應用代碼完全一樣,但只有節點對應的值不一樣,當一台機器掛機后,可查看zookeeper 上的節點的值 變成了另外一個,
