前言: 隨著業務的擴大,用戶的增多,訪問量的增加,單機模式已經不能支撐,從而出現了從單機模式->垂直應用模式->集群模式,集群模式誕生了,伴隨著一堆問題也油然而生,Master怎麼選舉,機器故障及時移除集群,添加機器瞭如何及時的感應到,Zookeeper不僅能維護當前的集群服務狀態,還能及時的選出m ...
前言:
隨著業務的擴大,用戶的增多,訪問量的增加,單機模式已經不能支撐,從而出現了從單機模式->垂直應用模式->集群模式,集群模式誕生了,伴隨著一堆問題也油然而生,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