1. 程式人生 > >分散式系列七: zookeeper簡單用法

分散式系列七: 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上檢視Curator原始碼.