一。zookeeper簡介
- zookeeper 是apache旗下的hadoop子項目,它一個開源的,分布式的服務協調器。同樣通過zookeeper可以實現服務間的同步與配置維護。通常情況下,在分布式應用開發中,協調服務這樣的工作不是件容易的事,很容易出現死鎖,不恰當的選舉競爭等。zookeeper就是擔負起了分布式協調的重擔。
- zookeeper的特點:
- 使用簡單:ZooKeeper允許分布式程序通過一個類似於標准文件系統的共享的層次化名稱空間來相互協調。名稱空間由數據寄存器(稱為znode)組成,在ZooKeeper中,它們類似於文件和目錄。與為存儲而設計的典型文件系統不同,ZooKeeper數據保存在內存中,這意味着ZooKeeper可以達到高吞吐量和低延遲數
- 同步與復制:組成ZooKeeper服務的服務器必須互相有感知。客戶端連接到一個ZooKeeper服務器。客戶端維護一個TCP連接,通過它發送請求、獲取響應、獲取觀察事件和發送心跳。如果連接到服務器的TCP連接中斷,客戶端將連接到另一個服務器。
- 有序
- 在進行大量讀操作時,運行速度奇快
- ZooKeeper提供的名稱空間非常類似於標准文件系統。名稱是由斜杠(/)分隔的路徑元素序列。在ZooKeeper的名稱空間中,每一個節點都是通過一條路徑來標識的。如圖所示 :

- 當然zookeeper與標准文件系統不同的是,它的節點分為永久節點和臨時節點(隨着會話斷開而消失)
- 客戶端的節點都會被設置一個監控,當znode發生更改時,這個變化會通知所有客戶端然后刪除
二。zookeeper快速上手
- 下載zookeeper:地址,並解壓,然后得到如下目錄:

- 進入conf目錄下我們復制一份zoo_sample.cfg並改名為zoo.cfg
cp zoo_sample.cfg zoo.cfg運行 vi zoo.cfg 我們先來看看配置
View Code# 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=../zookeeper-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 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
在這里我們保持默認配置先不變。更改一下dataDir這個值,注意:先在zookeeper的根目錄下把該文件夾建好
- 進入bin目錄下啟動zookeeper。注意:再此之前必須配置JAVA_HOME的環境變量
./zkServer.sh start - 緊接着在bin目錄下運行客戶端
./zkCli.sh -server 127.0.0.1:2181
運行過后會得到如下提示界面:
Connecting to localhost:2181 log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper). log4j:WARN Please initialize the log4j system properly. Welcome to ZooKeeper! JLine support is enabled [zkshell: 0]
緊接着我們運行help命令可以看看當前可以運行哪些指令:
[zkshell: 0] help
ZooKeeper host:port cmd args
get path [watch]
ls path [watch]
set path data [version]
delquota [-n|-b] path
quit
printwatches on|off
create path data acl
stat path [watch]
listquota path
history
setAcl path acl
getAcl path
sync path
redo cmdno
addauth scheme auth
delete path [version]
setquota -n|-b val path
其中 get:為獲取節點數據 , ls查看當前節點的子節點 create:創建節點 delete:刪除節點 set設置節點的內容數據
下面我們依次運行如下命令看看:
-
[zkshell: 8] ls / [zookeeper]
[zkshell: 9] create /zk_test my_data Created /zk_test
[zkshell: 11] ls / [zookeeper, zk_test]
[zkshell: 12] get /zk_test my_data cZxid = 5 ctime = Fri Jun 05 13:57:06 PDT 2009 mZxid = 5 mtime = Fri Jun 05 13:57:06 PDT 2009 pZxid = 5 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0 dataLength = 7 numChildren = 0
[zkshell: 14] set /zk_test junk cZxid = 5 ctime = Fri Jun 05 13:57:06 PDT 2009 mZxid = 6 mtime = Fri Jun 05 14:01:52 PDT 2009 pZxid = 5 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0 dataLength = 4 numChildren = 0 [zkshell: 15] get /zk_test junk cZxid = 5 ctime = Fri Jun 05 13:57:06 PDT 2009 mZxid = 6 mtime = Fri Jun 05 14:01:52 PDT 2009 pZxid = 5 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0 dataLength = 4 numChildren = 0
[zkshell: 16] delete /zk_test [zkshell: 17] ls / [zookeeper] [zkshell: 18]
三。使用java操作zookeeper
通常情況下我們可以使用zookeeper提供的原生jar包操作zookeeper服務,但是zookeeper原生方式操作很麻煩,不過我們可以用第三方的組件來操作zookeeper,比如說:zkClient 或者curator。curator提供了更豐富的功能,但是使用起來比zkClient稍微復雜一點。關於curator我們后續篇幅會介紹,這里先貼出zkClient的例子:
添加zkClient的依賴:
// https://mvnrepository.com/artifact/com.101tec/zkclient compile group: 'com.101tec', name: 'zkclient', version: '0.10'
示例代碼:
package com.bdqn.lyrk.register; import org.I0Itec.zkclient.IZkDataListener; import org.I0Itec.zkclient.ZkClient; import org.apache.zookeeper.CreateMode; import java.io.IOException; public class ResgisterApplication { public static void main(String[] args) throws IOException { ZkClient zkClient = new ZkClient("localhost:2181", 1000); //獲取指定路徑的子節點個數 System.out.println(zkClient.countChildren("/")); //如果節點存在則刪除該節點 if (zkClient.exists("/dubbo")) { zkClient.delete("/dubbo"); } //創建永久的節點 String nodeName = zkClient.create("/dubbo", "{\"name\":\"admin\"}", CreateMode.PERSISTENT); System.out.println(nodeName); //創建臨時節點 zkClient.createEphemeralSequential("/dubbo/test", "a"); zkClient.createEphemeralSequential("/dubbo/test", "b"); //讀取節點數據 System.out.println(zkClient.readData("/dubbo").toString()); //訂閱dubbo數據的變化 zkClient.subscribeDataChanges("/dubbo", new IZkDataListener() { @Override public void handleDataChange(String dataPath, Object data) throws Exception { System.out.println(dataPath+"節點數據發生變化。。。"); } @Override public void handleDataDeleted(String dataPath) throws Exception { System.out.println(dataPath+"節點數據被刪除...."); } }); //訂閱dubbo子節點的變化 zkClient.subscribeChildChanges("/dubbo",(parentPath, currentChilds) -> System.out.println("dubbo節點發生變化")); //更新dubbo節點的數據 zkClient.writeData("/dubbo", "dubbo"); System.in.read(); } }
注意以下幾點:
1.不能刪除已經存在子節點的節點
2.不能再臨時節點上創建節點
四。zookeeper與eureka淺談
一個分布式系統不可能同時滿足C(一致性)、A(可用性)和P(分區容錯性)
zookeeper優先保證CP,當服務發生故障會進行leader的選舉,整個期間服務處在不可用狀態,如果選舉時間過長勢必會大幅度降低性能,另外就用途來說zookeeper偏向於服務的協調,當然含有注冊中心的作用
eureka優先保證AP, 即服務的節點各個都是平等的,沒有leader不leader一說, 當服務發生故障時,其余的節點仍然可以提供服務,因此在出現故障時,性能表現優於zookeeper,但是可能會造成數據不一致的情況。
