1. 程式人生 > >zookeeper和java實現的統一配置管理和叢集節點管理簡單案例

zookeeper和java實現的統一配置管理和叢集節點管理簡單案例

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);
}
}