距離上一篇的更新也是好一段日子了,期間也是有小夥伴催更但是由於一些雜事一直沒處理好,接下來會恢復周更java
有小夥伴的反饋中說到標題都是經典應用,太過籠統因此無法經過標題得知對應內容的問題,在此也是進行了改進node
第四篇:Zookeeper的經典應用場景---標題修改成---Zookeeper的分佈式隊列
第五篇:Zookeeper的經典應用場景2---標題修改成---Zookeeper的配置中心應用
複製代碼
從零開始的高併發(一)--- Zookeeper的基礎概念算法
從零開始的高併發(二)--- Zookeeper實現分佈式鎖編程
從零開始的高併發(三)--- Zookeeper集羣的搭建和leader選舉緩存
從零開始的高併發(四)--- Zookeeper的分佈式隊列session
從零開始的高併發(五)--- Zookeeper的配置中心應用架構
在分佈式架構中常常採用的結構就是一主多從,主節點祈使句就是負責協調管理集羣用的。咱們能夠借用這個場景去展開。併發
爲何咱們要採用臨時節點,覺得考慮到master節點可能負載較高,掛掉了,這時咱們要保證其餘下面的servers服務都可以獲得通知,框架
其實咱們也能夠經過最小節點方式來實現,就誰排在前面,誰就有權利去得到master運維
首先咱們須要有一個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了而已
在本身仍是0基礎的時候,如何來經過官網去學習,雖然如今網上關於各大框架的知識確實已經不少了,但是咱們仍是有必要去瀏覽這些開源框架的官網,由於不管網上的說法再良莠不齊衆說紛紜,但官網是表明着絕對權威的
並且官網所提到的知識通常也是基礎的應用,不會說涉及不少複雜的業務場景,從官網上去了解一個新的框架是最好的,也不會存在帶有誤導性的demo和總結,在大體瞭解以後,想看看具體的業務中使用,則可使用百度,去看看別人寫的一些應用,就沒有問題。
若是官網都會出錯,那就只能本身看源碼了,過程則會很是痛苦(攤手)
基本會按照以前寫的章節的內容去大體說明,就是之前章節提到的內容在官網中哪裏能夠找到
這是zookeeper官網的目錄結構,整個zookeeper的骨架都會列出來
這裏其實就是介紹了每一個欄目分別都存在了什麼東西,上面的圖其實也大體翻譯了這些內容
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
複製代碼
ZooKeeper Java Example
A Simple Watch Client
Requirements
Program Design
The Executor Class
The DataMonitor Class
Complete Source Listings
複製代碼
在program design中會介紹這個程序所要達成的目的
這裏提到了柵欄和隊列的實現,不過在以前的文章中實現的方式和官網的不一樣
Recipes上面的是一些更爲高級的使用,雙柵欄,權重隊列,共享鎖,對leader選舉的補充等等
這裏涉及到一些運維和管理員的使用文檔,好比怎麼去搭建集羣等,在這裏只貼部分,在以前的文章也有提到
dataLogDir也是經過log4j來進行管理的
JMX:zookeeper默認實現了JMX接口,內容也包括了以前咱們提到的jconsole
Observers Guide:觀察者,其實它的職責就是服務集羣,能夠用來分擔讀請求的負載,還可讓leader選舉的時候更加快速,在集羣數較多的時候,進行leader選舉是一個很是耗時的過程,好比我只讓幾個節點來參與leader選舉,其他的只是做爲觀察者,不參與投票而僅同步數據。
開票就提到了咱們說過的原子廣播協議
wiki中有關於zab的介紹,包括paxos算法的介紹也有
curator的一種比較優雅的鏈式編程
curator自身實現了leader選舉和分佈式鎖等功能,leader選舉中Curator提供了LeaderSelector監聽器實現Leader選舉功能,同一時刻,只有一個Listener會進入takeLeadership()方法,說明它是當前的Leader。不過若是不清楚這個機制的話代碼走起來講真的其實有點懵。而分佈式鎖呢curator是經過一個InterProcessMutexDemo類來實現的,這裏就不展開了。
到這篇爲止zookeeper的東西就差很少了,也算是填了一個坑吧,代碼從二到六也算是敲的很多,並且基本都是完整地貼出來了,有興趣想跑一下驗證的話直接ctrl+c/v便可。以後應該是按部就班,RPC再到dubbo的一個路線
下一篇:從零開始的高併發(七)--- RPC的介紹,協議及框架