Warm tip: HERE I make a small request again, I hope you can get used to reading the official documents, although the documents are in English but the words are relatively simple, basically can understand the meaning of the document expression. I believe we all understand that it is better to teach people to fish than to teach them to fish. I also hope that through the ZooKeeper series of the Valley of apes, we can start and get familiar with ZooKeeper and master ZooKeeper after drawing inferions.

In the previous article, we introduced ZooKeeper stand-alone version, pseudo cluster and cluster environment construction, and tested node creation, deletion, update and obtaining node information through command line. The purpose of Zookeeper is to provide a simple and efficient core API for the client to build complex coordination functions. In this article, we use Java to achieve these functions of adding, deleting, modifying and checking through the API interface provided by Zookeeper.

1 introduction

Org. Apache. Zookeeper. Zookeeper is zookeeper client main class, in the official document (this series with v3.5.5 is given priority to, This is the main class of ZooKeeper Client Library.

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.

Create a ZooKeeper instances to use org. Apache. The ZooKeeper. The method in the ZooKeeper, official document has already pointed out that there is no special statement, they are in the class is thread-safe. When a client connects to the ZooKeeper service, a session ID is assigned to the client. The client and server maintain the validity of the session through heartbeat.

Org. Apache. The zookeeper. The method is very much in the zookeeper, not list one by one, only a few to add and delete.

Method Description
create(String path, byte[] data, List acl, CreateMode createMode) Create a node with the given path.
create(String path, byte[] data, List acl, CreateMode createMode, AsyncCallback.Create2Callback cb, Object ctx) The asynchronous version of create.
create(String path, byte[] data, List acl, CreateMode createMode, Stat stat) Create a node with the given path and return 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). (If the given version is -1, it matches any node’s versions)

2 Test environment setup

Here, create a new Spring Boot project to test. The process of creating a New Spring Boot project is very simple and not the focus here, so I won’t do the introduction.

Two additional packages will be introduced into the project for testing:

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

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

3 the API test

The complete test code is as follows:

