一、ZooKeeper概述
ZooKeeper是一種爲分佈式應用所設計的高可用、高性能且一致的開源協調服務,是Google的Chubby一個開源實現,是Hadoop和Hbase的重要組件,它提供了一項基本服務:分佈式鎖服務。由於ZooKeeper的開源特性,後來我們的開發者在分佈式鎖的基礎上,摸索了出了其他的使用方法:配置維護、組服務、分佈式消息隊列、分佈式通知/協調等。
zookeeper是基於內存同步數據的,所以集羣內的節點其內存中的數據結構是完全相同的,因此效率非常高。
ZooKeeper具備的幾個特點決定了它能夠用在大型的、分佈式的系統當中:
順序一致性
從同一個客戶端發起的事務請求,最終將會嚴格按照其發起順序被應用到zookeeper中
原子性
所有事物請求的處理結果在整個集羣中所有機器上的應用情況是一致的,即,要麼整個集羣中所有機器都成功應用了某一事務,要麼都沒有應用,一定不會出現集羣中部分機器應用了改事務,另外一部分沒有應用的情況。
單一視圖
無論客戶端連接的是哪個zookeeper服務器,其看到的服務端數據模型都是一致的。
可靠性
一旦服務端成功的應用了一個事務,並完成對客戶端的響應,那麼該事務所引起的服務端狀態變更將會一直保留下來,除非有另一個事務又對其進行了改變。
實時性
zookeeper並不是一種強一致性,只能保證順序一致性和最終一致性,只能稱爲達到了僞實時性。
二、zookeeper 數據模型
ZooKeeper擁有一個層次的命名空間,這個和標準的文件系統非常相似,如圖:
ZooKeeper採用樹形層次結構,樹中的每個節點被稱爲—Znode,Znode也可以擁有子節點。
引用方式:
Zonde通過路徑引用,如同Unix中的文件路徑。必須是絕對路徑,因此他們必須由斜槓字符來開頭。除此以外,他們必須是唯一的,也就是說每一個路徑只有一個表示,因此這些路徑不能改變。在ZooKeeper中,路徑由Unicode字符串組成,並且有一些限制。字符串"/zookeeper"用以保存管理信息,比如關鍵配額信息。
Znode 結構
ZooKeeper命名空間中的Znode,兼具文件和目錄兩種特點。既像文件一樣維護着數據、元信息、ACL、時間戳等數據結構,又像目錄一樣可以作爲路徑標識的一部分。每個Znode由3部分組成 :
1、stat:此爲狀態信息, 描述該Znode的版本, 權限等信息
2、data:與該Znode關聯的數據
3、children:該Znode下的子節點
ZooKeeper雖然可以關聯一些數據,但並沒有被設計爲常規的數據庫或者大數據存儲,相反的是,它用來管理調度數據,比如分佈式應用中的配置文件信息、狀態信息、彙集位置等等。這些數據的共同特性就是它們都是很小的數據,通常以KB爲大小單位。ZooKeeper的服務器和客戶端都被設計爲嚴格檢查並限制每個Znode的數據大小至多1M,但常規使用中應該遠小於此值。
三、節點類型
ZooKeeper中的節點有兩種,分別爲臨時節點和永久節點。節點的類型在創建時即被確定,並且不能改變。
臨時節點:該節點的生命週期依賴於創建它們的會話。一旦會話(Session)結束,臨時節點將被自動刪除,當然可以也可以手動刪除。雖然每個臨時的Znode都會綁定到一個客戶端會話,但他們對所有的客戶端還是可見的。另外,ZooKeeper的臨時節點不允許擁有子節點。
永久節點:該節點的生命週期不依賴於會話,並且只有在客戶端顯示執行刪除操作的時候,他們才能被刪除。
順序節點
當創建Znode的時候,用戶可以請求在ZooKeeper的路徑結尾添加一個遞增的計數。這個計數對於此節點的父節點來說是唯一的,它的格式爲"%10d"(10位數字,沒有數值的數位用0補充,例如"0000000001")。當計數值大於232-1時,計數器將溢出。
監視器
客戶端可以在節點上設置watch,我們稱之爲監視器。當節點狀態發生改變時(Znode的增、刪、改)將會觸發watch所對應的操作。當watch被觸發時,ZooKeeper將會向客戶端發送且僅發送一條通知,因爲watch只能被觸發一次,這樣可以減少網絡流量。
ZooKeeper有多種記錄時間的形式,其中包含以下幾個主要屬性:
(1) Zxid
致使ZooKeeper節點狀態改變的每一個操作都將使節點接收到一個Zxid格式的時間戳,並且這個時間戳全局有序。也就是說,也就是說,每個對節點的改變都將產生一個唯一的Zxid。如果Zxid1的值小於Zxid2的值,那麼Zxid1所對應的事件發生在Zxid2所對應的事件之前。實際上,ZooKeeper的每個節點維護者三個Zxid值,爲別爲:cZxid、mZxid、pZxid。
1、cZxid: 是節點的創建時間所對應的Zxid格式時間戳。
2、mZxid:是節點的修改時間所對應的Zxid格式時間戳。
實現中Zxid是一個64爲的數字,它高32位是epoch用來標識leader關係是否改變,每次一個leader被選出來,它都會有一個 新的epoch。低32位是個遞增計數。
(2) 版本號
對節點的每一個操作都將致使這個節點的版本號增加。每個節點維護着三個版本號,他們分別爲:
1、version:節點數據版本號
2、cversion:子節點版本號
3、aversion:節點所擁有的ACL版本號
ZooKeeper節點屬性:
四、ZooKeeper 安裝配置
ZooKeeper的工作模式有三種:單機模式、集羣模式、僞集羣模式。
單機模式:Zookeeper只運行在一臺服務器上,適合測試環境;
僞集羣模式:就是在一臺物理機上運行多個Zookeeper 實例;
集羣模式:Zookeeper運行於一個至少有三個節點以上集羣中,適合生產環境;
Zookeeper通過複製來實現高可用性,只要集羣中半數以上的節點處於可用狀態,它就能夠保證服務繼續。爲什麼一定要超過半數呢?這跟Zookeeper的複製策略有關:zookeeper確保對znode 樹的每一個修改都會被複制到集羣中超過半數的節點上。
服務器角色有兩種:
1、leader -主節點
2、follower -從節點
在一個集羣中通常只有一個leader和多個follower,當leader下線時,follower能根據選舉策略,選舉一個新的leader保證集羣的正常工作。
下面我們來構建一個單機模式的ZooKeeper節點:
可以去Apache的鏡像站點下載zookeeper: http://www.apache.org/dyn/closer.cgi/zookeeper/
安裝ZooKeeper之前首先需要安裝JDK,在oracle官網可以下載到。(建議下載rpm包安裝)
1、解壓zookeeper
tar xf zookeeper-3.4.9.tar.gz cd zookeeper-3.4.9
2、創建配置文件
# conf/zoo.cfg tickTime=2000 dataDir=/tmp/zookeeper clientPort=2181
3、啓動服務
bin/zkServer.sh start
ZooKeeper僞集羣模式
ZooKeeper提供了僞集羣模式,也就是可以在同一臺機器上啓動多個zookeeper服務,當手頭機器不足時,又需要做實驗,提供了很大的便利。
注: 在同一臺機器上部署3個zookeeper server時,需要爲每個server創建獨立的配置文件,並且保證每個配置文件中的端口不能衝突,除了clientPort不同之外,另外,還要在dataDir所對應的目錄中創建myid文件來指定對應的zookeeper server 實例。
需要注意的幾個配置項:
clientPort端口:如果在1臺機器上部署多個server,那麼每臺機器都要不同的 clientPort,比如 server1是2181,server2是2182,server3是2183
dataDir和dataLogDir:dataDir和dataLogDir也需要區分下,將數據文件和日誌文件分開存放,同時每個server的這兩變量所對應的路徑都是不同的
server.X和myid: server.X 這個數字就是對應,data/myid中的數字。在3個server的myid文件中分別寫入了0,1,2,那麼每個server中的zoo.cfg都配 server.0 server.2,server.3就行了。因爲在同一臺機器上,後面連着的2個端口,3個server都不要一樣,否則端口衝突
啓動命令
# 這時使用單機模式的啓動命令是不行的,需要在指令後面跟上不同實例的配置文件名稱。如下: bin/zkServer.sh start zoo1.cfg bin/zkServer.sh start zoo2.cfg bin/zkServer.sh start zoo3.cfg
五、集羣實戰 — 構建一個3節點的 ZooKeeper 集羣
實驗環境:
服務器IP | myid |
192.168.1.21 | 11 |
192.168.1.22 | 12 |
192.168.1.23 | 13 |
注:
(1) zk服務器集羣規模不得小於3個節點
(2) 要求各服務器之間系統時間要保持一致。
爲了實現高可用的ZooKeeper服務,應該把zk部署在一個集羣中,每臺機器只跑一個zk實例。配置方式和前面差不多,只是每臺機器上的配置文件 conf/zoo.cfg 完全相同。
創建myid
# 爲每臺機器創建myid文件 # 192.168.1.21 echo 11 >/u01/zookeeper/zookeeper-3.4.9/data/myid # 192.168.1.22 echo 12 >/u01/zookeeper/zookeeper-3.4.9/data/myid # 192.168.1.23 echo 13 >/u01/zookeeper/zookeeper-3.4.9/data/myid
創建配置文件
可以複製 zoo_sample.cfg 到 zoo.cfg 以下爲配置文件的參數設置:
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/u01/zookeeper/zookeeper-3.4.9/data # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 server.11=192.168.1.21:2888:3888 server.12=192.168.1.22:2888:3888 server.13=192.168.1.23:2888:3888
改好配置文件後,同步到集羣內的所有節點。
常用配置參數解析:
dataLogdDir=/path1 # 指定事務日誌的存儲路徑,可以和dataDir在不同設備,這意味着可以使用一個日誌的專用磁盤,避免日誌IO和快照競爭。 dataDir=/path2 # 運行數據的存放路徑 tickTime=2000 # 這個時間是作爲Zookeeper服務器之間或客戶端與服務器之間維持心跳的時間間隔,每隔tickTime時間就會發送一個心跳;最小 的session過期時間爲2倍tickTime maxClientCnxns=0 # 最大的併發連接數限制,設置爲0或者不設置該參數,表示不進行連接數的限制。 minSessionTimeout # 最小的會話超時時間,默認值 minSession=2*tickTime maxSessionTimeout # 最大的會話超時時間,默認值 maxSession=20*tickTime initLimit=10 # 此配置表示,允許follower(相對於Leaderer言的“客戶端”)連接並同步到Leader的初始化連接時間,以tickTime爲單位。當初始化連接時間超過該值,則表示連接失敗。 syncLimit=5 # 此配置項表示Leader與Follower之間發送消息時,請求和應答時間長度。如果follower在設置時間內不能與leader通信,那麼此follower將會被丟棄。 # 集羣模式最關鍵的配置參數 server.11=192.168.1.21:2888:3888 # server.myid=ip:leader_port:inner_port # myid 爲服務器編號,用於標識服務器,這個值必須和dataDir目錄下myid文件中的值保證一致 # ip 爲當前服務器IP, # leader_port Leader的端口 # inner_port zk服務器之間內部通信端口 # 同一個集羣內的服務器,需要把該集羣內的服務器列表信息都寫在配置文件中。
啓動服務 & 查看節點的角色分配情況
# 192.168.1.21 bin/zkServer.sh start bin/zkServer.sh status # ZooKeeper JMX enabled by default # Using config: /u01/zookeeper/zookeeper-3.4.9/bin/../conf/zoo.cfg # Mode: leader # 192.168.1.22 bin/zkServer.sh start bin/zkServer.sh status # ZooKeeper JMX enabled by default # Using config: /u01/zookeeper/zookeeper-3.4.9/bin/../conf/zoo.cfg # Mode: follower # 192.168.1.23 bin/zkServer.sh start bin/zkServer.sh status # ZooKeeper JMX enabled by default # Using config: /u01/zookeeper/zookeeper-3.4.9/bin/../conf/zoo.cfg # Mode: follower
由此可見,集羣已經正常運行;
六、ZooKeeper的四字命令
客戶端可以通過nc或telnet連接ZooKeeper Server提交指令
簡單用例:
# 檢查服務器狀態是否正常 echo ruok | nc localhost 2181 imok # 輸出服務器配置信息 echo conf | nc localhost 2181 clientPort=2181 dataDir=/u01/zookeeper/zookeeper-3.4.9/data/version-2 dataLogDir=/u01/zookeeper/zookeeper-3.4.9/data/version-2 tickTime=2000 maxClientCnxns=60 minSessionTimeout=4000 maxSessionTimeout=40000 serverId=11 initLimit=10 syncLimit=5 electionAlg=3 electionPort=3888 quorumPort=2888 peerType=0 # 輸出服務器狀態信息 echo stat | nc localhost 2181 Zookeeper version: 3.4.9-1757313, built on 08/23/2016 06:50 GMT Clients: /127.0.0.1:60822[0](queued=0,recved=1,sent=0) Latency min/avg/max: 0/1/1591 Received: 200338 Sent: 200389 Connections: 1 Outstanding: 0 Zxid: 0x200498db5 Mode: follower Node count: 166
七、ZooKeeper Client 簡單操作
9個基本操作指令:
簡單用例:
# 連接 ZooKeeper 服務器 bin/zkCli.sh -server localhost:2181 # 查看根下有哪些節點 [zk: localhost:2181(CONNECTED) 1] ls / [controller_epoch, controller, brokers, zookeeper, admin, isr_change_notification, consumers, config] # 查看 brokers 下有哪些子節點 [zk: localhost:2181(CONNECTED) 4] ls /brokers [ids, topics, seqid] # 在根下創建一個 "tuchao" 節點,並設置數據爲 "hello zookeeper" [zk: localhost:2181(CONNECTED) 5] create /tuchao "hello zookeeper" # 查看是否創建成功 [zk: localhost:2181(CONNECTED) 6] ls / [controller_epoch, controller, brokers, zookeeper, tuchao, admin, isr_change_notification, consumers, config] # 查看 /tuchao 中的數據 [zk: localhost:2181(CONNECTED) 7] get /tuchao hello zookeeper cZxid = 0x20049ab24 ctime = Sun Oct 09 15:45:02 CST 2016 mZxid = 0x20049ab24 mtime = Sun Oct 09 15:45:02 CST 2016 pZxid = 0x20049ab24 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 15 numChildren = 0 # 可以看到剛剛設置的數據。 # 修改 /tuchao 中的數據爲 "Happy birthday" [zk: localhost:2181(CONNECTED) 8] set /tuchao "Happy birthday" cZxid = 0x20049ab24 ctime = Sun Oct 09 15:45:02 CST 2016 mZxid = 0x20049b2cc mtime = Sun Oct 09 15:51:17 CST 2016 pZxid = 0x20049ab24 cversion = 0 dataVersion = 1 # 可以發現,當數據變更時,數據版本號增加了。 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 14 numChildren = 0 # 再查看一次 /tuchao 中的數據 [zk: localhost:2181(CONNECTED) 9] get /tuchao Happy birthday cZxid = 0x20049ab24 ctime = Sun Oct 09 15:45:02 CST 2016 mZxid = 0x20049b2cc mtime = Sun Oct 09 15:51:17 CST 2016 pZxid = 0x20049ab24 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 14 numChildren = 0 # 給 /tuchao 創建一個子節點 /tuchao/abc1 [zk: localhost:2181(CONNECTED) 10] create /tuchao/abc1 "abc1 node" Created /tuchao/abc1 [zk: localhost:2181(CONNECTED) 11] ls /tuchao [abc1] # 刪除節點 /tuchao/abc1 [zk: localhost:2181(CONNECTED) 0] delete /tuchao/abc1 [zk: localhost:2181(CONNECTED) 1] ls /tuchao [] # 查看命令幫助,輸入 h [zk: localhost:2181(CONNECTED) 2] h ZooKeeper -server host:port cmd args stat path [watch] set path data [version] ls path [watch] delquota [-n|-b] path ls2 path [watch] setAcl path acl setquota -n|-b val path history redo cmdno printwatches on|off delete path [version] sync path listquota path rmr path get path [watch] create [-s] [-e] path data acl addauth scheme auth quit getAcl path close connect host:port
參考文獻:http://www.cnblogs.com/sunddenly/p/4033574.html