1. 程式人生 > >zookeeper內部機制與註冊監聽機制

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臨時節點。