/** * Simple test example *@authorApe-man valley *@date2019/12/16 * /
public class ZooKeeperDemo {

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

    private static final int SESSION_TIME_OUT = 10000;
    // IP address of the ZooKeeper service. For example, multiple IP addresses are separated by commas (,)
    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(a) throws IOException {
        zk = new ZooKeeper(CONNECT_STRING, SESSION_TIME_OUT, new Watcher(){
            @Override
            public void process(WatchedEvent event) {
                System.out.println("It has been triggered." + event.getType() + "An event!); }}); }@Test
    public void testCreate(a) throws KeeperException, InterruptedException {
        zk.create(ZNODE_PATH, "anna2019".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

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

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

    @Test
    public void testGet(a) 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("{} message: {}", ZNODE_PATH, new String(data1) );
        LOGGER.info("{} message: {}", ZNODE_PATH_PARENT, new String(data2) );
        LOGGER.info("{} message: {}", ZNODE_PATH_CHILDREN, new String(data3) );
    }

    /** * delete *@throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDelete(a) throws KeeperException, InterruptedException {
        // Specify the version to be deleted. -1 indicates that all versions are to be deleted
        zk.delete(ZNODE_PATH, -1);
    }

    /** * delete the child node *@throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDeleteHasChildrenZnode(a) throws KeeperException, InterruptedException {
        // Specify the version to be deleted. -1 indicates that all versions are to be deleted
        zk.delete(ZNODE_PATH_PARENT, -1);
    }

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

The above is useful for @before, a brief explanation:

  • @beforeClass – executes before any public static void method in a class
  • AfterClass – after the execution of any public static void method in a class
  • @before – Before execution of any public void method annotated with the @test annotation
  • @after – indicates execution After any public void method annotated with the @test annotation
  • @test – A public void method annotated with this annotation is represented as a Test method

If set SESSION_TIME_OUT time too short, you will be submitted to the API client exception: org. Apache. The zookeeper. KeeperException $ConnectionLossException: KeeperErrorCode = ConnectionLoss for /zk_demo. The complete error message is as follows:

[main - SendThread 09:33:52. 139 (2181) 106.12.111.172:] the DEBUG org. Apache. Zookeeper. ClientCnxnSocketNIO - Ignoring the 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 -1Copy the code

At first, it was thought that the ZooKeeper service was deployed incorrectly or the service was not started. After the check, SESSION_TIME_OUT = 2000 was found during debugging. If the value is too small, no error will be reported after the value is changed to 10000.

SESSION_TIME_OUT is the session timeout period, that is, if a ZooKeeper does not have heartbeat after the timeout period, the node is considered faulty. Therefore, if the value is less than the creation time of ZooKeeper, the session time is up before ZooKeeper creates a connection. Therefore, an exception is thrown, indicating that the node is faulty.

3.1 Creating a Session

You can create a ZooKeeper instance to connect to the ZooKeeper server (for details, see ZooKeeper standalone, Pseudo-cluster, and Cluster Environment Setup).

10 ZooKeeper constructors are provided and described as follows:

Constructor Description
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider, ZKClientConfig clientConfig) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, ZKClientConfig conf) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly, HostProvider aHostProvider) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly, HostProvider aHostProvider, ZKClientConfig clientConfig) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, ZKClientConfig conf) To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.

The English description of each constructor is very simple, basic can see very clear, according to the actual application scenario to select the corresponding constructor.

There are constructors that include sessionId and sessionPasswd in the passed parameters, representing the sessionId and session key respectively. These two parameters can uniquely identify a session, and the client can reuse the session using these two parameters to recover the session. When connecting to the ZooKeeper server for the first time, you can obtain the ID and key of the current session by invoking the following two interfaces of the ZooKeeper object instance: Long getSessionId(); byte[] getSessionPasswd(); Once you have these two parameter values, you can pass in the constructor the next time you create an instance of the ZooKeeper object.

Select a few typical constructors to guide you through the document.

3.1.1 ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)

public ZooKeeper(String connectString,
                 int sessionTimeout,
                 Watcher watcher)
          throws IOException
          
To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - potentially (usually)before the session is fully established. The watcher argument specifies the watcher that will be notified of any changes  in state. This notification can come at any point before or after the constructor call has returned. The instantiated ZooKeeper client object will pick an arbitrary server from the connectString and attempt to connect to it. If establishment of the connection fails, another server in the connect string will betried (the order is non-deterministic, as we random shuffle the list), until a connection is established. The client will continueThe attempts until the session is explicitly closed. Added in 3.2.0: An optional "chroot" suffix may also be appended to the connection string. This will run the client commandswhile interpreting all paths relative to this root (similar to the unix chroot command).

Parameters:
connectString - comma separated host:port pairs, each corresponding to a zk server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If the optional chroot suffix is used the example would look like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" where the client would be rooted at "/app/a" and all paths would be relative to this root - ie getting/setting/etc... "/foo/bar" would result in operations being run on "/app/a/foo/bar" (from the server perspective).
sessionTimeout - session timeout in milliseconds
watcher - a watcher object which will be notified of state changes, may also be notified for node events
Throws:
IOException - in cases of network failure
IllegalArgumentException - if an invalid chroot path is specified
Copy the code

One thing to note is that the documentation states that the client and server establish sessions asynchronously. The constructor returns immediately after handling client initialization, and in most cases, a usable session is not really established and is in the “CONNECTING” state during the lifetime of the session. After the session is created, the ZooKeeper server sends an event notification to the client corresponding to the session. The client can establish a session only after obtaining the notification.

The Instantiated ZooKeeper client object will randomly select one of the servers listed by connectString and attempt to connect to it. If the connection fails to be established, another server will be tried (the order is uncertain because the listed servers are shuffled randomly) until the connection is established. That is, the client fails to connect to a server and continues to try until the session is explicitly closed.

Since version 3.2.0, the optional “chroot” suffix has been added. This means that you can add “chroot” to the server listed in connectString. After the ZooKeeper server is connected to the client, all operations on ZooKeeper are based on this root directory.

A brief description of the parameters:

parameter describe
connectString Specify the ZooKeeper server list, there are English comma-separated host: port of string, such as “127.0.0.1:3000127.00 0.1:3001127.00 0.1:3002”. Can be specified in the connectString client even after the server root directory, such as “127.0.0.1:3000127.00 0.1:3001127.00 0.1:3002 / app/a”.ZooKeeper operations are based on the root directory /app/a, that is, create a node whose path is "/foo/bar". The actual path is "/app/a/foo/bar".
sessionTimeout Timeout event of the session, an integer value in milliseconds. During a session, the ZooKeeper client and server use the heartbeat detection mechanism to maintain the validity of the session. If no heartbeat detection is performed within the sessionTimeout period, the session becomes invalid.
watcher ZooKeeper allows a client to an interface in the method of constructing Watcher (org. Apache. The ZooKeeper. Watcher) implementation class object as a Watch for the default event notification.This parameter can also be set tonullThe default Watch processor does not need to be set.

3.1.2 ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly)

public ZooKeeper(String connectString,
                 int sessionTimeout,
                 Watcher watcher,
                 boolean canBeReadOnly)
          throws IOException
          
To create a ZooKeeper client object, the application needs to pass a connection string containing a comma separated list of host:port pairs, each corresponding to a ZooKeeper server.
Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - potentially (usually)before the session is fully established. The watcher argument specifies the watcher that will be notified of any changes  in state. This notification can come at any point before or after the constructor call has returned. The instantiated ZooKeeper client object will pick an arbitrary server from the connectString and attempt to connect to it. If establishment of the connection fails, another server in the connect string will betried (the order is non-deterministic, as we random shuffle the list), until a connection is established. The client will continueThe attempts until the session is explicitly closed. Added in 3.2.0: An optional "chroot" suffix may also be appended to the connection string. This will run the client commandswhile interpreting all paths relative to this root (similar to the unix chroot command).

Parameters:
connectString - comma separated host:port pairs, each corresponding to a zk server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If the optional chroot suffix is used the example would look like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" where the client would be rooted at "/app/a" and all paths would be relative to this root - ie getting/setting/etc... "/foo/bar" would result in operations being run on "/app/a/foo/bar" (from the server perspective).
sessionTimeout - session timeout in milliseconds
watcher - a watcher object which will be notified of state changes, may also be notified for node events
canBeReadOnly - (added in 3.4) whether the created client is allowed to go to read-only mode in case of partitioning. Read-only mode basically means that if the client can't find any majority servers but there's partitioned server it could reach, it connects to one in read-only mode, i.e. read requests are allowed while write requests are not. It continues seeking for majority in the background.
Throws:
IOException - in cases of network failure
IllegalArgumentException - if an invalid chroot path is specified
Copy the code

This constructor is very similar to the previous one, except that since version 3.4 a canBeReadOnly parameter is added to indicate whether the current session supports “read-only” mode (read-only mode). By default, if a node in a ZooKeeper cluster loses network connection to more than half of the nodes in the cluster, the machine will no longer process client requests (including read and write requests). However, in some scenarios, when the ZooKeeper server encounters such a fault, the ZooKeeper server is still expected to provide the read service. This is the “read-only” mode of ZooKeeper. However, a client can connect to one of the servers in a partition, connect to one of the servers in read-only mode, allow read requests, but not write requests, and then continue to find more servers in the background.

3.2 new

public String create(String path,
                     byte[] data,
                     List<ACL> acl,
                     CreateMode createMode)
              throwsKeeperException, 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 usedfor 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
Copy the code

Talk is cheap. Show me the code. Here we are not blind BB, directly on the official document. Is the official documentation easy to read and clearly explained (and slightly wordy)?

Here are a few key points from the document:

  1. You can specify a persistent node or a temporary node. So here’s the thingCreateModeZooKeeper has only four types of nodes (persistent, temporary, persistent order, and temporary order)Seven kinds ofIn the form of.
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);
}
Copy the code
  • PERSISTENT: PERSISTENT nodes (also known as PERSISTENT nodes) are not deleted automatically at the end of a session.
  • PERSISTENT_SEQUENTIAL: a persistent node with monotonically increasing sequential numbers that is not automatically deleted at the end of a session.
  • EPHEMERAL: The temporary node that is automatically deleted as the session ends.
  • EPHEMERAL_SEQUENTIAL: A temporary node with a monotonically increasing sequential number that is automatically deleted as the session ends.
  • CONTAINER: container node, used for Leader, Lock and other special purposes. When the container node does not have any child nodes, the container will be a candidate node to be deleted by the server at some point in the future.
  • PERSISTENT_WITH_TTL: a persistent node with TTL (time-to-live). If the node has not been updated within the TTL and has no child nodes, it will be deleted automatically.
  • PERSISTENT_SEQUENTIAL_WITH_TTL: a persistent node with TTL (time-to-live) and monotonically increasing sequence number. If the node has not been updated within the TTL and has no child nodes, it will be deleted automatically.
  1. If the instruction path and version of the node already exist, a KeeperException will be thrown.
  2. Temporary nodes cannot have children. A KeeperException is thrown if a child node is created for a temporary node.
  3. The life cycle of the temporary node is bound to the client session. Any temporary nodes created by the client are removed if the client session fails (not necessarily if the client is disconnected from Zookeeper).
  4. Byte [] data the maximum amount of data allowed is 1MB (1,048,576 bytes). If it exceeds, KeeperExecption is thrown.

Run the code to create the node:

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

The node is successfully created based on logs:

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_demoCopy the code

On the server, the /zk_demo node is successfully created.

[zk: 127.0.0.1:2181(CONNECTED) 21] ls / [Zookeeper, zk_demo] 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 = 0Copy the code

3.3 get

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 thrownif 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.
Copy the code

Throw KeeperException.NoNode if the specified path does not exist.

Run:

    @Test
    public void testGet(a) 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("{} message: {}", ZNODE_PATH, new String(data1) );
        LOGGER.info("{} message: {}", ZNODE_PATH_PARENT, new String(data2) );
        LOGGER.info("{} message: {}", ZNODE_PATH_CHILDREN, new String(data3) );
    }
Copy the code

Results:

13:51:00. [the main] INFO 288 com. Yuanrengu. Demo. ZooKeeperDemo - / zk_demo information: Anna2019 13:51:00. [the main] INFO 288 com. Yuanrengu. Demo. ZooKeeperDemo - / app1 information: Anna2019 13:51:00. [the main] INFO 289 com. Yuanrengu. Demo. ZooKeeperDemo - / app1 / app1_1 information: anna2020Copy the code

The 3.4 update

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 specifiedCopy the code

The following points should be paid attention to:

  1. If the version is -1, it indicates that all versions of the node in the specified path are adapted.
  2. If the specified path node does not exist behind KeeperException. NoNode abnormalities, the node does not have the incoming version, will throw KeeperException. BadVersion anomalies.
  3. Byte [] data the maximum amount of data allowed is 1MB (1,048,576 bytes). If it exceeds, KeeperExecption is thrown.

Run:

    @Test
    public void testSet(a) 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));
    }
Copy the code

You can see that the data has been updated:

15:46:16. [the main] INFO 472 com. Yuanrengu. Demo. ZooKeeperDemo - yuanrenguCopy the code

The updated interface refers to the concept of version. When version -1 is mentioned above, it means that all versions of the specified path node are adapted. Every time node setData version will add 1, update the specified version does not exist to KeeperException. BadVersion anomalies. Let’s take a test:

    @Test
    public void testSetForVersion(a) throws KeeperException, InterruptedException {
        String pathVersion = "/versionDemo";
        zk.create(pathVersion, "yuanrengu2019".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        Stat stat = zk.setData(pathVersion, "yuanrengu2020".getBytes(), -1);
        LOGGER.info("============1111111 start======================");
        LOGGER.info(String.valueOf(stat));
        LOGGER.info("version:{}", stat.getVersion());
        byte[] data1 = zk.getData(pathVersion, false.null);
        LOGGER.info("data1:{}".new String(data1));
        LOGGER.info("============1111111 end======================");

        Stat stat2 = zk.setData(pathVersion, "yuanrengu2021".getBytes(), stat.getVersion());
        LOGGER.info("============222222 start======================");
        LOGGER.info(String.valueOf(stat2));
        LOGGER.info("version2:{}", stat2.getVersion());
        byte[] data2 = zk.getData(pathVersion, false.null);
        LOGGER.info("data2:{}".new String(data2));
        LOGGER.info("============222222 end======================");

        Stat stat3 = zk.setData(pathVersion, "yuanrengu2022".getBytes(), stat.getVersion());
        LOGGER.info("============3333333 start======================");
        LOGGER.info(String.valueOf(stat3));
        LOGGER.info("version3:{}", stat3.getVersion());
        byte[] data3 = zk.getData(pathVersion, false.null);
        LOGGER.info("data3:{}".new String(data3));
        LOGGER.info("============3333333 end======================");
    }
Copy the code

The running results are as follows:

[main - SendThread 09:56:00. 931 (2181) 106.12.111.172:] the DEBUG org. Apache. Zookeeper. ClientCnxn - Reading the reply Sessionid: 0 x1014dce26220008, packet: : clientPath: null serverPath: null finished: false header: : 1, 5 replyHeader: : 1128490005, 0 request: : '/ versionDemo, # 7975616 e72656e677532303230, 1 response: : S 12884901996128490005157720627, 15157720609, 18,1,0,0,0,13,0,12884901996} {09:56:00. 940 (main) INFO Com. Yuanrengu. Demo. ZooKeeperDemo - = = = = = = = = = = = = 1111111 start = = = = = = = = = = = = = = = = = = = = = = 09:56:00. [the main] 941 INFO Com. Yuanrengu. Demo. 18,1,0,0,0,13,0,12884901996 ZooKeeperDemo - 12884901996128490005157720627-15157720609 09:56:00. [the main] INFO 942 com. Yuanrengu. Demo. ZooKeeperDemo - version: 1 09:56:00. 971 [main - SendThread (106.12.111.172:2181)] the DEBUG org. Apache. The zookeeper. ClientCnxn - Reading the reply Sessionid: 0 x1014dce26220008, packet: : clientPath: null serverPath: null finished: false header: : 2, 4 replyHeader: : 2128490005, 0 request: : '/ versionDemo, F the response... # 7975616 e72656e677532303230, s 12884901996128490005157720627, 15157720609, 18,1,0,0,0,13,0,12884901996} {09:56:00. 971 [the main] INFO com. Yuanrengu. Demo. ZooKeeperDemo - data1: yuanrengu2020 09:56:00. [the main] 971 INFO Com. Yuanrengu. Demo. ZooKeeperDemo - = = = = = = = = = = = = 1111111 end = = = = = = = = = = = = = = = = = = = = = = 09:56:00. 988 [main - SendThread (106.12.111.172:2181)] the DEBUG org. Apache. The zookeeper. ClientCnxn - Reading the reply Sessionid: 0 x1014dce26220008, packet: : clientPath: null serverPath: null finished: false header: : 3, 5 replyHeader: : 3128490006, 0 request: : '/ versionDemo, # 7975616 e72656e677532303231, 1 response: : S 15157720610 02,2,0,0,0,13,0,12884901996 {12884901996128490006157720627} 09:56:00. 988 (main) INFO Com. Yuanrengu. Demo. ZooKeeperDemo - = = = = = = = = = = = = 222222 start = = = = = = = = = = = = = = = = = = = = = = 09:56:00. [the main] 988 INFO Com. Yuanrengu. Demo. The 15157720610-02,2,0,0,0,13,0,12884901996 ZooKeeperDemo - 12884901996128490006157720627 09:56:00. [the main] INFO 990 com. Yuanrengu. Demo. ZooKeeperDemo - version2:2 09:56:01. 017 [main - SendThread (106.12.111.172:2181)] the DEBUG org. Apache. The zookeeper. ClientCnxn - Reading the reply Sessionid: 0 x1014dce26220008, packet: : clientPath: null serverPath: null finished: false header: : 4, 4 replyHeader: : 4128490006, 0 request: : '/ versionDemo, F the response... # 7975616 e72656e677532303231, s 15157720610 02,2,0,0,0,13,0,12884901996 {12884901996128490006157720627} 09:56:01. 017 [the main] INFO com. Yuanrengu. Demo. ZooKeeperDemo - data2: yuanrengu2021 09:56:01. [the main] 017 INFO Com. Yuanrengu. Demo. ZooKeeperDemo - = = = = = = = = = = = = 222222 end = = = = = = = = = = = = = = = = = = = = = = 09:56:01. 037 [main - SendThread (106.12.111.172:2181)] the DEBUG org. Apache. The zookeeper. ClientCnxn - Reading the reply Sessionid: 0 x1014dce26220008, packet: : clientPath: null serverPath: null finished: false header: : 5, 5 replyHeader: : 5128490007-103 request: : '/ versionDemo, # 7975616 e72656e677532303232, 1 response: : org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for /versionDemo at org.apache.zookeeper.KeeperException.create(KeeperException.java:122) at org.apache.zookeeper.KeeperException.create(KeeperException.java:54) at org.apache.zookeeper.ZooKeeper.setData(ZooKeeper.java:2384)Copy the code

The test code carried out three setData operations, the first setData passed in version -1, after the success of version 1; When setData is passed in the second time, version 1 is passed in. After success, version 2 is passed in. Incoming version is 1, when the third setData. At that moment, just throw the KeeperException BadVersion anomalies. If version -1 is passed in the third time, the update succeeds.

3.5 delete

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
Copy the code

A node may contain child nodes. When deleting a node, note the following:

  1. If the version is -1, it indicates that all versions of the node in the specified path are adapted.
  2. If the specified path node does not exist behind KeeperException. NoNode abnormalities, the node does not have the incoming version, will throw KeeperException. BadVersion anomalies.
  3. If a node has children, a KeeperException.NotEmpty exception will be thrown when the parent node is removed.

In ZooKeeper, only child nodes can be deleted. If a node has one or more child nodes, the node cannot be deleted directly. All child nodes must be deleted first.

/app1 has a child node, let’s delete it:

    /** * Delete the parent node * that contains children@throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testDeleteHasChildrenZnode(a) throws KeeperException, InterruptedException {
        // Specify the version to be deleted. -1 indicates that all versions are to be deleted
        zk.delete(ZNODE_PATH_PARENT, -1);
    }
Copy the code

You can see the log:

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)Copy the code

4 summarizes

Above, we have implemented the test of adding, deleting, changing and searching nodes. In the following chapters, there will be more interesting uses, such as implementing distributed locks and configuring centers.

Based on the above analysis, several points for attention are summarized:

  1. Node hasSeven kinds of form:
  • PERSISTENT: PERSISTENT nodes (also known as PERSISTENT nodes) are not deleted automatically at the end of a session.
  • PERSISTENT_SEQUENTIAL: a persistent node with monotonically increasing sequential numbers that is not automatically deleted at the end of a session.
  • EPHEMERAL: The temporary node that is automatically deleted as the session ends.
  • EPHEMERAL_SEQUENTIAL: A temporary node with a monotonically increasing sequential number that is automatically deleted as the session ends.
  • CONTAINER: container node, used for Leader, Lock and other special purposes. When the container node does not have any child nodes, the container will be a candidate node to be deleted by the server at some point in the future.
  • PERSISTENT_WITH_TTL: a persistent node with TTL (time-to-live). If the node has not been updated within the TTL and has no child nodes, it will be deleted automatically.
  • PERSISTENT_SEQUENTIAL_WITH_TTL: a persistent node with TTL (time-to-live) and monotonically increasing sequence number. If the node has not been updated within the TTL and has no child nodes, it will be deleted automatically.
  1. Temporary nodes cannot have children. A KeeperException is thrown if a child node is created for a temporary node.
  2. The life cycle of the temporary node is bound to the client session. Any temporary nodes created by the client are removed if the client session fails (not necessarily if the client is disconnected from Zookeeper).
  3. Byte [] data the maximum amount of data allowed is 1MB (1,048,576 bytes).