zookeeper內部機制與註冊監聽機制
zookeeper應用:
You can use it off-the-shelf to implement consensus, group management, leader election, and presence protocols. And you can build on it for your own, specific needs.
叢集節點為什麼建議奇數個?
只有超過一半的節點正常,叢集才正常,才可以對外服務。
所以,1個節點可以;2個節點,死一個叢集就不能用了,所以和一個是一樣的;
三個節點,四個節點死一個可以用,死兩個不能用,所以和三個是一樣的。
所以,需要配置奇數個節點。
zookeeper如何選舉?投票結果超過一半立馬成為leader,其餘的自動成為follower
假如有三個節點
- 啟動叢集時:
1、叢集啟動時,傳送投票,自己選舉自己為leader,只有一臺可選舉,但是沒有超過半數,進入looking狀態;
2、第二臺啟動,傳送投票,自己選舉自己為leader,與第一臺交換資訊,會進行比較epoch、zxid(新啟動這兩個值都相等),然後比較myid,選舉出myid大的那個,此時一定會有一個節點票數超過2,會產生leader
3、第三個一定是follower
- 叢集執行時,發現leader死了進行重新選舉,每個節點都發起一輪投票,此時每個節點投票的方式就是先比較epoch、再比較zxid、最後比較myid
znode註冊事件模式:
/*** * CreateMode value determines how the znode is created on ZooKeeper. */ public enum CreateMode { /** * The znode will not be automatically deleted upon client's disconnect. */ PERSISTENT (0, false, false), /** * The znode will not be automatically deleted upon client's disconnect, * and its name will be appended with a monotonically increasing number. */ PERSISTENT_SEQUENTIAL (2, false, true), /** * The znode will be deleted upon the client's disconnect. */ EPHEMERAL (1, true, false), /** * The znode will be deleted upon the client's disconnect, and its name * will be appended with a monotonically increasing number. */ EPHEMERAL_SEQUENTIAL (3, true, true);
demo註冊,監聽到進行業務處理
監聽端:
public class ClientManagerAUTO {
// zk物件
static ZooKeeper zk;
// 用來阻止程式執行
private static CountDownLatch countDown = new CountDownLatch(1);
/* 建立連線相關資訊 */
// 連線地址
static String connect = "focuson1:2181,focuson2:2181,focuson3:2181";
// 連線超時時間
static int TIME_OUT = 2000;
// 連線監控器
Watcher connectWatcher = new Watcher() {
public void process(WatchedEvent event) {
System.out.println("接收到zookeeper服務端通知,會話真正建立完成!");
}
};
// 節點是否存在監控器
Watcher existsWatcher = new Watcher() {
public void process(WatchedEvent event) {
try {
System.out.println(event.getState()+"========="+event.getType());
if(event.getState().equals(KeeperState.SyncConnected)){
System.out.println("連線上了");
}
if (event.getType().toString().equals("None")) {
System.out.println("none");
}else if (event.getType().toString().equals("NodeCreated")) {
System.out.println("節點1上線");
}else if (event.getType().toString().equals("NodeDeleted")) {
System.out.println("節點1下線");
}else if (event.getType().toString().equals("NodeDataChanged")) {
System.out.println("節點1中的資料已經被修改");
}else if (event.getType().toString().equals("NodeChildrenChanged")) {
System.out.println("節點1的子節點被修改");
}else{
System.out.println("event的資訊:"+event);
}
//重複註冊watcher
zk.exists("/big1507/node1", existsWatcher);
} catch (Exception e) {
e.printStackTrace();
}
}
};
/**
* 初始化zk物件
*/
public void init() throws Exception{
zk = new ZooKeeper(connect,TIME_OUT,connectWatcher);
}
/**
* 向zk伺服器註冊對節點1是否存在(即上線)的通知
* @param zk 客戶端
* @throws Exception
*/
public void checkExists(ZooKeeper zk) throws Exception{
zk.exists("/focuson_", existsWatcher);
}
public static void main(String[] args) throws Exception{
ClientManagerAUTO auto = new ClientManagerAUTO();
auto.init();
auto.checkExists(zk);
countDown.await();
}
}
//註冊端
public class Client1 {
//zk物件
static ZooKeeper zk;
//用來阻止程式執行
private static CountDownLatch countDown = new CountDownLatch(1);
/* 建立連線相關資訊 */
// 連線地址
static String connect = "focuson1:2181,focuson2:2181,focuson3:2181";
// 連線超時時間
static int TIME_OUT = 2000;
// 監控器
static Watcher watcher = new Watcher() {
public void process(WatchedEvent event) {
System.out.println("接收到zookeeper服務端通知,會話真正建立完成!");
System.out.println("此時zk物件資訊:"+zk);
try {
//先建立管理所有客戶端的節點
Stat s = zk.exists("/focuson_", true);
if (null==s) {
System.out.println("管理客戶端節點不存在,開始建立");
zk.create("/focuson_", "aaa".getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
}
System.out.println("node1開始向zk服務端註冊>>>>>>");
//String path = zk.create("/big1507/node1", "node1".getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
System.out.println("向zk服務端註冊成功!!!");
} catch (Exception e) {
System.out.println("會話建立完成後建立臨時節點時出現異常:"+e.getMessage());
}
}
};
public static void main(String[] args) throws Exception {
System.out.println("客戶端1程式開始啟動……");
zk = new ZooKeeper(connect, TIME_OUT, watcher);
System.out.println("zk物件建立完成!正在非同步建立和zk伺服器之間的連線:");
System.out.println("zk物件的資訊:" + zk);
countDown.await();
}
}
測試一把:
先啟動監聽端,再啟動註冊端,會輸出如下資訊:
接收到zookeeper服務端通知,會話真正建立完成!
SyncConnected=========NodeCreated
連線上了
節點1上線
在zookeeper叢集上檢視(使用zkCli.sh):
[zk: localhost:2181(CONNECTED) 0] ls /
[focuson_, zookeeper, yarn-leader-election, spark, hadoop-ha, hbase]
關閉client1,focuson_資料夾不存在,說明註冊的是臨時節點。zookeeper應用場景如下等:
1.1、各種HA,比如NameNode HA、HMaster HA、Spark Master HA、ResourceManager HA;
1.2、各種監控,比如,HRegionServer失敗後HMaster能監控到,執行重啟、等待重啟等;
2、hbase的Meta表資訊(或是root表資訊)
應用場景舉yarn例
yarn在zookeeper節點建立的資料夾:
/yarn-leader-election
--yrc(yarn叢集的名字)
--ActiveBreadCrumb(持久化的節點)
--ActiveStandbyElectorLock(臨時節點)
當yarn ResourceManager沒有啟動(yarn之前啟動過)時,沒有ActiveStandbyElectorLock資料夾,ActiveBreadCrumb資料夾存在,值為上次alive ResourceManager的值,如yrcrm2(根據配置檔案的配置來的)。
[zk: localhost:2181(CONNECTED) 101] get /yarn-leader-election/yrc/ActiveBreadCrumb
yrcrm2
cZxid = 0x1b00000055
ctime = Sun May 06 07:21:40 PDT 2018
mZxid = 0x1c00000019
mtime = Fri May 11 21:05:28 PDT 2018
pZxid = 0x1b00000055
cversion = 0
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0
當啟動ResourceManager時,資料夾ActiveStandbyElectorLock被建立,值為yrcrm1(根據配置檔案的配置來的),此時ActiveBreadCrumb也是yrcrm1
[zk: localhost:2181(CONNECTED) 102] get /yarn-leader-election/yrc/ActiveBreadCrumb
yrcrm1
cZxid = 0x1b00000055
ctime = Sun May 06 07:21:40 PDT 2018
mZxid = 0x1c0000001f
mtime = Fri May 11 21:18:53 PDT 2018
pZxid = 0x1b00000055
cversion = 0
dataVersion = 4
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0
[zk: localhost:2181(CONNECTED) 103] get /yarn-leader-election/yrc/ActiveStandbyElectorLock
yrcrm1
cZxid = 0x1c0000001e
ctime = Fri May 11 21:18:53 PDT 2018
mZxid = 0x1c0000001e
mtime = Fri May 11 21:18:53 PDT 2018
pZxid = 0x1c0000001e
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x1000003187b0002
dataLength = 10
numChildren = 0
此時rm2正在監聽ActiveStandbyElectorLock臨時節點,當該臨時節點不存在時,會自己建立一個值為yrcrm2的ActiveStandbyElectorLock臨時節點。