利用Zookeeper實現(xiàn) - Master選舉

      網(wǎng)友投稿 1003 2025-04-02

      Zookeeper 是一個高可用的分布式數(shù)據(jù)管理與協(xié)調框架,基于ZAB協(xié)議算法的實現(xiàn),該框架能夠很好的保證分布式環(huán)境中數(shù)據(jù)的一致性。Zookeeper的典型應用場景主要有:數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務、分布式協(xié)調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等。


      本文主要介紹如何利用Zookeeper實現(xiàn)Master選舉。

      Master選舉

      Master選舉在分布式系統(tǒng)中是一個非常常見的場景。在分布式系統(tǒng)中,常常采用主從模式的方式避免單點故障,提高系統(tǒng)服務的可用性。正常情況下,Master節(jié)點用來協(xié)調集群中其他系統(tǒng)單元,維護系統(tǒng)狀態(tài)信息,或者負責一些復雜的邏輯,再將處理結果同步給其他節(jié)點。當Master節(jié)點宕機,或者由于其他問題導致無法提供服務時,系統(tǒng)將發(fā)起一次Master選舉,從候選節(jié)點中選出一個新的Master節(jié)點,以繼續(xù)提供服務。

      譬如在一些讀寫分離的應用中,Master節(jié)點負責客戶端的寫請求,處理完畢之后再將結果同步給從節(jié)點。

      選舉算法?

      著名的選舉算法有 Paxos算法、Raft算法、Bully算法等,但在業(yè)務系統(tǒng)的開發(fā)中,實現(xiàn)選舉算法并不是我們工作的重心。

      Zookeeper有一個非常重要的特性即強一致性,能夠很好地保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定能夠保證全局唯一性,即Zookeeper將會保證客戶端無法重復創(chuàng)建一個已經(jīng)存在的數(shù)據(jù)節(jié)點。也就是說,如果同時有多個客戶端請求創(chuàng)建同一個節(jié)點,那么最終一定只有一個客戶端請求能夠創(chuàng)建成功。利用這個特性,就能很容易地在分布式環(huán)境中進行Master選舉了。

      利用Zookeeper實現(xiàn)Master選舉

      Apache Curator是一個Zookeeper的開源客戶端,它提供了Zookeeper各種應用場景(Recipe,如共享鎖服務、master選舉、分布式計數(shù)器等)的抽象封裝,本文使用 Curator 提供的Recipe來實現(xiàn)Master選舉。

      Curator提供了兩種選舉方案:Leader Latch 和 Leader Election。下面分別介紹這兩種選舉方案。

      Leader Latch

      使用 Leader Latch 方案進行Master選舉,系統(tǒng)將隨機從候選者中選出一臺作為 leader,直到調用 close() 釋放leadship,此時再重新隨機選舉 leader,否則其他的候選者無法成為 leader。

      下面的程序將啟動 N 個線程用來模擬分布式系統(tǒng)中的節(jié)點,每個線程將創(chuàng)建一個Zookeeper客戶端和一個 LeaderLatch 對象用于選舉;每個線程有一個名稱,名稱中有一個編號用于區(qū)分;每個線程的存活時間為 number * 10秒 ,存活時間結束后將關閉 LeaderLatch 對象和客戶端,表示該 '節(jié)點' 宕機,如果該節(jié)點為 Master節(jié)點,這時系統(tǒng)將重新發(fā)起 Master選舉。

      public?class?LeaderLatchTest?{

      private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";

      private?static?final?String?masterPath?=?"/testZK/leader_latch";

      public?static?void?main(String[]?args)?{

      final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬

      final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);

      List?latchList?=?new?CopyOnWriteArrayList();

      List?clientList?=?new?CopyOnWriteArrayList();

      AtomicInteger?atomicInteger?=?new?AtomicInteger(1);

      try?{

      for?(int?i?=?0;?i?

      new?Thread(new?Runnable()?{

      @Override

      public?void?run()?{

      CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端

      clientList.add(client);

      int?number?=?atomicInteger.getAndIncrement();

      final?LeaderLatch?latch?=?new?LeaderLatch(client,?masterPath,?"client#"?+?number);

      System.out.println("創(chuàng)建客戶端:"?+?latch.getId());

      //?LeaderLatch?添加監(jiān)聽事件

      latch.addListener(new?LeaderLatchListener()?{

      @Override

      public?void?isLeader()?{

      System.out.println(latch.getId()?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");

      }

      @Override

      public?void?notLeader()?{

      System.out.println(latch.getId()?+?":?我遺憾地落選了,我到一旁休息去吧...");

      }

      });

      latchList.add(latch);

      try?{

      latch.start();

      //?隨機等待?number?*?10秒,之后關閉客戶端

      Thread.sleep(number?*?10000);

      }?catch?(Exception?e)?{

      System.out.println(e.getMessage());

      }?finally?{

      System.out.println("客戶端?"?+?latch.getId()?+?"?關閉");

      CloseableUtils.closeQuietly(latch);

      CloseableUtils.closeQuietly(client);

      countDownLatch.countDown();

      }

      }

      }).start();

      }

      countDownLatch.await();?//?等待,只有所有線程都退出

      }?catch?(Exception?e)?{

      e.printStackTrace();

      }

      }

      private?static?synchronized?CuratorFramework?getClient()?{

      CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)

      .sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")

      .retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();

      client.start();

      return?client;

      }

      }

      控制臺輸出的日志

      創(chuàng)建客戶端:client#1

      創(chuàng)建客戶端:client#2

      創(chuàng)建客戶端:client#3

      創(chuàng)建客戶端:client#4

      創(chuàng)建客戶端:client#5

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#1?關閉

      客戶端?client#2?關閉

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#3?關閉

      客戶端?client#4?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#5?關閉

      系統(tǒng)運行過程中查看 masterPath 可以看見客戶端注冊的臨時節(jié)點,當客戶端關閉時,臨時節(jié)點也會被刪除

      LeaderLatch選舉時的ZK節(jié)點

      Leader Election

      通過 Leader Election 選舉方案進行 Master選舉,需添加 LeaderSelectorListener -對領導權進行控制,當節(jié)點被選為leader之后,將調用 takeLeadership 方法進行業(yè)務邏輯處理,處理完成會立即釋放 leadship,重新進行Master選舉,這樣每個節(jié)點都有可能成為 leader。autoRequeue() 方法的調用確保此實例在釋放領導權后還可能獲得領導權。

      利用Zookeeper實現(xiàn) - Master選舉

      public?class?LeaderSelectorTest?{

      private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";

      private?static?final?String?masterPath?=?"/testZK/leader_selector";

      public?static?void?main(String[]?args)?{

      final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬

      final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);

      List?selectorList?=?new?CopyOnWriteArrayList();

      List?clientList?=?new?CopyOnWriteArrayList();

      AtomicInteger?atomicInteger?=?new?AtomicInteger(1);

      try?{

      for?(int?i?=?0;?i?

      new?Thread(new?Runnable()?{

      @Override

      public?void?run()?{

      CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端

      clientList.add(client);

      int?number?=?atomicInteger.getAndIncrement();

      final?String?name?=?"client#"?+?number;

      final?LeaderSelector?selector?=?new?LeaderSelector(client,?masterPath,?new?LeaderSelectorListener()?{

      @Override

      public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{

      System.out.println(name?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");

      Thread.sleep(3000);

      }

      @Override

      public?void?stateChanged(CuratorFramework?curatorFramework,?ConnectionState?connectionState)?{

      }

      });

      System.out.println("創(chuàng)建客戶端:"?+?name);

      try?{

      selector.autoRequeue();

      selector.start();

      selectorList.add(selector);

      //?隨機等待?number?*?10秒,之后關閉客戶端

      Thread.sleep(number?*?10000);

      }?catch?(Exception?e)?{

      System.out.println(e.getMessage());

      }?finally?{

      countDownLatch.countDown();

      System.out.println("客戶端?"?+?name?+?"?關閉");

      CloseableUtils.closeQuietly(selector);

      if?(!client.getState().equals(CuratorFrameworkState.STOPPED))?{

      CloseableUtils.closeQuietly(client);

      }

      }

      }

      }).start();

      }

      countDownLatch.await();?//?等待,只有所有線程都退出

      }?catch?(Exception?e)?{

      e.printStackTrace();

      }

      }

      private?static?synchronized?CuratorFramework?getClient()?{

      CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)

      .sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")

      .retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();

      client.start();

      return?client;

      }

      }

      控制臺輸出的日志信息

      創(chuàng)建客戶端:client#2

      創(chuàng)建客戶端:client#1

      創(chuàng)建客戶端:client#3

      創(chuàng)建客戶端:client#5

      創(chuàng)建客戶端:client#4

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#1?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#2?關閉

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#3?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#4?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#5?關閉

      LeaderSelectorListener類繼承了ConnectionStateListener。一旦LeaderSelector啟動,它會向curator客戶端添加-。使用LeaderSelector必須時刻注意連接的變化。一旦出現(xiàn)連接問題如 SUSPENDED,curator實例必須確保它不再是leader,直至它重新收到 RECONNECTED。如果 LOST 出現(xiàn),curator實例不再是 leader 并且其 takeLeadership() 應該直接退出。

      推薦的做法是,如果發(fā)生 SUSPENDED 或者 LOST 連接問題,最好直接拋CancelLeadershipException,此時,leaderSelector實例會嘗試中斷并且取消正在執(zhí)行 takeLeadership() 方法的線程。 建議擴展LeaderSelectorListenerAdapter,LeaderSelectorListenerAdapter中已經(jīng)提供了推薦的處理方式 。

      后序

      代碼:https://github.com/whirlys/BigData-In-Practice/tree/master/curator-example/src/main/java/com/whirly/recipes

      參考:

      《從Paxos到Zookeeper分布式一致性原理與實踐》

      Zookeeper開源客戶端Curator之Master/Leader選舉

      關注_小旋鋒_微信公眾號

      Zookeeper 是一個高可用的分布式數(shù)據(jù)管理與協(xié)調框架,基于ZAB協(xié)議算法的實現(xiàn),該框架能夠很好的保證分布式環(huán)境中數(shù)據(jù)的一致性。Zookeeper的典型應用場景主要有:數(shù)據(jù)發(fā)布/訂閱、負載均衡、命名服務、分布式協(xié)調/通知、集群管理、Master選舉、分布式鎖和分布式隊列等。

      本文主要介紹如何利用Zookeeper實現(xiàn)Master選舉。

      Master選舉

      Master選舉在分布式系統(tǒng)中是一個非常常見的場景。在分布式系統(tǒng)中,常常采用主從模式的方式避免單點故障,提高系統(tǒng)服務的可用性。正常情況下,Master節(jié)點用來協(xié)調集群中其他系統(tǒng)單元,維護系統(tǒng)狀態(tài)信息,或者負責一些復雜的邏輯,再將處理結果同步給其他節(jié)點。當Master節(jié)點宕機,或者由于其他問題導致無法提供服務時,系統(tǒng)將發(fā)起一次Master選舉,從候選節(jié)點中選出一個新的Master節(jié)點,以繼續(xù)提供服務。

      譬如在一些讀寫分離的應用中,Master節(jié)點負責客戶端的寫請求,處理完畢之后再將結果同步給從節(jié)點。

      著名的選舉算法有 Paxos算法、Raft算法、Bully算法等,但在業(yè)務系統(tǒng)的開發(fā)中,實現(xiàn)選舉算法并不是我們工作的重心。

      Zookeeper有一個非常重要的特性即強一致性,能夠很好地保證在分布式高并發(fā)情況下節(jié)點的創(chuàng)建一定能夠保證全局唯一性,即Zookeeper將會保證客戶端無法重復創(chuàng)建一個已經(jīng)存在的數(shù)據(jù)節(jié)點。也就是說,如果同時有多個客戶端請求創(chuàng)建同一個節(jié)點,那么最終一定只有一個客戶端請求能夠創(chuàng)建成功。利用這個特性,就能很容易地在分布式環(huán)境中進行Master選舉了。

      利用Zookeeper實現(xiàn)Master選舉

      Apache Curator是一個Zookeeper的開源客戶端,它提供了Zookeeper各種應用場景(Recipe,如共享鎖服務、master選舉、分布式計數(shù)器等)的抽象封裝,本文使用 Curator 提供的Recipe來實現(xiàn)Master選舉。

      Curator提供了兩種選舉方案:Leader Latch 和 Leader Election。下面分別介紹這兩種選舉方案。

      使用 Leader Latch 方案進行Master選舉,系統(tǒng)將隨機從候選者中選出一臺作為 leader,直到調用 close() 釋放leadship,此時再重新隨機選舉 leader,否則其他的候選者無法成為 leader。

      下面的程序將啟動 N 個線程用來模擬分布式系統(tǒng)中的節(jié)點,每個線程將創(chuàng)建一個Zookeeper客戶端和一個 LeaderLatch 對象用于選舉;每個線程有一個名稱,名稱中有一個編號用于區(qū)分;每個線程的存活時間為 number * 10秒 ,存活時間結束后將關閉 LeaderLatch 對象和客戶端,表示該 '節(jié)點' 宕機,如果該節(jié)點為 Master節(jié)點,這時系統(tǒng)將重新發(fā)起 Master選舉。

      public?class?LeaderLatchTest?{

      private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";

      private?static?final?String?masterPath?=?"/testZK/leader_latch";

      public?static?void?main(String[]?args)?{

      final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬

      final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);

      List?latchList?=?new?CopyOnWriteArrayList();

      List?clientList?=?new?CopyOnWriteArrayList();

      AtomicInteger?atomicInteger?=?new?AtomicInteger(1);

      try?{

      for?(int?i?=?0;?i?

      new?Thread(new?Runnable()?{

      @Override

      public?void?run()?{

      CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端

      clientList.add(client);

      int?number?=?atomicInteger.getAndIncrement();

      final?LeaderLatch?latch?=?new?LeaderLatch(client,?masterPath,?"client#"?+?number);

      System.out.println("創(chuàng)建客戶端:"?+?latch.getId());

      //?LeaderLatch?添加監(jiān)聽事件

      latch.addListener(new?LeaderLatchListener()?{

      @Override

      public?void?isLeader()?{

      System.out.println(latch.getId()?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");

      }

      @Override

      public?void?notLeader()?{

      System.out.println(latch.getId()?+?":?我遺憾地落選了,我到一旁休息去吧...");

      }

      });

      latchList.add(latch);

      try?{

      latch.start();

      //?隨機等待?number?*?10秒,之后關閉客戶端

      Thread.sleep(number?*?10000);

      }?catch?(Exception?e)?{

      System.out.println(e.getMessage());

      }?finally?{

      System.out.println("客戶端?"?+?latch.getId()?+?"?關閉");

      CloseableUtils.closeQuietly(latch);

      CloseableUtils.closeQuietly(client);

      countDownLatch.countDown();

      }

      }

      }).start();

      }

      countDownLatch.await();?//?等待,只有所有線程都退出

      }?catch?(Exception?e)?{

      e.printStackTrace();

      }

      }

      private?static?synchronized?CuratorFramework?getClient()?{

      CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)

      .sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")

      .retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();

      client.start();

      return?client;

      }

      }

      控制臺輸出的日志

      創(chuàng)建客戶端:client#1

      創(chuàng)建客戶端:client#2

      創(chuàng)建客戶端:client#3

      創(chuàng)建客戶端:client#4

      創(chuàng)建客戶端:client#5

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#1?關閉

      客戶端?client#2?關閉

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#3?關閉

      客戶端?client#4?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#5?關閉

      系統(tǒng)運行過程中查看 masterPath 可以看見客戶端注冊的臨時節(jié)點,當客戶端關閉時,臨時節(jié)點也會被刪除

      通過 Leader Election 選舉方案進行 Master選舉,需添加 LeaderSelectorListener -對領導權進行控制,當節(jié)點被選為leader之后,將調用 takeLeadership 方法進行業(yè)務邏輯處理,處理完成會立即釋放 leadship,重新進行Master選舉,這樣每個節(jié)點都有可能成為 leader。autoRequeue() 方法的調用確保此實例在釋放領導權后還可能獲得領導權。

      public?class?LeaderSelectorTest?{

      private?static?final?String?zkServerIps?=?"master:2181,hadoop2:2181";

      private?static?final?String?masterPath?=?"/testZK/leader_selector";

      public?static?void?main(String[]?args)?{

      final?int?clientNums?=?5;??//?客戶端數(shù)量,用于模擬

      final?CountDownLatch?countDownLatch?=?new?CountDownLatch(clientNums);

      List?selectorList?=?new?CopyOnWriteArrayList();

      List?clientList?=?new?CopyOnWriteArrayList();

      AtomicInteger?atomicInteger?=?new?AtomicInteger(1);

      try?{

      for?(int?i?=?0;?i?

      new?Thread(new?Runnable()?{

      @Override

      public?void?run()?{

      CuratorFramework?client?=?getClient();??//?創(chuàng)建客戶端

      clientList.add(client);

      int?number?=?atomicInteger.getAndIncrement();

      final?String?name?=?"client#"?+?number;

      final?LeaderSelector?selector?=?new?LeaderSelector(client,?masterPath,?new?LeaderSelectorListener()?{

      @Override

      public?void?takeLeadership(CuratorFramework?client)?throws?Exception?{

      System.out.println(name?+?":?我現(xiàn)在被選舉為Leader!我開始工作了....");

      Thread.sleep(3000);

      }

      @Override

      public?void?stateChanged(CuratorFramework?curatorFramework,?ConnectionState?connectionState)?{

      }

      });

      System.out.println("創(chuàng)建客戶端:"?+?name);

      try?{

      selector.autoRequeue();

      selector.start();

      selectorList.add(selector);

      //?隨機等待?number?*?10秒,之后關閉客戶端

      Thread.sleep(number?*?10000);

      }?catch?(Exception?e)?{

      System.out.println(e.getMessage());

      }?finally?{

      countDownLatch.countDown();

      System.out.println("客戶端?"?+?name?+?"?關閉");

      CloseableUtils.closeQuietly(selector);

      if?(!client.getState().equals(CuratorFrameworkState.STOPPED))?{

      CloseableUtils.closeQuietly(client);

      }

      }

      }

      }).start();

      }

      countDownLatch.await();?//?等待,只有所有線程都退出

      }?catch?(Exception?e)?{

      e.printStackTrace();

      }

      }

      private?static?synchronized?CuratorFramework?getClient()?{

      CuratorFramework?client?=?CuratorFrameworkFactory.builder().connectString(zkServerIps)

      .sessionTimeoutMs(6000).connectionTimeoutMs(3000)?//.namespace("LeaderLatchTest")

      .retryPolicy(new?ExponentialBackoffRetry(1000,?3)).build();

      client.start();

      return?client;

      }

      }

      控制臺輸出的日志信息

      創(chuàng)建客戶端:client#2

      創(chuàng)建客戶端:client#1

      創(chuàng)建客戶端:client#3

      創(chuàng)建客戶端:client#5

      創(chuàng)建客戶端:client#4

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#1?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#2:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#2?關閉

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#3:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#3?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#4:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#4?關閉

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      client#5:?我現(xiàn)在被選舉為Leader!我開始工作了....

      客戶端?client#5?關閉

      LeaderSelectorListener類繼承了ConnectionStateListener。一旦LeaderSelector啟動,它會向curator客戶端添加-。使用LeaderSelector必須時刻注意連接的變化。一旦出現(xiàn)連接問題如 SUSPENDED,curator實例必須確保它不再是leader,直至它重新收到 RECONNECTED。如果 LOST 出現(xiàn),curator實例不再是 leader 并且其 takeLeadership() 應該直接退出。

      推薦的做法是,如果發(fā)生 SUSPENDED 或者 LOST 連接問題,最好直接拋CancelLeadershipException,此時,leaderSelector實例會嘗試中斷并且取消正在執(zhí)行 takeLeadership() 方法的線程。 建議擴展LeaderSelectorListenerAdapter,LeaderSelectorListenerAdapter中已經(jīng)提供了推薦的處理方式 。

      代碼:https://github.com/whirlys/BigData-In-Practice/tree/master/curator-example/src/main/java/com/whirly/recipes

      參考:

      《從Paxos到Zookeeper分布式一致性原理與實踐》

      Zookeeper開源客戶端Curator之Master/Leader選舉

      大數(shù)據(jù) ZooKeeper

      版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內刪除侵權內容。

      上一篇:如何運轉私域流量(私域流量運行筆記)
      下一篇:wps怎么縮小頁面?
      相關文章
      亚洲精品无码不卡在线播HE| 国产精品亚洲一区二区在线观看| 亚洲成A人片在线观看中文| 亚洲综合久久一本伊伊区| 亚洲日本国产乱码va在线观看| 337p欧洲亚洲大胆艺术| 99亚洲精品高清一二区| 久久精品国产亚洲| 亚洲AV无码成人精品区蜜桃| 亚洲AV无码乱码国产麻豆| 亚洲成AV人片在WWW色猫咪| 国产亚洲av片在线观看播放| 国产成人亚洲综合色影视| 日韩va亚洲va欧洲va国产| 亚洲VA中文字幕无码一二三区| 亚洲不卡av不卡一区二区| 亚洲国产精品人久久| 在线免费观看亚洲| 亚洲美女aⅴ久久久91| 亚洲成人免费在线观看| 亚洲国产成人精品久久| 亚洲最大的黄色网| 亚洲国产欧美国产综合一区 | 亚洲国产精品丝袜在线观看| 国产成人亚洲精品91专区高清 | 18亚洲男同志videos网站| 亚洲成A∨人片在线观看无码| 亚洲国产日韩在线一区| 亚洲中文无码亚洲人成影院| 亚洲AV无码国产精品永久一区| 女bbbbxxxx另类亚洲| 亚洲午夜精品久久久久久浪潮| 久久久久一级精品亚洲国产成人综合AV区 | 亚洲黄色免费在线观看| 亚洲天堂福利视频| 国产精品亚洲四区在线观看 | 亚洲啪啪AV无码片| 亚洲av无码不卡| 1区1区3区4区产品亚洲| 2019亚洲午夜无码天堂| 国产精品亚洲专区无码不卡|