從零開始的高併發(六)--- Zookeeper的Master選舉及官網小覽

前言

前情概要

距離上一篇的更新也是好一段日子了,期間也是有小夥伴催更但是由於一些雜事一直沒處理好,接下來會恢復周更java

有小夥伴的反饋中說到標題都是經典應用,太過籠統因此無法經過標題得知對應內容的問題,在此也是進行了改進node

第四篇:Zookeeper的經典應用場景---標題修改成---Zookeeper的分佈式隊列
第五篇:Zookeeper的經典應用場景2---標題修改成---Zookeeper的配置中心應用
複製代碼

以往連接

從零開始的高併發(一)--- Zookeeper的基礎概念算法

從零開始的高併發(二)--- Zookeeper實現分佈式鎖編程

從零開始的高併發(三)--- Zookeeper集羣的搭建和leader選舉緩存

從零開始的高併發(四)--- Zookeeper的分佈式隊列session

從零開始的高併發(五)--- Zookeeper的配置中心應用架構

內容一:簡單談談Zookeeper的Master選舉

1.什麼是Master選舉

在分佈式架構中常常採用的結構就是一主多從,主節點祈使句就是負責協調管理集羣用的。咱們能夠借用這個場景去展開。併發

2.zookeeper如何去實現master選舉

爲何咱們要採用臨時節點,覺得考慮到master節點可能負載較高,掛掉了,這時咱們要保證其餘下面的servers服務都可以獲得通知,框架

其實咱們也能夠經過最小節點方式來實現,就誰排在前面,誰就有權利去得到master運維

3.代碼實現

① 須要使用到的變量

首先咱們須要有一個master節點,而後cluster表明的是集羣的名字,name是指服務名,address是指服務的地址。masterPath是指master的znode目錄,value是用來記錄上面的name加address的,ZkClient不用多說了,從第二篇開始用這貨用到如今了

private String cluster, name, address;

private final String masterPath, value;

private String master;

private ZkClient client; 
複製代碼

② 構造器

public Server(String cluster, String name, String address) {
	super();
	this.cluster = cluster;
	this.name = name;
	this.address = address;
	masterPath = "/" + this.cluster + "/master";
	value = "name:" + this.name + " address:" + this.address;
	client = new ZkClient("localhost:2181");
	client.setZkSerializer(new MyZkSerializer());

	String serversPath = "/" + this.cluster + "/servers";
	client.createPersistent(serversPath, true);

	String serverPath = serversPath + "/" + name;
	client.createEphemeral(serverPath, value);

	new Thread(new Runnable() {
		@Override
		public void run() {
			electionMaster(client);
		}
	}).start();

}
複製代碼

進來時你要先告訴我,你是屬於哪一個集羣的啊,你的名字,還有你的對應地址是什麼,而後咱們的masterPath就定義在這個集羣的master目錄下,這種方式讓咱們方便記錄多個不一樣的集羣。

serversPath是指集羣中全部服務信息存放的znode根目錄路徑,serverPath是一個具體的服務,是剛剛的根目錄+這個服務的名字,這個服務咱們是要存放於臨時節點(createEphemeral()方法)上的,剛剛的根目錄咱們是建立了持久節點(createPersistent()方法),爲何咱們如今要使用臨時節點了呢,由於咱們剛剛也提到了,master節點是能夠掛掉的,並且咱們以後也會進行master節點掛掉的模擬,value是用來記錄name和address的,在以後的執行結果中會打印出來

最後經過一個線程去執行這個master的選舉,咱們在master的選舉中要不停地監聽咱們的master,在master被搶到了之後,我須要對這個線程進行阻塞操做,但是若是這時候主線程阻塞了,整個程序就不跑了,因此咱們必須經過一個子線程去幫咱們去搶master,此時就算我搶不到master,也能保證整個程序能夠繼續往下執行。

③ 選舉的方法實現

