首先先引入官網(wǎng)對Zookeeper介紹:
意思就是說:Zookeeper是一個集中服務损趋,用于維護配置信息卵史,命名舰讹,提供分布式同步和提供組服務娃承。而這類類型的服務被分布式程序使用的時候,不可避免的會發(fā)生錯誤和競爭條件桩匪,zookeeper可以很好的解決這些問題……
其實zookeeper簡單說就是文件系統(tǒng)和通知機制打瘪。
先說文件系統(tǒng)(引入一張圖):
Zookeeper提供的名稱空間很像標準的文件系統(tǒng)(就像win下面的文件夾),名稱是由(/)分割的一系列路徑元素傻昙,在zookeeper中闺骚,每一個目錄節(jié)點都成為一個Znode節(jié)點。但是與標準文件系統(tǒng)不同的是妆档,這些znode還可以保存數(shù)據(jù)僻爽。
Znode節(jié)點還有四種類型:
持久化目錄節(jié)點(PERSISTENT)
持久化順序編號目錄節(jié)點(PERSISTENT_SEQUENTIAL)
臨時目錄節(jié)點(EPHEMERAL)
臨時順序編號目錄節(jié)點(EPHEMERAL_SEQUENTIAL)
這些類型的節(jié)點的意思和名稱一樣,比如(持久化目錄節(jié)點:就是在zookeeper注冊后的znode節(jié)點不會因為客戶端的退出而消失贾惦;而順序編號的意思就是:zookeeper會隨機分配一個數(shù)來進行區(qū)分)以此類推臨時節(jié)點胸梆。
再說一下通知機制:
簡單點就是說,在客戶端監(jiān)聽某一個目錄節(jié)點(比如/servers)须板,每當該節(jié)點增加znode碰镜,更改或者刪除znode,zookeeper就會通知到客戶端习瑰。
=========================================================再來介紹一下zookeeper的總體結構:
Zookeeper服務自身組成一個集群(2n+1個服務允許n個失效)绪颖。
在Zookeeper Service中分為兩種角色:
Leader(領導者):主要負責投票的發(fā)起和決策,更新系統(tǒng)狀態(tài)
Follower(跟隨者):他可以接受客戶端的請求甜奄,并向客戶端響應結果柠横,同時也在選舉leader中參與投票。
其中Zookeeper最核心就是原子廣播(Zab協(xié)議)课兄,他的原子廣播有兩種模式(恢復模式和廣播模式)
恢復模式:當zookeeper集群啟動的時候或者是leader掛了的時候牍氛,會進入這種恢復模式,進行重新選舉第喳,當leader選舉出來就進入了廣播模式糜俗。
廣播模式:這種模式主要是實現(xiàn)zookeeper集群中各個節(jié)點數(shù)據(jù)的同步。
=========================================================那么zookeeper可以做什么呢曲饱?
使用zookeeper可以用作分布式配置管理、集群管理珠月、事務鎖等等扩淀。
這里介紹和實現(xiàn)一個mini版的(客戶端動態(tài)感知服務端的上下線情況)。
(需求)
假設有一組服務端集群啤挎,對外提供功能服務驻谆,如果有一臺服務器節(jié)點因為斷電或其他原因?qū)е孪戮€了卵凑,那么客戶端如何能夠知道是哪一臺服務器下線了,從而不去訪問這臺服務端節(jié)點胜臊,可以通過zookeeper實現(xiàn)勺卢。
(實現(xiàn)方法)
如圖:
- 所有的服務端節(jié)點一上線就去zookeeper的/servers的目錄節(jié)點進行注冊
- 只要有客戶端請求服務端,首先先去zookeeper中查看/servers中有哪些服務器可用象对,并且去監(jiān)聽/servers節(jié)點(每當有服務器上下線就會通知到該客戶端)
需求和實現(xiàn)方法有了黑忱,那么用java進行實現(xiàn)
(使用的zookeeper版本是zookeeper-3.3.6)
首先導入jar包在eclipse中,jar在zookeeper-3.3.6/lib目錄下勒魔,為了防止出錯甫煞,可以把lib下所有的jar進行導入
創(chuàng)建一個類Zk_Server用來模擬上圖的服務端
該類中首先要實現(xiàn):
- 連接zookeeper
- 在/servers中進行注冊
- 執(zhí)行他的業(yè)務邏輯
再創(chuàng)建一個Zk_Cli的類用于模擬上圖的客戶端
該類要實現(xiàn):
- 連接zookeeper
- 獲取/servers目錄節(jié)點下的子目錄,并監(jiān)聽/servers目錄節(jié)點冠绢。具體代碼實現(xiàn)如下:
public class Zk_server {
private static ZooKeeper zk;
public void getConnect() throws Exception {
//連接zookeeper的ip和端口號 session超時時間 監(jiān)聽時間的回調(diào)函數(shù)
zk = new ZooKeeper("127.0.0.1:2181", 2000, null);
}
public void get_res() throws Exception {
//path創(chuàng)建一個臨時的順序節(jié)點
zk.create("/servers/server", "server".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
Thread.*sleep*(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
Zk_server zk_server = new Zk_server();
//獲取zk連接
zk_server.getConnect();
//在zk上注冊服務端 創(chuàng)建臨時順序節(jié)點
zk_server.get_res();
}
}
=========================================================
public class zk_cli {
private static ZooKeeper zk;
Watcher wa = **new** Watcher() {
@Override
public void process(WatchedEvent event) {
// 監(jiān)聽事件 查看子節(jié)點的變化
try {
getData();
} catch (Exception e) {
e.printStackTrace();
}
}
};
public void getConnect() throws Exception {
zk = new ZooKeeper("127.0.0.1:2181", 2000, wa);
}
//監(jiān)聽/servers,并查看該節(jié)點的子目錄文件
public void getData() throws Exception {
// 查詢該節(jié)點下的子節(jié)點 并監(jiān)聽/servers
List<String> list = *zk*.getChildren("/servers", **true**);
System.out.println("現(xiàn)有的子節(jié)點為" + list);
}
public static void main(String[] args) throws Exception {
zk_cli zk_cli = new zk_cli();
// 獲取zk連接
zk_cli.getConnect();
//查看/servers的子節(jié)點
zk_cli.getData();
Thread.*sleep*(Long.***MAX_VALUE***);
}
}
========================================================運行截圖:
只要/servers的子節(jié)點有增加刪除節(jié)點的操作抚吠,zk_cli就可以獲取到,從而實現(xiàn)客戶端動態(tài)感知服務端的上下線的功能弟胀。