1. 程式人生 > >zookeeper主備切換學習

zookeeper主備切換學習

sem ant gen pri print 建立 mode reat 調用

今天了解了下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 上的節點的值 變成了另外一個,

zookeeper主備切換學習