0 介紹
官網:http://zookeeper.apache.org/
ZooKeeper是Hadoop的正式子項目,它是一個針對大型分布式系統的可靠協調系統,提供的功能包括:配置維護、名字服務、分布式同步、組服務等。ZooKeeper的目標就是封裝好復雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
ZooKeeper代碼版本中,提供了分布式獨享鎖、選舉、隊列的接口,代碼在zookeeper-x.x.x\src\recipes。其中分布鎖和隊列有Java和C兩個版本,選舉只有Java版本。
ZooKeeper是可以集群復制的,集群間通過Zab(ZooKeeper Atomic Broadcast)協議來保持數據的一致性。
原理:http://cailin.iteye.com/blog/2014486/
1 安裝
1.1 前提
需配置Java運行環境
1.2 下載
http://mirrors.cnnic.cn/apache/zookeeper
https://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
1.3 解壓
解壓到自己想要的目錄即可
1.4 配置
可通過復制conf/zoo_sample.cfg
文件,命名為zoo.cfg,然后進行修改。
示例
# ZooKeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。
tickTime=2000
# 投票選舉新leader的初始化時間
initLimit=10
# 集群中的follower服務器與leader服務器之間請求和應答之間能容忍的最多心跳數(tickTime的數量)
syncLimit=5
# 保存數據的目錄
dataDir=D:\\zookeeper\\data
#保存日志文件的目錄
dataLogDir=D:\\zookeeper\\log
# 客戶端啟動端口
clientPort=2181
1.5 運行
雙擊bin/zkServer.cmd
啟動ZooKeeper啟動服務端。
bin\zkCli.cmd -server 127.0.0.1:2181
啟動客戶端操作。
2 結構
ZooKeeper的核心類似一個精簡的文件系統,提供一些簡單的操作和一些附件的抽象(例如,znode的排序與watch)。
有4種節點類型
類型 | 說明 |
---|---|
持久節點(PERSISTENT) | 節點創建后,就一直存在,直到有刪除操作來主動清除這個節點 |
持久順序節點(PERSISTENT_SEQUENTIAL) | 持久化節點,每個父節點會為他的第一級子節點維護一個單調增數 |
臨時節點(EPHEMERAL) | 臨時節點的生命周期和客戶端會話綁定。也就是說,如果客戶端會話失效,那么這個節點就會自動被清除掉。 |
臨時順序節點(EPHEMERAL_SEQUENTIAL) | 臨時節點,每個父節點會為他的第一級子節點維護一個單調增數,可用於實現分布式鎖 |
3 常用命令
- help:查看可執行的命令
- quit:退出客戶端
- ls:查看某個節點下的數據
- create:在某個節點下創建子節點
- delete:刪除子節點
- rmr:刪除路徑
- get:獲取節點數據
- set:設置節點數據
4 在Java中進行使用
導入相應的jar包,這里使用Maven進行jar包的管理,如下配置
<zookeeper.version>3.4.10</zookeeper.version>
<zkclient.version>0.10</zkclient.version>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>${zkclient.version}</version>
</dependency>
org.apache.zookeeper.ZooKeeper
的使用
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ZooKeeperTest {
private static final String ZK_CONNECT_URL = "127.0.0.1:2181";
private static final int SESSION_TIMEOUT = 3000;
// 這里直接拋出Exception,實際項目中需要自行捕獲異常
public static void main(String[] args) throws Exception {
ZooKeeper zooKeeper = new ZooKeeper(ZK_CONNECT_URL, SESSION_TIMEOUT, null);
// 設置監聽器
zooKeeper.register(new ZkWatcher(zooKeeper, "/root"));
// 創建root節點,其包含的數據為“root data”,設置訪問權限為所有人均可訪問,創建模式為持久化節點
zooKeeper.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 設置節點內容,-1無視版本,如果版本與服務器上版本不一致則拋出異常
zooKeeper.setData("/root", "new data".getBytes(), -1);
// 獲取節點內容
Stat stat = new Stat();
System.out.println(new String(zooKeeper.getData("/root", false, stat)));
// 創建子節點
zooKeeper.create("/root/child", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 刪除節點,必須先刪除子節點才能刪除根節點,不然會報錯
zooKeeper.delete("/root/child", -1);
zooKeeper.delete("/root", -1);
}
// 節點監聽器
private static class ZkWatcher implements Watcher {
private ZooKeeper zooKeeper;
private String path;
public ZkWatcher(ZooKeeper zooKeeper, String path) {
this.zooKeeper = zooKeeper;
this.path = path;
}
@Override
public void process(WatchedEvent event) {
System.out.println("watcher:" + event.getType());
// 由於Watcher的監聽只能是一次性,所以需要這樣處理,或者改用ZkClient進行實現
try {
zooKeeper.exists(path, true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
org.I0Itec.zkclient.ZkClient
的使用
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.CreateMode;
public class ZkClientTest {
private static final String ZK_CONNECT_URL = "127.0.0.1:2181";
private static final String PATH = "/zkclient";
public static void main(String[] args) {
ZkClient zkClient = new ZkClient(ZK_CONNECT_URL);
zkClient.subscribeDataChanges(PATH, new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("handleDataDeleted dataPath:" + dataPath);
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("handleDataChange dataPath:" + dataPath + " data:" + data);
}
});
// 創建節點
zkClient.create(PATH, "Hello", CreateMode.PERSISTENT);
// 設置節點數據
zkClient.writeData(PATH, "new");
// 獲取數據
System.out.println(zkClient.readData(PATH));
// 創建子節點
zkClient.create(PATH + "/child", "child", CreateMode.PERSISTENT);
// 獲取子節點信息
System.out.println(zkClient.getChildren(PATH));
// 刪除節點
zkClient.delete(PATH + "/child");
zkClient.delete(PATH);
}
}