分散式系列七: zookeeper簡單用法
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上檢視ofollow,noindex" target="_blank">Curator原始碼 .