概述
利用zookeeper來進行選主,可以使用apache curator framework,它給我們封裝了兩種選主工具,它們分別是LeaderSelector和LeaderLatch。它們各自的應用場景不一樣,LeaderSelector應用于那些需要頻繁變主的情況,而LeaderLatch則用于不頻繁變主的情況。今天我們主要介紹LeaderLatch。
原理
LeaderLatch的實現原理其實是利用了zookeeper的臨時有序節點來實現,比如我們在/leader目錄下創建臨時有序的節點,那么應用第一個實例創建類似/leader/node-0,第二個實例創建類似/leader/node-1(實際目錄名不是叫這個,這里只是打個比方),那么LeaderLatch會選擇序號最小的zookeeper節點作為主節點,每個從節點實例都會監聽前一個比自己小的znode的事件,一旦比自己小的zookeeper節點發生變化,則立馬檢測自身是否可成為主節點。
實現
引入maven依賴
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.3.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.3.0</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><!--需要和你zookeeper的版本一致--><version>3.4.14</version></dependency>
初始化CuratorFramework Client
public void initClient() {CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181").retryPolicy(new RetryNTimes(1, 1000)).connectionTimeoutMs(30 * 1000).sessionTimeoutMs(60 * 1000);client = builder.build();client.start();
}
創建LeaderLatch實例
public void initLeaderLatch() throws Exception {//participantId 為選舉者ID,LeaderLatch.CloseMode.NOTIFY_LEADER 模式在失主的時候會回調下notLeader方法 LeaderLatch leaderLatch = new LeaderLatch(client, "/leader", "participantId", LeaderLatch.CloseMode.NOTIFY_LEADER);leaderLatch.addListener(new LeaderLatchListener() {@Overridepublic void isLeader() {System.out.print("I am leader.");}@Overridepublic void notLeader() {System.out.print("I am not leader.");}});leaderLatch.start();
}
關閉資源釋放連接
public void close() throws IOException {leaderLatch.close();client.close();
}
檢查自己是否還在選民列表中
可以定時的檢查一下應用實例是否還在選民列表中,如果已不在選民列表中,可先關閉連接,然后再重新初始化client和LeaderLatch,維持應用集群狀態與zookeeper上的臨時有序節點的最終一致性。
/*** 檢查當前進程是否還在選民列表中,不在的話,可以進行重連,使得自己重新回到選民列表中 */public boolean checkMeInParticipants() throws Exception {boolean result = false;Collection<Participant> participants = participants = this.leaderLatch.getParticipants();for (Participant participant : participants) {if ("participantId".equals(participant.getId())) {result = true;break;}}return result;}