Apache ZooKeeper是一個開源的分佈式服務框架,爲分佈式應用提供協調服務,用來解決分佈式應用中的數據管理問題,如:配置管理、域名服務、分佈式同步、集羣管理等
官網 https://zookeeper.apache.org/
ZooKeeper視頻教程 http://edu.51cto.com/course/16190.htmlhtml
主要包括兩部分:文件系統、通知機制java
ZooKeeper維護一個相似Linux文件系統的數據結構,用於存儲數據node
節點類型有四種:算法
持久化目錄節點 persistent數據庫
客戶端與服務器斷開鏈接,該節點仍然存在apache
持久化順序編號目錄節點 persistent_sequential數組
客戶端與服務器斷開鏈接,該節點仍然存在,此時節點會被順序編號,如:00000一、000002.....bash
臨時目錄節點 ephemeral服務器
客戶端與服務器斷開鏈接,該節點會被刪除session
臨時順序編號目錄節點 ephemeral_sequential
客戶端與服務器斷開鏈接,該節點會被刪除,此時節點會被順序編號,如:00000一、000002.....
ZooKeeper是一個基於觀察者模式設計的分佈式服務管理框架
簡單來講,客戶端註冊監聽它關心的目錄節點,當目錄節點發生變化時,ZooKeeper會通知客戶端
ZooKeeper是一個訂閱中心(註冊中心)
場景:集羣環境、服務器的許多配置都是相同的,如:數據庫鏈接信息,當須要修改這些配置時必須同時修改每臺服務器,很麻煩
解決:把這些配置所有放到ZooKeeper上,保存在ZooKeeper的某個目錄節點中,而後全部的應用程序(客戶端)對這個目錄節點進行監視Watch,一旦配置信息發生變化,ZooKeeper會通知每一個客戶端,而後從ZooKeeper獲取新的配置信息,並應用到系統中。
場景:集羣環境下,如何知道有多少臺機器在工做?是否有機器退出或加入?須要選舉一個總管master,讓總管來管理集羣
解決:在父目錄GroupMembers下爲全部機器建立臨時目錄節點,而後監聽父目錄節點的子節點變化,一旦有機器掛掉,該機器與ZooKeeper的鏈接斷開,其所建立的臨時目錄節點被刪除,全部其餘機器都會收到通知。當有新機器加入時也是一樣的道理。
選舉master:爲全部機器建立臨時順序編號目錄節點,給每臺機器編號,而後每次選取編號最小的機器做爲master
ZooKeeper自己是不提供負載均衡策略的,須要本身實現,因此準確的說,是在負載均衡中使用ZooKeeper來作集羣的協調(也稱爲軟負載均衡)
實現思路:
實際上利用了ZooKeeper的特性,將ZooKeeper用爲服務的註冊和變動通知中心
ZooKeeper通常都運行在Linux平臺
步驟:
解壓zookeeper-3.4.13.tar.gz
cd ~/software tar -zxf zookeeper-3.4.13.tar.gz
配置
# 建立存放數據文件的目錄 cd zookeeper-3.4.13/ mkdir data # 建立配置文件 cd conf cp zoo_sample.cfg zoo.cfg # 默認使用的是zoo.cfg,名稱固定 # 修改配置文件 vi zoo.cfg dataDir=../data # 指定數據存放目錄
啓動zookeeper
cd bin ./zkServer.sh start | stop | status | restart # 啓動|中止|查看狀態|重啓
客戶端鏈接zookeeper
./zkCli.sh # 啓動客戶端,默認鏈接本機的2181端口 或 ./zkCli.sh -server 服務器地址:端口 # 鏈接指定主機、指定端口的zookeeper quit # 退出客戶端
配置項 | 含義 | 說明 |
---|---|---|
tickTime=2000 | 心跳時間 | 維持心跳的時間間隔,單位是毫秒<br>在zookeeper中全部的時間都是以這個時間爲基礎單元,進行整數倍配置 |
initLimit=10 | 初始通訊時限 | 用於zookeeper集羣,此時有多臺zookeeper服務器,其中一個爲Leader,其餘都爲Follower |
syncLimit=5 | 同步通訊時限 | 在運行時Leader經過心跳檢測與Follower進行通訊,若是超過syncLimit*tickTime時間還未收到響應,則認爲該Follower已經宕機 |
dataDir=../data | 存儲數據的目錄 | 數據文件也稱爲snapshot快照文件 |
clientPort=2181 | 端口號 | 默認爲2181 |
maxClientCnxns=60 | 單個客戶端的最大鏈接數限制 | 默認爲60,能夠設置爲0,表示沒有限制 |
autopurge.snapRetainCount=3 | 保留文件的數量 | 默認3個 |
autopurge.purgeInterval=1 | 自動清理快照文件和事務日誌的頻率 | 默認爲0,表示不開啓自動清理,單位是小時 |
dataLogDir= | 存儲日誌的目錄 | 未指定時日誌文件也存放在dataDir中,爲了性能最大化,通常建議把dataDir和dataLogDir分別放到不一樣的磁盤上 |
命令 | 做用 | 說明 |
---|---|---|
help | 查看幫助 | 查看全部操做命令 |
ls 節點路徑 | 查看指定節點下的內容 | |
ls2 節點路徑 | 查看指定節點的詳細信息 | 查看全部子節點和當前節點的狀態 |
create 節點路徑 內容 | 建立普通節點 | 若是內容中有空格,則須要使用對雙引號引發來 |
get 節點路徑 | 獲取節點中的值 | |
create -e 節點路徑 內容 | 建立臨時節點 | 當鏈接斷開後,節點會被自動刪除 |
create -s 節點路徑 內容 | 建立順序編號節點 | 即帶序號的節點 |
delete 節點路徑 | 刪除節點 | 只能刪除空節點,即不能有子節點 |
rmr 節點路徑 | 遞歸刪除節點 | remove recursion |
stat 節點路徑 | 查看節點狀態 | |
set 節點路徑 新值 | 修改節點內容 |
查看指定節點的詳細信息: ls2 /
# 子節點名稱數組 [zookeeper] # -----------節點的狀態信息,也稱爲stat結構體------------------- # 建立該znode的事務的zxid(ZooKeeper Transaction ID) # 事務ID是ZooKeeper爲每次更新操做/事務操做分配一個全局惟一的id,表示zxid,值越小,表示越先執行 cZxid = 0x0 # 0x0表示十六進制數0 # 建立時間 ctime = Thu Jan 01 08:00:00 CST 1970 # 最後一次更新的zxid mZxid = 0x0 # 最後一次更新的時間 mtime = Thu Jan 01 08:00:00 CST 1970 # 最後更新的子節點的zxid pZxid = 0x0 # 子節點的變化號,表示子節點被修改的次數,-1表示從未被修改過 cversion = -1 # 當前節點的變化號,0表示從未被修改過 dataVersion = 0 # 訪問控制列表的變化號 access control list aclVersion = 0 # 若是臨時節點,表示當前節點的擁有者的sessionId # 若是不是臨時節點,則值爲0 ephemeralOwner = 0x0 # 數據長度 dataLength = 0 # 子節點數據 numChildren = 1
順序編號節點:
步驟:
準備多臺ZooKeeper服務器
配置ZooKeeper服務器
在每臺服務器的conf/zoo.cfg文件中添加以下內容:
server.20=192.168.4.20:2888:3888 server.21=192.168.4.21:2888:3888 server.22=192.168.4.22:2888:3888
格式:server.A=B:C:D
建立myid配置文件
在集羣環境下,須要在dataDir
目錄中建立一個名爲myid
的文件,文件內容是當前服務器的編號ID,即上面配置的A
cd data echo A的值 > myid
ZooKeeper啓動時會讀取這個文件,將裏面的數字與zoo.cfg中配置的server.A進行比較,從而判斷這臺服務器是哪一個
測試集羣環境
啓動全部ZooKeeper服務器,查看狀態
此時在某臺服務器上執行更新操做時,其餘服務器也會同步
ZooKeeper在提供服務時會自動選舉一個節點服務器做爲Leader,其餘都是Follower
選舉流程:
總結:
集羣數/2+1
個服務器中,id值最大的會成爲Leader# 在集羣的A服務器,監聽某個節點值的變化 get /yyy watch # 在集羣的B服務器,修改對應節點的值 set /yyy myyyy # 此時A服務器會收到事件NodeDataChanged WATCHER:: WatchedEvent state:SyncConnected type:NodeDataChanged path:/yyy
監聽Watch事件是一個一次性的觸發器,當數據改變時只會觸發一次,若是之後這個數據再發生改變,則不會再次觸發
# 在集羣的A服務器,監聽某個節點的子節點的變化 ls /yyy watch # 在集羣的B服務器,建立/修改/刪除對應節點的子節點 create /yyy/hello hello # 此時A服務器會收到事件NodeChildrenChanged WATCHER:: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/yyy
Java操做Zookeeper很簡單,只須要添加ZooKeeper客戶端的依賴便可,能夠進行節點信息的獲取、管理等。
步驟:
添加jar包
<!--ZooKeeper客戶端--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.13</version> </dependency>
操做
public static void main(String[] args) throws IOException, KeeperException, InterruptedException { //獲取ZooKeeper的鏈接,即建立ZooKeeper的客戶端 String connectString = "127.0.0.1:2181"; //服務器地址 int sessionTimeout = 3000; //超時時間,單位爲毫秒 Watcher watcher = new MyWatcher(); ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, watcher); Thread.sleep(2000); System.out.println(zkClient.getState()); /** * 操做ZooKeeper */ //查看指定節點下的內容 List<String> children = zkClient.getChildren("/", true);//第二個參數表示是否監視該節點 System.out.println(children); //建立節點,OPEN_ACL_UNSAFE表示acl權限列表爲徹底開放,PERSISTENT表示節點類型爲持久化節點 zkClient.create("/world", "世界".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //獲取節點的數據(節點的值和節點狀態Stat) byte[] data = zkClient.getData("/world", true, null); System.out.println(new String(data)); Stat stat = new Stat(); byte[] data = zkClient.getData("/hello", true, stat); byte[] data = zkClient.getData("/hello", new DataWatcher(), stat); System.out.println(new String(data)); System.out.println(stat); System.out.println(stat.getCtime()); System.out.println(stat.getVersion()); System.out.println(stat.getDataLength()); //修改節點的數據 // zkClient.setData("/hello","aaa".getBytes(),stat.getVersion()); //第三個參數表示當前節點的數據版本,通常先獲取數據stat,而後指定數據版本 zkClient.setData("/hello", "bbb".getBytes(), -1); //也能夠設置爲-1,表示不檢測版本 //刪除節點 zkClient.delete("/hello", -1); //判斷節點是否存在 System.out.println(zkClient.exists("/hello",false)); //存在時返回節點狀態,不存在則返回null //休眠 Thread.sleep(1000000); //關閉鏈接 zkClient.close(); }
ZooKeeper快速入門視頻,連接:http://edu.51cto.com/course/16190.html