LeaderLatch
一旦節點成爲主節點,那麼只有調用close方法,其它節點纔會繼續爭奪
List<LeaderLatch> latches = new ArrayList<>();
List<CuratorFramework> clients = new ArrayList<>();
for (int i = 0; i < 10; i++) {
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
clients.add(client);
LeaderLatch leaderLatch = new LeaderLatch(client, "/master", "node-" + i, LeaderLatch.CloseMode.NOTIFY_LEADER);
leaderLatch.addListener(new LeaderLatchListener() {
@Override
public void isLeader() {
System.out.println(leaderLatch.getId() + " is a leader ");
}
@Override
public void notLeader() {
System.out.println(leaderLatch.getId() + " not a leader ");
}
});
latches.add(leaderLatch);
}
for (LeaderLatch latch : latches) {
new Thread(new Runnable() {
@Override
public void run() {
try {
latch.start();
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(latch.getId()+" elect end");
}
}).start();
}
Thread.sleep(10000);
for (LeaderLatch latch : latches) {
System.out.println(latch.getId() + " leader:" + latch.getLeader() + " isLeader:" + latch.hasLeadership());
if(latch.hasLeadership()){
latch.close();
}
}
for (CuratorFramework client : clients) {
System.out.println(client.getData() + " is close");
client.close();
}
Thread.sleep(100000);
在上面的例子中創建了10個clien,當某一個clien成爲主節點後,就會觸發isLeader方法,調用close方法後會觸發notLeader,然後再在其它節點中選舉一個新的leader,並且只有主節點才能繼續執行latch.await()後面的邏輯。
LeaderSelector
當實例被選爲leader之後,調用takeLeadership方法進行業務邏輯處理,處理完成即釋放領導權。
autoRequeue()方法的調用確保此實例在釋放領導權後還可能獲得領導權。
這樣保證了每個節點都可以獲得領導權。
List<LeaderSelector> leaderSelectors = new ArrayList<>();
List<CuratorFramework> clients = new ArrayList<>();
for (int i = 0; i < 10; i++) {
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
clients.add(client);
LeaderSelector leaderSelector = new LeaderSelector(client, "/master", new LeaderSelectorListenerAdapter() {
@Override
public void takeLeadership(CuratorFramework curatorFramework) throws Exception {
System.out.println(Thread.currentThread().getName() + " is a leader");
Thread.sleep(Integer.MAX_VALUE);
}
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
super.stateChanged(client, newState);
}
});
leaderSelectors.add(leaderSelector);
}
leaderSelectors.forEach(leaderSelector -> {
leaderSelector.autoRequeue();
leaderSelector.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("==================");
clients.forEach(client -> {
client.close();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread.sleep(100 * 1000);
在上面的例子中同樣新建10個客戶端然後進行選舉,當調用close方法後其它節點會重新選舉新的主節點。
當我們把takeLeadership方法中的Thread.sleep(Integer.MAX_VALUE);改爲Thread.sleep(3*1000);當takeLeadership方法執行結束,就自動放棄領導權,其它節點重新選舉。
當註釋掉leaderSelector.autoRequeue()後,釋放了領導權的節點不能再次獲取領導權。
區別
- leaderlatch需要調用close方法才能釋放主導權,並且不能重新獲得。leaderselector當執行完takeleadership方法後自動釋放主導權,並且可以設置autorequeue重新再獲取領導權
- 實現方式不同leaderselector使用分佈式鎖InterProcessMutex實現