一、Master選舉使用場景及結構
- 現在很多時候我們的服務需要7*24小時工作,假如一台機器掛了,我們希望能有其它機器頂替它繼續工作。此類問題現在多采用master-salve模式,也就是常說的主從模式,正常情況下主機提供服務,備機負責監聽主機狀態,當主機異常時,可以自動切換到備機繼續提供服務(這里有點兒類似於數據庫主庫跟備庫,備機正常情況下只監聽,不工作),這個切換過程中選出下一個主機的過程就是master選舉。
- 對於以上提到的場景,傳統的解決方式是采用一個備用節點,這個備用節點定期給當前主節點發送ping包,主節點收到ping包后會向備用節點發送應答ack,當備用節點收到應答,就認為主節點還活着,讓它繼續提供服務,否則就認為主節點掛掉了,自己將開始行使主節點職責。如圖1所示:
Zookeeper選舉策略

二、代碼實現
2.1 Maven依賴信息
<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>
2.2 IndexController
@RestController
public class IndexController {
// 獲取服務信息
@RequestMapping("/getServerInfo")
public String getServerInfo() {
return ElectionMaster.isSurvival ? "當前服務器為主節點" : "當前服務器為從節點";
}
}
2.3 MyApplicationRunner
@Component
public class MyApplicationRunner implements ApplicationRunner {
// 創建zk連接
ZkClient zkClient = new ZkClient("127.0.0.1:2181");
private String path = "/election";
@Value("${server.port}")
private String serverPort;
public void run(ApplicationArguments args) throws Exception {
System.out.println("項目啟動完成...");
createEphemeral();
// 創建事件監聽
zkClient.subscribeDataChanges(path, new IZkDataListener() {
// 節點被刪除
public void handleDataDeleted(String dataPath) throws Exception {
// 主節點已經掛了,重新選舉
System.out.println("主節點已經掛了,重新開始選舉");
createEphemeral();
}
public void handleDataChange(String dataPath, Object data) throws Exception {
}
});
}
private void createEphemeral() {
try {
zkClient.createEphemeral(path, serverPort);
ElectionMaster.isSurvival = true;
System.out.println("serverPort:" + serverPort + ",選舉成功....");
} catch (Exception e) {
ElectionMaster.isSurvival = false;
}
}
}
2.4 ElectionMaster
@Component
public class ElectionMaster {
// 服務器info信息 是否存活
public static boolean isSurvival;
}