Zookeeper實現Master選舉(哨兵機制)
阿新 • • 發佈:2018-11-04
master選舉使用場景及結構
現在很多時候我們的服務需要7*24小時工作,假如一臺機器掛了,我們希望能有其它機器頂替它繼續工作。此類問題現在多采用master-salve模式,也就是常說的主從模式,正常情況下主機提供服務,備機負責監聽主機狀態,當主機異常時,可以自動切換到備機繼續提供服務(這裡有點兒類似於資料庫主庫跟備庫,備機正常情況下只監聽,不工作),這個切換過程中選出下一個主機的過程就是master選舉。
對於以上提到的場景,傳統的解決方式是採用一個備用節點,這個備用節點定期給當前主節點發送ping包,主節點收到ping包後會向備用節點發送應答ack,當備用節點收到應答,就認為主節點還活著,讓它繼續提供服務,否則就認為主節點掛掉了,自己將開始行使主節點職責。如圖1所示:
使用Zookeeper實現服務master選舉
在哨兵機制中 只能一個主 多個從!
使用zk可以實現之!
原理: 多個伺服器在啟動時候,會在Zookeeper上建立相同的臨時節點,誰如果能夠建立成功,誰就為主!(節點保證唯一)
如果主伺服器宕機,會話連線斷開。臨時節點刪除。其他節點服務選舉開始
建立專案:
pom檔案: 注意springboot 整合 zk的包
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> <exclusions> <exclusion> <artifactId>slf4j-api</artifactId> <groupId>org.slf4j</groupId> </exclusion> <exclusion> <artifactId>log4j</artifactId> <groupId>log4j</groupId> </exclusion> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
後臺controller
package com.toov5.zkMaster; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IndexController { @Value("${server.port}") private String serverPort; @RequestMapping("getServerInfo") public String getServerInfo(){ return "serverPort"+serverPort+(ElectionMaster.isSurvival? "選舉為主" :"選舉為從"); } public static void main(String[] args) { //1,專案啟動的時候 在zk建立臨時節點 //2,誰能夠建立成功誰就是主伺服器 //3,使用服務監聽節點是否被刪除,如果被刪。 重新開始建立節點 } }
啟動載入執行類
package com.toov5.zkMaster; import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient; 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 ZkClient zkClient = new ZkClient("192.168.91.5:2181"); private String path = "/election"; @Value("${server.port}") private String serverPort; //啟動後執行的方法 public void run(ApplicationArguments args) throws Exception { //重寫這個方法 System.out.println("專案啟動成功!"); //1,專案啟動的時候 在zk建立臨時節點 createEphemeral(); //2,誰能夠建立成功誰就是主伺服器 //3,使用服務監聽節點是否被刪除,如果被刪。 重新開始建立節點 zkClient.subscribeDataChanges(path, new IZkDataListener() { //返回節點如果被刪除後 返回通知 public void handleDataDeleted(String arg0) throws Exception { //重新建立(選舉) System.out.println("開始重新選舉策略"); createEphemeral(); } public void handleDataChange(String arg0, Object arg1) throws Exception { // TODO Auto-generated method stub } }); } private void createEphemeral(){ try { zkClient.createEphemeral(path); System.out.println("serverport"+serverPort+",選舉成功!"); ElectionMaster.isSurvival=true; //標誌位true 單個jvm共享 } catch (Exception e) { System.out.println("該節點已經存在"); ElectionMaster.isSurvival=false; } } }
全域性變數
package com.toov5.zkMaster; public class ElectionMaster { //伺服器info資訊 是否存活 public static boolean isSurvival; //靜態的 標誌下 伺服器是否還存活 }
執行類
package com.toov5.zkMaster; public class ElectionMaster { //伺服器info資訊 是否存活 public static boolean isSurvival; //靜態的 標誌下 伺服器是否還存活 }
yml:
server: port: 8088
執行,啟動兩個埠
一個主 一個從
然後關掉主,重新選舉從(需要等待一段時間,強制關閉有延遲的)