分散式系列七: zookeeper簡單用法
阿新 • • 發佈:2018-12-13
zookeeper是分散式開源框架, 是Google Chubby的一個實現, 主要作為分散式系統的協調服務. Dobbo等框架使用了其功能.
zookeeper特性
- 順序一致性: 事務請求最終會嚴格按順序執行
- 原子性:
- 可靠性:
- 實時性:
- 單一檢視:
安裝
使用windows的linux子系統時: cd /mnt/e/chromedownload/
轉到windows下載路徑
拷貝 cp /mnt/e/chromedownload/zookeeper.tar.gz /program/zookeeper.tar.gz
轉到 cd /program
如果沒有的先mkdir program
解壓 tar -zxvf zookeeper.tar.gz
cd ZK_HOME/conf
拷貝 cp zoo_sample.cfg zoo.cfg
轉到 cd ZK_HOME/bin
啟動 sh zkServer.sh start
叢集搭建
- zoo.cfg中配置叢集, 配置格式如
server.id=ip:port:port
; 有幾臺就配置幾個.例如: server.1=192.168.1.145:2897:3181 server.2=192.168.1.146:2897:3181 server.3=192.168.1.147:2897:3181 - zoo.cfg中的dataDir所配置的目錄下新增myid檔案, 值對應server.id的id
- zoo.cfg中, 如果需要observer,則新增
peerType=observer
, 並且修改server.id=ip:port:port:observer
zoo.cfg 配置
- tickTime=2000 zk的方法最小時間單位
- initTime=10 時長為10*tickTime, follow節點和leader節點同步的時間
- syncLimit=5 時長為5*tickTime, leader和follow幾點進行心跳檢測的最大延遲時間
- dataDir=/tmp/zookeeper 儲存快照檔案的目錄
- dataLogDir = /log/zookeeper 事務日誌的儲存路徑, 預設在dataDir下
- clientPort=2181 連線zookeeper的預設埠
zookeeper幾個概念
- znode: zookeeper資料儲存為樹形結構, 深度層級沒有限制, znode是資料儲存節點,是zookeeper的最小儲存單元. 分為1.持久化節點;2.持久化有序節點;3.臨時節點;4.臨時有序節點;
- 臨時節點, 是會話時生成的節點, 會話結束後節點會自動刪除.
客戶端命令操作
help
可以檢視客戶端支援的命令
- create [-s] [-e] node : 建立節點 -s是有序 -e臨時節點
- get path [watch] 獲取節點的資訊
- set path data [version] : 修改節點的值
- delete path [version] : 刪除節點, 當節點有子節點時無法刪除
[version] 樂觀鎖
[Watcher] 提供了釋出/訂閱, 允許客戶端向伺服器端註冊一個監聽, 當服務端觸發指定事件時會觸發watcher,服務端向客戶端傳送一個通知. Watcher是一次性的, 觸發一次後自動失效
資訊節點
- stat path 可以檢視節點的資訊
cversion=0 子節點的版本 AclVersion=0 acl的版本號, 許可權控制相關 dataVersion=1 資料的版本號 cxid 建立的事務id mzxid 最後一次修改的事務id pzxid 子節點最後一次修改的事務id ephemeralOwner 臨時會話的id dataLength 資料長度 numChidren 子節點數量
java開發
引用依賴
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.4-beta</version>
</dependency>
java程式碼
/**
* 定義Watcher
*/
public class MyWatcher implements Watcher {
@Override
public void process(WatchedEvent event) {
if(event.getState()== Event.KeeperState.SyncConnected){
System.out.println("---->>>>>"+event.getType());
System.out.println("---->>>>>"+event.getPath());
}
}
}
//測試
public class MySession {
private static final String CONN = "localhost:2181";
private static Stat stat = new Stat();
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
ZooKeeper zooKeeper = new ZooKeeper(CONN,1000,new MyWatcher());
// 建立
zooKeeper.create("/xlx","this is a string".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 查詢,註冊watcher
byte[] rst = zooKeeper.getData("/xlx",true,stat);
System.out.println(new String(rst));
//刪除(只能刪除永久節點)
zooKeeper.delete("/xlx",-1);
// 建立
zooKeeper.create("/xlx","this is a string".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 查詢
byte[] rs = zooKeeper.getData("/xlx",true,stat);
System.out.println(new String(rs));
// 註冊watcher
zooKeeper.exists("/xlx/yy",true);
// 建立
zooKeeper.create("/xlx/yy","this is a sub child string".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 獲取子節點
List<String> children = zooKeeper.getChildren("/xlx", true);
System.out.println(children);
//刪除(只能刪除永久節點)
zooKeeper.delete("/xlx/yy",-1);
// 修改
zooKeeper.setData("/xlx","this is a modified string".getBytes(),-1);
byte[] rss = zooKeeper.getData("/xlx",true,stat);
System.out.println(new String(rss));
//刪除(只能刪除永久節點)
zooKeeper.delete("/xlx",-1);
// watcher 非同步的, 這裡停留段時間才可以檢視到watcher列印的資訊
Thread.sleep(2000);
}
}
三方API
- zkClient
- curator 這個用的較多,Netflix開源
curator開發
特點:
- 抽象層次更高
- 鏈式程式設計風格
- 非同步回撥
public class CuratorSession {
private static final String CONN = "localhost:2181";
public static void main(String[] args) throws Exception {
// 建立
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(CONN, 2000, 5000, new ExponentialBackoffRetry(1000,3));
curatorFramework.start();
System.out.println(curatorFramework.getState());
//另一種方式
//curatorFramework = CuratorFrameworkFactory.builder().build();
// 新增節點
curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/curator/chd/dd","dfadfe".getBytes());
//讀取
byte[] data = curatorFramework.getData().forPath("/curator/chd/dd");
java.lang.String string = new java.lang.String(data);
System.out.println(string);
// 修改
Stat stat = curatorFramework.setData().forPath("/curator/chd/dd","fdaefv".getBytes());
System.out.println(stat);
curatorFramework.setData().inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println(event);
}
}).forPath("/curator/chd/dd","fafdae".getBytes());
//刪除
curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath("/curator/chd");
Thread.sleep(2000);
}
}
這些程式碼寫下來就算入門了, curator真正有用的使用場景還沒接觸到, 比如分散式鎖,leader選舉等, curator有示例程式, 可以在github上檢視Curator原始碼.