【ZooKeeper系列】2.用Java實現ZooKeeper API的調用

舒適提示:在這裏我再次提個小要求,但願你們能習慣看 官方文檔,文檔雖然是英文但用詞都比較簡單,基本都能看懂文檔表達的意思。 授之以魚不如授之以漁的道理相信你們都明白,也但願經過猿人谷的這個ZooKeeper系列,讓你們入門、到熟悉,觸類旁通後能精通ZooKeeper。

在前一篇咱們介紹了ZooKeeper單機版、僞集羣和集羣環境搭建,經過命令行的方式作了節點的建立、刪除、更新、獲取節點信息的測試。Zookeeper 的目的是爲客戶端構建複雜的協調功能提供簡單、高效的核心 API,這一篇咱們用Java經過ZooKeeper提供的API接口來實現這些增刪改查的功能。html

1 簡介

org.apache.zookeeper.Zookeeper是ZooKeeper客戶端的主類,在官方文檔中已明確說明(This is the main class of ZooKeeper client library.)。java

This is the main class of ZooKeeper client library. To use a ZooKeeper service, an application must first instantiate an object of ZooKeeper class. All the iterations will be done by calling the methods of ZooKeeper class. The methods of this class are thread-safe unless otherwise noted.
Once a connection to a server is established, a session ID is assigned to the client. The client will send heart beats to the server periodically to keep the session valid.

建立一個ZooKeeper的實例來使用org.apache.zookeeper.Zookeeper裏的方法,官方文檔已經指出沒有特別聲明的話,ZooKeeper類裏的方法是線程安全的。客戶端鏈接到ZooKeeper服務的時候,會給客戶端分配一個會話ID(session ID),客戶端與服務端會經過心跳來保持會話有效。node

org.apache.zookeeper.Zookeeper裏的方法很是多,就不一一列舉了,只列幾個增刪改查的。git