public void electionMaster(ZkClient client) {
    try {
        //嘗試去獲取master
	client.createEphemeral(masterPath, value);
	
	//若是成功,記錄master節點信息
	//在這裏咱們記錄master信息並做爲緩存,方便得知這個集羣的master是誰
	//這樣就能夠再也不使用zookeeper去查master了
	master = client.readData(masterPath);
	
	System.out.println(value + "建立節點成功,成爲Master");
    } catch (ZkNodeExistsException e) {
    
        //沒有搶到master的狀況下,咱們把如今master的信息讀到本身的服務裏面
    	master = client.readData(masterPath);
    	System.out.println("Master爲:" + master);
    }

	// 爲阻塞本身等待而用
	CountDownLatch cdl = new CountDownLatch(1);

	// 註冊watcher
	IZkDataListener listener = new IZkDataListener() {

		@Override
		public void handleDataDeleted(String dataPath) throws Exception {
			System.out.println("-----監聽到節點被刪除");
			cdl.countDown();
		}

		@Override
		public void handleDataChange(String dataPath, Object data) throws Exception {

		}
	};

	client.subscribeDataChanges(masterPath, listener);

	// 讓本身阻塞
	if (client.exists(masterPath)) {
		try {
			cdl.await();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
	}
	// 醒來後,取消watcher
	client.unsubscribeDataChanges(masterPath, listener);
	// 遞歸調本身(下一次選舉)
	electionMaster(client);
}

	public void close() {
		client.close();
	}

}
複製代碼

咱們監聽節點的刪除事件,一旦master節點被釋放掉了,咱們會當即喚醒本身的線程去參與爭搶。在最後還進行了一個if (client.exists(masterPath))的判斷,肯定是已經有節點成爲了master了,咱們就會經過await方法讓本身阻塞,若是不存在master,那就從新調用自身爭搶master的方法

最後的close()方法是爲了模擬機器掛掉而使用的,與代碼自己的邏輯無關

④ 場景測試

咱們使用線程來代替進程,ScheduledThreadPoolExecutor是一個定時任務,5秒後我會關閉s1,10秒後關閉s2以此類推。

