1,master選舉使用場景及結構
現在很多時候我們的服務需要7*24小時工作,假如一台機器掛了,我們希望能有其它機器頂替它繼續工作。此類問題現在多采用master-salve模式,也就是常說的主從模式,正常情況下主機提供服務,備機負責監聽主機狀態,當主機異常時,可以自動切換到備機繼續提供服務(這里有點兒類似於數據庫主庫跟備庫,備機正常情況下只監聽,不工作),這個切換過程中選出下一個主機的過程就是master選舉。
對於以上提到的場景,傳統的解決方式是采用一個備用節點,這個備用節點定期給當前主節點發送ping包,主節點收到ping包后會向備用節點發送應答ack,當備用節點收到應答,就認為主節點還活着,讓它繼續提供服務,否則就認為主節點掛掉了,自己將開始行使主節點職責。如圖1所示:
2,master 選擇策略和zookeeper 分布式鎖的思路大致一樣
package com.aiyuesheng.controller; import java.util.concurrent.CountDownLatch; import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient; import org.I0Itec.zkclient.exception.ZkException; import org.I0Itec.zkclient.exception.ZkInterruptedException; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class MyApplicationRunner implements ApplicationRunner { private CountDownLatch countDownLatch = null; String PATH = "/master"; @Value("${server.port}") private String serverPort; ZkClient zkClient = new ZkClient("127.0.0.1:2181"); @Override public void run(ApplicationArguments args) throws Exception { System.out.println("初始化........."); // 2,zookeeper實現監聽功能,當主節點掛了之后,繼續選舉 if (zkClient != null) { // 1,在初始化過程中創建一個臨時節點,如果成功,則選為master節點 election(); // zookeeper 數據監聽的接口 IZkDataListener izkDataListener = new IZkDataListener() { public void handleDataChange(String arg0, Object arg1) throws Exception { } public void handleDataDeleted(String path) throws Exception { // 一直在監聽,節點有變化的時候原子量就是-1 if (countDownLatch != null) { countDownLatch.countDown(); } } }; //zkClient會去監聽 zkClient.subscribeDataChanges(PATH, izkDataListener); if (zkClient.exists(PATH)) { countDownLatch = new CountDownLatch(1); try { // 一直進行等待,等待監聽的路徑有變化 countDownLatch.await(); election(); } catch (Exception e) { e.printStackTrace(); } } // 刪除監聽 zkClient.unsubscribeDataChanges(PATH, izkDataListener); } } private void election() { try { zkClient.createEphemeral(PATH, serverPort); System.out.println("選舉成功"); ZookeeperMaster.masterIsAlive = true; } catch (Exception e) { ZookeeperMaster.masterIsAlive = false; } } }
public class ZookeeperMaster { public static boolean masterIsAlive = false; }