Method Description
create(String path, byte[] data, List<ACL> acl, CreateMode createMode) Create a node with the given path. (建立指定路徑的節點)
create(String path, byte[] data, List<ACL> acl, CreateMode createMode, AsyncCallback.Create2Callback cb, Object ctx) The asynchronous version of create.(異步形式建立)
create(String path, byte[] data, List<ACL> acl, CreateMode createMode, Stat stat) Create a node with the given path and returns the Stat of that node.(按指定路徑建立節點並返回節點狀態信息)
delete(String path, int version) Delete the node with the given path.(刪除指定路徑的節點)
delete(String path, int version, AsyncCallback.VoidCallback cb, Object ctx) The asynchronous version of delete.(異步刪除指定路徑的節點)
exists(String path, boolean watch) Return the stat of the node of the given path.(返回指定路徑的節點狀態信息)
getChildren(String path, boolean watch) Return the list of the children of the node of the given path.(返回指定路徑的全部子節點狀態信息)
getData(String path, boolean watch, Stat stat) Return the data and the stat of the node of the given path.(返回指定路徑的節點數據和狀態信息)
setData(String path, byte[] data, int version) Set the data for the node of the given path if such a node exists and the given version matches the version of the node (if the given version is -1, it matches any node's versions).(給指定路徑和版本的節點設置新值,如版本爲-1,即給全部版本設置值)

2 測試環境搭建

這裏新建一個Spring Boot的項目來進行測試,新建Spring Boot項目的過程很簡單,也不是這裏的重點,就不作介紹了。shell

項目裏會須要額外引入兩個包來進行測試:apache

<dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.5.2</version>
        </dependency>

3 API測試

完整測試代碼以下:segmentfault

/**
 *  簡單測試示例
 * @author 猿人谷
 * @date 2019/12/16
 */
public class ZooKeeperDemo {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZooKeeperDemo.class);

    private static final int SESSION_TIME_OUT = 10000;
    // ZooKeeper服務的地址,如爲集羣,多個地址用逗號分隔
    private static final String CONNECT_STRING = "127.0.0.1:2181";
    private static final String ZNODE_PATH = "/zk_demo";
    private static final String ZNODE_PATH_PARENT = "/app1";
    private static final String ZNODE_PATH_CHILDREN = "/app1/app1_1";

    private ZooKeeper zk = null;

    @Before
    public void init() throws IOException {
        zk = new ZooKeeper(CONNECT_STRING, SESSION_TIME_OUT, new Watcher(){
            @Override
            public void process(WatchedEvent event) {
                System.out.println("已經觸發了" + event.getType() + "事件!");
            }
        });

    }

    @Test
    public void testCreate() throws KeeperException, InterruptedException {
        zk.create(ZNODE_PATH, "anna2019".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    @Test
    public void testCreateParentZnode() throws KeeperException, InterruptedException {
        zk.create(ZNODE_PATH_PARENT, "anna2019".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    @Test
    public void testCreateChildrenZnode() throws KeeperException, InterruptedException {
        zk.create(ZNODE_PATH_CHILDREN, "anna2020".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    @Test
    public void testGet() throws KeeperException, InterruptedException {
        byte[] data1 = zk.getData(ZNODE_PATH, false, null);
        byte[] data2 = zk.getData(ZNODE_PATH_PARENT, false, null);
        byte[] data3 = zk.getData(ZNODE_PATH_CHILDREN, false, null);
        LOGGER.info("{}的信息:{}", ZNODE_PATH, new String(data1) );
        LOGGER.info("{}的信息:{}", ZNODE_PATH_PARENT, new String(data2) );
        LOGGER.info("{}的信息:{}", ZNODE_PATH_CHILDREN, new String(data3) );
    }

    /**
     *  刪除
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDelete() throws KeeperException, InterruptedException {
        // 指定要刪除的版本,-1表示刪除全部版本
        zk.delete(ZNODE_PATH, -1);
    }

    /**
     *  刪除含有子節點
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDeleteHasChildrenZnode() throws KeeperException, InterruptedException {
        // 指定要刪除的版本,-1表示刪除全部版本
        zk.delete(ZNODE_PATH_PARENT, -1);
    }

    @Test
    public void testSet() throws KeeperException, InterruptedException {
        Stat stat = zk.setData(ZNODE_PATH, "yuanrengu".getBytes(), -1);
        LOGGER.info(stat.toString());
    }

}

上面有用到@Before,簡單說明下:api

  • @BeforeClass – 表示在類中的任意public static void方法執行以前執行
  • @AfterClass – 表示在類中的任意public static void方法執行以後執行
  • @Before – 表示在任意使用@Test註解標註的public void方法執行以前執行
  • @After – 表示在任意使用@Test註解標註的public void方法執行以後執行
  • @Test – 使用該註解標註的public void方法會表示爲一個測試方法

若是將SESSION_TIME_OUT設置的時間過短,會報API客戶端異常:org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /zk_demo 。完整的報錯信息以下:安全

09:33:52.139 [main-SendThread(106.12.111.172:2181)] DEBUG org.apache.zookeeper.ClientCnxnSocketNIO - Ignoring exception during shutdown input
java.net.SocketException: Socket is not connected
    at sun.nio.ch.Net.translateToSocketException(Net.java:123)
    at sun.nio.ch.Net.translateException(Net.java:157)
    at sun.nio.ch.Net.translateException(Net.java:163)
    at sun.nio.ch.SocketAdaptor.shutdownInput(SocketAdaptor.java:401)
    at org.apache.zookeeper.ClientCnxnSocketNIO.cleanup(ClientCnxnSocketNIO.java:198)
    at org.apache.zookeeper.ClientCnxn$SendThread.cleanup(ClientCnxn.java:1338)
    at org.apache.zookeeper.ClientCnxn$SendThread.cleanAndNotifyState(ClientCnxn.java:1276)
    at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1254)
Caused by: java.nio.channels.NotYetConnectedException: null
    at sun.nio.ch.SocketChannelImpl.shutdownInput(SocketChannelImpl.java:782)
    at sun.nio.ch.SocketAdaptor.shutdownInput(SocketAdaptor.java:399)
    ... 4 common frames omitted
09:33:52.140 [main-SendThread(106.12.111.172:2181)] DEBUG org.apache.zookeeper.ClientCnxnSocketNIO - Ignoring exception during shutdown output
java.net.SocketException: Socket is not connected
    at sun.nio.ch.Net.translateToSocketException(Net.java:123)
    at sun.nio.ch.Net.translateException(Net.java:157)
    at sun.nio.ch.Net.translateException(Net.java:163)
    at sun.nio.ch.SocketAdaptor.shutdownOutput(SocketAdaptor.java:409)
    at org.apache.zookeeper.ClientCnxnSocketNIO.cleanup(ClientCnxnSocketNIO.java:205)
    at org.apache.zookeeper.ClientCnxn$SendThread.cleanup(ClientCnxn.java:1338)
    at org.apache.zookeeper.ClientCnxn$SendThread.cleanAndNotifyState(ClientCnxn.java:1276)
    at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1254)
Caused by: java.nio.channels.NotYetConnectedException: null
    at sun.nio.ch.SocketChannelImpl.shutdownOutput(SocketChannelImpl.java:799)
    at sun.nio.ch.SocketAdaptor.shutdownOutput(SocketAdaptor.java:407)
    ... 4 common frames omitted

org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /zk_demo

    at org.apache.zookeeper.KeeperException.create(KeeperException.java:102)
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:54)
    at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:2131)
    at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:2160)
    at com.yuanrengu.demo.ZooKeeperDemo.testGet(ZooKeeperDemo.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Disconnected from the target VM, address: '127.0.0.1:60454', transport: 'socket'

Process finished with exit code -1

起初覺得是ZooKeeper服務部署有問題或服務沒啓動,經檢查確認無誤後,debug調試發現,是SESSION_TIME_OUT = 2000;設置的值過小,改成10000後,再也不報錯。服務器

SESSION_TIME_OUT 是 會話超時時間,也就是當一個zookeeper超過該時間沒有心跳,則認爲該節點故障。因此,若是此值小於zookeeper的建立時間,則當zookeeper還將來得及建立鏈接,會話時間已到,所以拋出異常認爲該節點故障。

3.1 新增

public String create(String path,
                     byte[] data,
                     List<ACL> acl,
                     CreateMode createMode)
              throws KeeperException,
                     InterruptedException
                     
Create a node with the given path. The node data will be the given data, and node acl will be the given acl.
The flags argument specifies whether the created node will be ephemeral or not.

An ephemeral node will be removed by the ZooKeeper automatically when the session associated with the creation of the node expires.

The flags argument can also specify to create a sequential node. The actual path name of a sequential node will be the given path plus a suffix "i" where i is the current sequential number of the node. The sequence number is always fixed length of 10 digits, 0 padded. Once such a node is created, the sequential number will be incremented by one.

If a node with the same actual path already exists in the ZooKeeper, a KeeperException with error code KeeperException.NodeExists will be thrown. Note that since a different actual path is used for each invocation of creating sequential node with the same path argument, the call will never throw "file exists" KeeperException.

If the parent node does not exist in the ZooKeeper, a KeeperException with error code KeeperException.NoNode will be thrown.

An ephemeral node cannot have children. If the parent node of the given path is ephemeral, a KeeperException with error code KeeperException.NoChildrenForEphemerals will be thrown.

This operation, if successful, will trigger all the watches left on the node of the given path by exists and getData API calls, and the watches left on the parent node by getChildren API calls.

If a node is created successfully, the ZooKeeper server will trigger the watches on the path left by exists calls, and the watches on the parent of the node by getChildren calls.

The maximum allowable size of the data array is 1 MB (1,048,576 bytes). Arrays larger than this will cause a KeeperExecption to be thrown.

Parameters:
path - the path for the node
data - the initial data for the node
acl - the acl for the node
createMode - specifying whether the node to be created is ephemeral and/or sequential
Returns:
the actual path of the created node
Throws:
KeeperException - if the server returns a non-zero error code
KeeperException.InvalidACLException - if the ACL is invalid, null, or empty
InterruptedException - if the transaction is interrupted
IllegalArgumentException - if an invalid path is specified

Talk is cheap. Show me the code.這裏咱們不瞎BB,直接上官方文檔。官方文檔是否是很容易看懂,並且解釋的很是清楚(並且稍顯囉嗦的感受)?

這裏簡單列下文檔中的幾個關鍵點

  1. 按指定路徑和節點形式建立,可指定節點爲持久節點、臨時節點等。

這裏要說下CreateMode,你們可能都說ZooKeeper只有4種形式的節點(持久、臨時、持久順序、臨時順序),看文檔的話,實際上是有7種形式的。

public enum CreateMode {
   PERSISTENT(0, false, false, false, false),
   PERSISTENT_SEQUENTIAL(2, false, true, false, false),
   EPHEMERAL(1, true, false, false, false),
   EPHEMERAL_SEQUENTIAL(3, true, true, false, false),
   CONTAINER(4, false, false, true, false),
   PERSISTENT_WITH_TTL(5, false, false, false, true),
   PERSISTENT_SEQUENTIAL_WITH_TTL(6, false, true, false, true);
}
  • PERSISTENT:持久節點(也有叫永久節點的),不會隨着會話的結束而自動刪除。
  • PERSISTENT_SEQUENTIAL:帶單調遞增序號的持久節點,不會隨着會話的結束而自動刪除。
  • EPHEMERAL:臨時節點,會隨着會話的結束而自動刪除。
  • EPHEMERAL_SEQUENTIAL:帶單調遞增序號的臨時節點,會隨着會話的結束而自動刪除。
  • CONTAINER:容器節點,用於Leader、Lock等特殊用途,當容器節點不存在任何子節點時,容器將成爲服務器在未來某個時候刪除的候選節點。
  • PERSISTENT_WITH_TTL:帶TTL(time-to-live,存活時間)的持久節點,節點在TTL時間以內沒有獲得更新而且沒有子節點,就會被自動刪除。
  • PERSISTENT_SEQUENTIAL_WITH_TTL:帶TTL(time-to-live,存活時間)和單調遞增序號的持久節點,節點在TTL時間以內沒有獲得更新而且沒有子節點,就會被自動刪除。
  1. 若是指令路徑和版本的節點已經存在,則會拋出一個KeeperException異常。
  2. 臨時節點不能有子節點。若是給臨時節點建立子節點會拋KeeperException異常。
  3. 臨時節點的生命週期與客戶端會話綁定。一旦客戶端會話失效(客戶端與 Zookeeper鏈接斷開不必定會話失效),那麼這個客戶端建立的全部臨時節點都會被移除
  4. byte[] data容許的最大數據量爲1MB(1,048,576 bytes)。若是超過,會拋KeeperExecption。

運行建立節點的代碼:

@Test
    public void testCreate() throws KeeperException, InterruptedException {
        zk.create(ZNODE_PATH, "anna2019".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

能夠經過日誌信息獲得節點建立成功:

DEBUG org.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x101402626bb000b, packet:: clientPath:null serverPath:null finished:false header:: 1,1  replyHeader:: 1,12884901937,0  request:: '/zk_demo,#616e6e6132303139,v{s{31,s{'world,'anyone}}},0  response:: '/zk_demo

在服務端查看,/zk_demo節點建立成功:

[zk: 127.0.0.1:2181(CONNECTED) 21] ls /
[zookeeper, zk_demo]
[zk: 127.0.0.1:2181(CONNECTED) 22] stat /zk_demo
cZxid = 0x300000031
ctime = Tue Dec 17 12:52:50 CST 2019
mZxid = 0x300000031
mtime = Tue Dec 17 12:52:50 CST 2019
pZxid = 0x300000031
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 8
numChildren = 0

3.2 獲取

public byte[] getData(String path,
                      boolean watch,
                      Stat stat)
               throws KeeperException,
                      InterruptedException

Return the data and the stat of the node of the given path.
If the watch is true and the call is successful (no exception is thrown), a watch will be left on the node with the given path. The watch will be triggered by a successful operation that sets data on the node, or deletes the node.

A KeeperException with error code KeeperException.NoNode will be thrown if no node with the given path exists.

Parameters:
path - the given path
watch - whether need to watch this node
stat - the stat of the node
Returns:
the data of the node
Throws:
KeeperException - If the server signals an error with a non-zero error code
InterruptedException - If the server transaction is interrupted.

指定路徑的節點不存在時就拋KeeperException.NoNode異常。

運行:

@Test
    public void testGet() throws KeeperException, InterruptedException {
        byte[] data1 = zk.getData(ZNODE_PATH, false, null);
        byte[] data2 = zk.getData(ZNODE_PATH_PARENT, false, null);
        byte[] data3 = zk.getData(ZNODE_PATH_CHILDREN, false, null);
        LOGGER.info("{}的信息:{}", ZNODE_PATH, new String(data1) );
        LOGGER.info("{}的信息:{}", ZNODE_PATH_PARENT, new String(data2) );
        LOGGER.info("{}的信息:{}", ZNODE_PATH_CHILDREN, new String(data3) );
    }

結果:

13:51:00.288 [main] INFO com.yuanrengu.demo.ZooKeeperDemo - /zk_demo的信息:anna2019
13:51:00.288 [main] INFO com.yuanrengu.demo.ZooKeeperDemo - /app1的信息:anna2019
13:51:00.289 [main] INFO com.yuanrengu.demo.ZooKeeperDemo - /app1/app1_1的信息:anna2020

3.3 更新

public Stat setData(String path,
                    byte[] data,
                    int version)
             throws KeeperException,
                    InterruptedException
                    
Set the data for the node of the given path if such a node exists and the given version matches the version of the node (if the given version is -1, it matches any node's versions). Return the stat of the node.
This operation, if successful, will trigger all the watches on the node of the given path left by getData calls.

A KeeperException with error code KeeperException.NoNode will be thrown if no node with the given path exists.

A KeeperException with error code KeeperException.BadVersion will be thrown if the given version does not match the node's version.

The maximum allowable size of the data array is 1 MB (1,048,576 bytes). Arrays larger than this will cause a KeeperException to be thrown.

Parameters:
path - the path of the node
data - the data to set
version - the expected matching version
Returns:
the state of the node
Throws:
InterruptedException - If the server transaction is interrupted.
KeeperException - If the server signals an error with a non-zero error code.
IllegalArgumentException - if an invalid path is specified

主要注意如下幾點:

  1. 版本爲-1時,即表明適配指定路徑節點的全部版本。
  2. 若是指定路徑的節點不存在會拋KeeperException.NoNode異常,該節點沒有傳入的版本,會拋KeeperException.BadVersion異常。
  3. byte[] data容許的最大數據量爲1MB(1,048,576 bytes)。若是超過,會拋KeeperExecption。

運行:

@Test
    public void testSet() throws KeeperException, InterruptedException {
        Stat stat = zk.setData(ZNODE_PATH, "yuanrengu".getBytes(), -1);
        byte[] data = zk.getData(ZNODE_PATH, false, null);
        LOGGER.info(new String(data));
    }

能夠看到數據已經更新:

15:46:16.472 [main] INFO com.yuanrengu.demo.ZooKeeperDemo - yuanrengu

3.4 刪除

public void delete(String path,
                   int version)
            throws InterruptedException,
                   KeeperException
                   
Delete the node with the given path. The call will succeed if such a node exists, and the given version matches the node's version (if the given version is -1, it matches any node's versions).
A KeeperException with error code KeeperException.NoNode will be thrown if the nodes does not exist.

A KeeperException with error code KeeperException.BadVersion will be thrown if the given version does not match the node's version.

A KeeperException with error code KeeperException.NotEmpty will be thrown if the node has children.

This operation, if successful, will trigger all the watches on the node of the given path left by exists API calls, and the watches on the parent node left by getChildren API calls.

Parameters:
path - the path of the node to be deleted.
version - the expected node version.
Throws:
InterruptedException - IF the server transaction is interrupted
KeeperException - If the server signals an error with a non-zero return code.
IllegalArgumentException - if an invalid path is specified

節點可能含有子節點,刪除節點的操做有幾點須要特別注意:

  1. 版本爲-1時,即表明適配指定路徑節點的全部版本。
  2. 若是指定路徑的節點不存在會拋KeeperException.NoNode異常,該節點沒有傳入的版本,會拋KeeperException.BadVersion異常。
  3. 若是節點含有子節點,刪除父節點(parent node)時會拋KeeperException.NotEmpty異常。

/app1有子節點,咱們作下刪除操做:

/**
     *  刪除含有子節點的父節點
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDeleteHasChildrenZnode() throws KeeperException, InterruptedException {
        // 指定要刪除的版本,-1表示刪除全部版本
        zk.delete(ZNODE_PATH_PARENT, -1);
    }

能夠看到日誌:

org.apache.zookeeper.KeeperException$NotEmptyException: KeeperErrorCode = Directory not empty for /app1

    at org.apache.zookeeper.KeeperException.create(KeeperException.java:132)
    at org.apache.zookeeper.KeeperException.create(KeeperException.java:54)
    at org.apache.zookeeper.ZooKeeper.delete(ZooKeeper.java:1793)
    at com.yuanrengu.demo.ZooKeeperDemo.testDeleteHasChildrenZnode(ZooKeeperDemo.java:89)

4 總結

上面咱們實現了節點的增、刪、改、查的測試,後面的篇章會有更多好玩的用法,如實現分佈式鎖、配置中心等。

基於上面的分析,總結幾個注意的點:

  1. 節點有7種形式
  • PERSISTENT:持久節點(也有叫永久節點的),不會隨着會話的結束而自動刪除。
  • PERSISTENT_SEQUENTIAL:帶單調遞增序號的持久節點,不會隨着會話的結束而自動刪除。
  • EPHEMERAL:臨時節點,會隨着會話的結束而自動刪除。
  • EPHEMERAL_SEQUENTIAL:帶單調遞增序號的臨時節點,會隨着會話的結束而自動刪除。
  • CONTAINER:容器節點,用於Leader、Lock等特殊用途,當容器節點不存在任何子節點時,容器將成爲服務器在未來某個時候刪除的候選節點。
  • PERSISTENT_WITH_TTL:帶TTL(time-to-live,存活時間)的持久節點,節點在TTL時間以內沒有獲得更新而且沒有子節點,就會被自動刪除。
  • PERSISTENT_SEQUENTIAL_WITH_TTL:帶TTL(time-to-live,存活時間)和單調遞增序號的持久節點,節點在TTL時間以內沒有獲得更新而且沒有子節點,就會被自動刪除。
  1. 臨時節點不能有子節點。若是給臨時節點建立子節點會拋KeeperException異常。
  2. 臨時節點的生命週期與客戶端會話綁定。一旦客戶端會話失效(客戶端與 Zookeeper鏈接斷開不必定會話失效),那麼這個客戶端建立的全部臨時節點都會被移除
  3. byte[] data容許的最大數據量爲1MB(1,048,576 bytes)
相關文章
相關標籤/搜索