public static void main(String[] args) {
	// 測試時,依次開啓多個Server實例java進程,而後中止獲取的master的節點,看誰搶到Master
	Server s1 = new MasterElectionDemo().new Server("cluster1", "server1", "192.168.1.11:8991");
	Server s2 = new MasterElectionDemo().new Server("cluster1", "server2", "192.168.1.11:8992");
	Server s3 = new MasterElectionDemo().new Server("cluster1", "server3", "192.168.1.11:8993");
	Server s4 = new MasterElectionDemo().new Server("cluster1", "server4", "192.168.1.11:8994");
	
	ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
	scheduled.schedule(()->{
		System.out.println("關閉s1");
		s1.close();
	}, 5, TimeUnit.SECONDS);
	scheduled.schedule(()->{
		System.out.println("關閉s2");
		s2.close();
	}, 10, TimeUnit.SECONDS);
	scheduled.schedule(()->{
		System.out.println("關閉s3");
		s3.close();
	}, 15, TimeUnit.SECONDS);

	try {
		Thread.currentThread().join();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}
複製代碼

⑤ 結果分析

由於咱們s1是第一個被建立的,因此它成爲master的可能性固然是最大的

此時咱們5秒後關閉s1,這時監聽到master節點沒了,你們都被喚醒去搶master,而後s4搶到了,成爲了master

此時咱們再刪除s2和s3,就會發現和上面不同了,由於s4是master,因此我刪除s2,或者s3都不要緊,都不像刪除s1的時候會再觸發master的選舉,假設咱們下次不是s4搶到,而是s3搶到了master,那咱們在關閉s3的時候,就會像s1關閉時那樣從新觸發選舉了,不過此時就僅僅還剩s4了而已

內容二:zookeeper的官網

1.爲何要普及一下官網

在本身仍是0基礎的時候,如何來經過官網去學習,雖然如今網上關於各大框架的知識確實已經不少了,但是咱們仍是有必要去瀏覽這些開源框架的官網,由於不管網上的說法再良莠不齊衆說紛紜,但官網是表明着絕對權威的

並且官網所提到的知識通常也是基礎的應用,不會說涉及不少複雜的業務場景,從官網上去了解一個新的框架是最好的,也不會存在帶有誤導性的demo和總結,在大體瞭解以後,想看看具體的業務中使用,則可使用百度,去看看別人寫的一些應用,就沒有問題。

若是官網都會出錯,那就只能本身看源碼了,過程則會很是痛苦(攤手)

2.如何去大體地瀏覽官網

基本會按照以前寫的章節的內容去大體說明,就是之前章節提到的內容在官網中哪裏能夠找到

這是zookeeper官網的目錄結構,整個zookeeper的骨架都會列出來

① 歡迎頁

這裏其實就是介紹了每一個欄目分別都存在了什麼東西,上面的圖其實也大體翻譯了這些內容

② 咱們最關心的Programmer's Guide

Developing Distributed Applications that use ZooKeeper
    Introduction---這個模塊的簡介
    The ZooKeeper Data Model---zookeeper的數據模型
    ZNodes---znode的介紹
        Watches---監聽機制的介紹
        Data Access---以前談到額ACL
        Ephemeral Nodes---臨時節點的介紹
        Sequence Nodes -- Unique Naming---順序節點的介紹及命名惟一規則
        
        這倆是3.5.3的新加入的節點類型,咱們使用的版本並未涉及
        Container Nodes
        TTL Nodes
    
    Time in ZooKeeper---zookeeper的時間定義
    ZooKeeper Stat Structure---節點的元數據,zxid那些
    ZooKeeper Sessions---session相關
    ZooKeeper Watches---watch想關及watch怎樣用
        Semantics of Watches---watch的意義
        Remove Watches---移除
        What ZooKeeper Guarantees about Watches---watch的機制
        Things to Remember about Watches---使用注意的事項
        
    如下也不一一翻譯了,就是各個方面相關的知識唄
    ZooKeeper access control using ACLs
        ACL Permissions
        Builtin ACL Schemes
        ZooKeeper C client API
    Pluggable ZooKeeper authentication
    Consistency Guarantees---特性
    Bindings---客戶端使用方面的
        Java Binding
            Client Configuration Parameters
        C Binding
            Installation
            Building Your Own C Client
    Building Blocks: A Guide to ZooKeeper Operations
        Handling Errors
        Connecting to ZooKeeper
        Read Operations
        Write Operations
        Handling Watches
        Miscelleaneous ZooKeeper Operations
    Program Structure, with Simple Example
    Gotchas: Common Problems and Troubleshooting
複製代碼

③ java example

ZooKeeper Java Example
    A Simple Watch Client
        Requirements
        Program Design
    The Executor Class
    The DataMonitor Class
    Complete Source Listings
複製代碼

在program design中會介紹這個程序所要達成的目的

④ Barrier and Queue Tutorial和Recipes

這裏提到了柵欄和隊列的實現,不過在以前的文章中實現的方式和官網的不一樣

Recipes上面的是一些更爲高級的使用,雙柵欄,權重隊列,共享鎖,對leader選舉的補充等等

⑤ Admin & Ops

這裏涉及到一些運維和管理員的使用文檔,好比怎麼去搭建集羣等,在這裏只貼部分,在以前的文章也有提到

dataLogDir也是經過log4j來進行管理的

JMX:zookeeper默認實現了JMX接口,內容也包括了以前咱們提到的jconsole

Observers Guide:觀察者,其實它的職責就是服務集羣,能夠用來分擔讀請求的負載,還可讓leader選舉的時候更加快速,在集羣數較多的時候,進行leader選舉是一個很是耗時的過程,好比我只讓幾個節點來參與leader選舉,其他的只是做爲觀察者,不參與投票而僅同步數據。

⑥ contributor

開票就提到了咱們說過的原子廣播協議

以後的Miscellaneous模塊就是一些雜七雜八的文檔,維基百科之類的

wiki中有關於zab的介紹,包括paxos算法的介紹也有

⑦ 支持的客戶端

⑧ 一些有用的工具

keptCollections

curator

curator的一種比較優雅的鏈式編程

curator自身實現了leader選舉和分佈式鎖等功能,leader選舉中Curator提供了LeaderSelector監聽器實現Leader選舉功能,同一時刻,只有一個Listener會進入takeLeadership()方法,說明它是當前的Leader。不過若是不清楚這個機制的話代碼走起來講真的其實有點懵。而分佈式鎖呢curator是經過一個InterProcessMutexDemo類來實現的,這裏就不展開了。

finally

到這篇爲止zookeeper的東西就差很少了,也算是填了一個坑吧,代碼從二到六也算是敲的很多,並且基本都是完整地貼出來了,有興趣想跑一下驗證的話直接ctrl+c/v便可。以後應該是按部就班,RPC再到dubbo的一個路線

下一篇:從零開始的高併發(七)--- RPC的介紹,協議及框架

相關文章
相關標籤/搜索