zookeeper和java實現的統一配置管理和叢集節點管理簡單案例
阿新 • • 發佈:2018-12-03
1.首先談談對zookeeper的認識,以下簡稱zk
zk做為服務存在,是以三個或者三個以上存在的。服務節點啟動不分先後,他會自動選取出leader和follower。
服務奇數個更有利於容錯,資料一致性可以谷歌下paxos演算法。
2.其次是我們自己開發的應用程式app
app以節點樹存在與zk上。頂層是父節點,其次是app節點。(節點通過通過ZK api構建,節點上可以存放資料,改變資料)。
案例1(APP叢集上的統一配置管理)
package org.zookeeper; import java.io.File; import org.apache.log4j.PropertyConfigurator; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; public class AppServer { private static String groupNode = "sgroup"; private String subNode = "sub"; ZooKeeper zk; Stat stat = new Stat(); private void updateConfig() throws KeeperException, InterruptedException { //注意getdata 引數 boolean watch,這裡一定要是true,說明每次都要監控節點資料變化的 System.out.println(zk.hashCode()+": current config is:"+new String(zk.getData("/" + groupNode, true, null))); } public void connectZookeeper(String address) throws Exception { //zk叢集服務地址 zk = new ZooKeeper("10.15.107.105:2181,10.15.107.42:2181,10.15.107.43:2181", 30*1000, new Watcher() { public void process(WatchedEvent event) { if( event.getType().equals(EventType.NodeDataChanged) ){ System.out.println("config is changed"); try { updateConfig(); } catch (KeeperException | InterruptedException e) { e.printStackTrace(); } } } }); // 在"/sgroup"下建立子節點 // 子節點的型別設定為EPHEMERAL_SEQUENTIAL, 表明這是一個臨時節點, 且在子節點的名稱後面加上一串數字字尾 // 將server的地址資料關聯到新建立的子節點上 Stat s = zk.exists("/" + groupNode, false); if( s == null ){ zk.create("/" + groupNode, "".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); zk.setData("/" + groupNode, "origin config".getBytes(), -1); } String createdPath = zk.create("/" + groupNode + "/" + subNode,address.getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); zk.getData("/" + groupNode, true,null); System.out.println("create: " + createdPath); } /*** * 模擬3個app使用共同配置檔案。隨後讓一個執行緒去修改配置5次。3個app每次都會收到配置改變的通知。 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //初始化log4j File f = new File( "user.dir"+ File.separator + "log"); if( !f.exists() ){ f.mkdir(); new File("user.dir" + File.separator + "log"+ File.separator+"land.log"); } PropertyConfigurator.configureAndWatch(File.separator+ System.getProperty("user.dir") + File.separator + "conf"+ File.separator + "log4j.properties"); String[] hosts = new String[] { "10.15.107.105", "10.15.107.42","10.15.107.43" }; for (int i = 0; i < hosts.length; ++i) { final AppServer as = new AppServer(); as.connectZookeeper(hosts[i]); if( i == 2){ new Thread(){ public void run(){ try { for( int i=0;i<5;++i ){ System.out.println("config begin change"); as.zk.setData("/" + groupNode, (as.zk.hashCode()+" change id:"+Math.random()).getBytes(), -1); Thread.sleep(3 * 1000); } } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } Thread.sleep(1 * 1000); } Thread.sleep(Long.MAX_VALUE); } }
案例2(實現對APP叢集節點監控管理:APP線上和離線能即時通知到監控程式)
APP服務使用案例1的程式,監控程式程式碼如下:
package org.zookeeper; import java.io.File; import java.util.ArrayList; import java.util.List; import org.apache.log4j.PropertyConfigurator; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; public class AppClient { private String groupNode = "sgroup"; private ZooKeeper zk; private Stat stat = new Stat(); private volatile List<String> serverList; /** * 連線zookeeper */ public void connectZookeeper() throws Exception { zk = new ZooKeeper("10.15.107.105:2181,10.15.107.42:2181,10.15.107.43:2181", 30*1000, new Watcher() { public void process(WatchedEvent event) { // 如果發生了"/sgroup"節點下的子節點變化事件, 更新server列表, 並重新註冊監聽 if (event.getType() == EventType.NodeChildrenChanged && ("/" + groupNode).equals(event.getPath())) { try { updateServerList(); } catch (Exception e) { e.printStackTrace(); } } } }); updateServerList(); } /** * 更新server列表 */ private void updateServerList() throws Exception { List<String> newServerList = new ArrayList<String>(); // 獲取並監聽groupNode的子節點變化 // watch引數為true, 表示監聽子節點變化事件. // 每次都需要重新註冊監聽, 因為一次註冊, 只能監聽一次事件, 如果還想繼續保持監聽, 必須重新註冊 List<String> subList = zk.getChildren("/" + groupNode, true); for (String subNode : subList) { // 獲取每個子節點下關聯的server地址 byte[] data = zk.getData("/" + groupNode + "/" + subNode, false,stat); newServerList.add(new String(data, "utf-8")); } // 替換server列表 serverList = newServerList; System.out.println("current active server address: " + serverList); } public static void main(String[] args) throws Exception { //初始化log4j File f = new File( "user.dir"+ File.separator + "log"); if( !f.exists() ){ f.mkdir(); new File("user.dir" + File.separator + "log"+ File.separator+"land.log"); } PropertyConfigurator.configureAndWatch(File.separator+ System.getProperty("user.dir") + File.separator + "conf"+ File.separator + "log4j.properties"); AppClient ac = new AppClient(); ac.connectZookeeper(); Thread.sleep(Long.MAX_VALUE); } }