Mind mapping

preface

In many cases, ZooKeeper can be found in various framework applications, such as Kafka middleware, Dubbo framework, Hadoop, etc. Why do you see ZooKeeper everywhere?

What is ZooKeeper

ZooKeeper is a distributed service coordination framework, providing distributed data consistency solutions, based on ZooKeeper data structure, Watcher, election mechanism and other features, can achieve data publish/subscribe, soft load balancing, naming service, unified configuration management, distributed lock, cluster management and so on.

Why use ZooKeeper

ZooKeeper ensures that:

  • Update requests are made in sequence. Update requests from the same client are executed in the order in which they are sent
  • Data update atomicity. A data update either succeeds or fails
  • Globally unique data view. Client Data views are consistent regardless of which server the client is connected to
  • Real time. Within a certain time range, the data read by the client is the latest

Data structure

The data structure of ZooKeeper is similar to that of the Unix file system. ZooKeeper is generally regarded as a tree. Each node is called a ZNode, and each ZNode can store 1 MB of data by default. Each ZNode can be identified by a unique path. As shown below:

When creating a ZNode, you can specify the following four types:

  • PERSISTENT ZNode. The creation is not deleted even if the client is disconnected from the server. The creation disappears only when the client is deleted.
  • PERSISTENT_SEQUENTIAL, serial number ZNode. As with persistent nodes, they are not deleted after disconnection, and the number of ZNodes is automatically increased.
  • EPHEMERAL is the temporary ZNode. When the client disconnects from the server, the ZNode will be deleted.
  • EPEMERAL_SEQUENTIAL, temporary sequential numbered ZNode. As with temporary nodes, disconnections are removed and the ZNode number is automatically increased.

4. Monitoring notification mechanism

Watcher is a mechanism implemented based on the observer pattern. If we need to implement notification when a ZNode changes, we can use the Watcher listener.

The client registers zNodes that need to receive notifications with ZooKeeper by setting monitoring points (watcher). ZooKeeper sends messages to the client when zNodes change.

This notification mechanism is one-off. Once Watcher is triggered, ZooKeeper is removed from the corresponding store. If you need to constantly monitor ZNode changes, you can set up a new Watcher to register with ZooKeeper after receiving notifications.

There are many types of monitoring points, such as monitoring ZNode data changes, monitoring ZNode child node changes, and monitoring ZNode creation or deletion.

5. Election mechanism

ZooKeeper is a highly available application framework because ZooKeeper supports clustering. When the ZooKeeper server is in cluster state, the configuration file does not specify Master and Slave. Instead, the ZooKeeper server conducts internal elections when it is initialized. One ZooKeeper server serves as the Leader and multiple ZooKeeper servers serve as followers, and the half availability rule is followed.

In order to save cost, the number of servers in a cluster is usually set to an odd number.

If the connection with the Leader cannot be maintained for a long time at runtime, a new Leader will be elected again to ensure the availability of the service.

Six, the beginning of experience

Download ZooKeeper from the official website. I’m using version 3.3.6.

Decompress the zoo_sample. CFG file in the /conf directory and rename it zoo.cfg.

CFG dataDir in zoo. CFG and create the corresponding directory:

Zkserver. CMD: /bin/zkserver. CMD /bin/zkserver. CMD

If the startup is successful, you should see this dialog box:

For visual interface, I recommend using ZooInspector, which is easy to operate:

6.1 Connecting to ZooKeeper Using Java

First we introduce Maven dependencies:

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.6</version>
</dependency>
Copy the code

Next we write a Main method to do this:

    // Connection address and port number
    private static final String SERVER_HOST = "127.0.0.1:2181";

    // Session timeout time
    private static final int SESSION_TIME_OUT = 2000;

    public static void main(String[] args) throws Exception {
        // Parameter 1: server address and port number
        // Parameter two: timeout period
        // Parameter three: listener
        ZooKeeper zooKeeper = new ZooKeeper(SERVER_HOST, SESSION_TIME_OUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                // Get the status of the event
                Event.KeeperState state = watchedEvent.getState();
                // Check whether it is a connection event
                if (Event.KeeperState.SyncConnected == state) {
                    Event.EventType type = watchedEvent.getType();
                    if (Event.EventType.None == type) {
                        System.out.println("Zk client connected..."); }}}}); zooKeeper.create("/java"."Hello World".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("ZNode added successfully");
        zooKeeper.close();
    }
Copy the code

Create a persistent ZNode with path/Java and value “Hello World” :

7. Overview of API

7.1 create

public String create(final String path, byte data[], List<ACL> acl, CreateMode createMode)
Copy the code

Parameter Description:

  • The path ZNode path
  • Data Data stored in a ZNode
  • Acl Acl permission control
  • CreateMode ZNode type

ZooKeeper defines three common ACL permissions in the zoodefs. Ids class:

/** * This is a completely open ACL. * This is a completely open ACL. Any connected client can operate This property
public final ArrayList<ACL> OPEN_ACL_UNSAFE = new ArrayList<ACL>(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));

/** * This ACL gives the creators authentication id's all permissions. */
public final ArrayList<ACL> CREATOR_ALL_ACL = new ArrayList<ACL>(Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));

/** * This ACL gives the world the ability to read
public final ArrayList<ACL> READ_ACL_UNSAFE = new ArrayList<ACL>(Collections.singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));
Copy the code

CreateMode is one of the four ZNode types mentioned earlier:

public enum CreateMode {
    /** * persistent ZNode */
    PERSISTENT (0.false.false),
    /** * persistence automatically adds sequence number ZNode */
    PERSISTENT_SEQUENTIAL (2.false.true),
    /** * temporary ZNode */
    EPHEMERAL (1.true.false),
    /** * temporarily add sequence number ZNode */
    EPHEMERAL_SEQUENTIAL (3.true.true);
}
Copy the code

7.2 the query

// Synchronously obtain node data
public byte[] getData(String path, boolean watch, Stat stat){
    ...
}

// Get node data asynchronously
public void getData(final String path, Watcher watcher, DataCallback cb, Object ctx){... }Copy the code

The stat argument in the getData() method is used to receive the returned node description:

public byte[] getData(final String path, Watcher watcher, Stat stat){
    / / to omit...
    GetDataResponse response = new GetDataResponse();
    // Sends a request to the ZooKeeper server and obtains a response
    ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
    if(stat ! =null) {
        // Assign the response Stat to the incoming StatDataTree.copyStat(response.getStat(), stat); }}Copy the code

GetData using synchronous getData() :

    // Data description, including version number, ACL permission, child node information, and so on
    Stat stat = new Stat();
    The result is byte[] data, and the getData() method copies the description to the stat object underneath
    byte[] bytes = zooKeeper.getData("/java".false, stat);
    // Print the result
    System.out.println("ZNode data:" + new String(bytes));//Hello World
    System.out.println("Got datSpanning version number :" + stat.getVersion());// The default data version is 0
Copy the code

The 7.3 update

public Stat setData(final String path, byte data[], int version){... }Copy the code

Note that the third parameter version uses the CAS mechanism to prevent multiple clients from updating node data at the same time, so the version number needs to be passed in the update. Each update will increase the version number by 1. If the server receives the version number and finds that it is inconsistent, it will throw an exception.

Therefore, you need to query the version number before updating, otherwise you do not know the current version number, you can not update:

    // Obtain node description
    Stat stat = new Stat();
    zooKeeper.getData("/java".false, stat);
    System.out.println("Update ZNode data...");
    // Update operation, pass path, update value, version number three parameters, return the new description
    Stat setData = zooKeeper.setData("/java"."fly!!!".getBytes(), stat.getVersion());
    System.out.println(The updated version number is: + setData.getVersion());// The updated version is: 1
Copy the code

After the update, the version number has been increased:

If the version parameter is “-1”, it tells the ZooKeeper server that the client needs to update the data based on the latest version. But -1 is not a legal version number, but an identifier.

7.4 delete

public void delete(final String path, int version){... }Copy the code
  • Path Path of the node to be deleted
  • Version version number

Here we also need to pass in the version number, which can be obtained by calling getData(), as simple as this:

Stat stat = new Stat();
zooKeeper.getData("/java".false, stat);
/ / delete the ZNode
zooKeeper.delete("/java", stat.getVersion());
Copy the code

7.5 watcher mechanism

As mentioned in the third point above, ZooKeeper can use notification monitoring mechanism. When ZNode changes, it will receive notification messages and process them. With the Watcher mechanic, ZooKeeper can do a lot of things. How to use it?

Generally speaking, ZooKeeper’s notification monitoring mechanism can be divided into three processes:

① The client registers the Watcher ② the server processes the Watcher ③ The client calls back the Watcher client.

There are four ways to register watcher: new ZooKeeper(), getData(), exists(), and getChildren(). Here’s how to register watcher using the exists() method:

First we need to implement the Watcher interface and create a new listener:

public class MyWatcher implements Watcher {
    @Override
    public void process(WatchedEvent event) {
        // Get the event type
        Event.EventType eventType = event.getType();
        // Notification status
        Event.KeeperState eventState = event.getState();
        // Node path
        String eventPath = event.getPath();
        System.out.println("Type of event monitored :" + eventType.name());
        System.out.println("Monitored notification status :" + eventState.name());
        System.out.println("ZNode listened path :"+ eventPath); }}Copy the code

Then call the exists() method to register a listener:

zooKeeper.exists("/java".new MyWatcher());
// The listener is triggered to update the ZNode data
zooKeeper.setData("/java"."fly".getBytes(), -1);
Copy the code

You can then see the printed message on the console:

EventType is the Event type. We can determine the Event type and perform related business processing according to the notification status of Event.KeeperState.

EventType, KeeperState, EventType, KeeperState

The event type is an enumeration
public enum EventType {
    None (-1),/ / no
    NodeCreated (1),// The data node Watcher is listening to is created
    NodeDeleted (2),// The data node monitored by Watcher is deleted
    NodeDataChanged (3),// The contents of the data node monitored by Watcher are changed
    NodeChildrenChanged (4);// The list of children of the data node monitored by Watcher has changed
}

// Notification status is also an enumeration
public enum KeeperState {
    Unknown (-1),// Attributes expire
    Disconnected (0),// The client is disconnected from the server
    NoSyncConnected (1),// Attributes expire
    SyncConnected (3),// The client is properly connected to the server
    AuthFailed (4),// Authentication failed
    ConnectedReadOnly (5),// Return this state to the client, which can only handle read requests
    SaslAuthenticated(6),// When the server uses SASL for verification
    Expired (-112);// The session session is invalid
}
Copy the code

7.5.1 Features of Watcher

  • Once and for all. Once watcher is triggered, the ZK is removed from the corresponding store.
    zooKeeper.exists("/java".new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("I am a listener for the exists() method"); }});// The listener is triggered to update the ZNode data
    zooKeeper.setData("/java"."fly".getBytes(), -1);
    // Attempts to trigger the listener a second time
    zooKeeper.setData("/java"."spring".getBytes(), -1);
Copy the code

  • Serial execution. The process of the client Watcher callback is a serial synchronization process to ensure order.
    zooKeeper.exists("/java".new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("I am a listener for the exists() method"); }}); Stat stat =new Stat();
    zooKeeper.getData("/java".new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            System.out.println("I'm a listener for the getData() method.");
        }
    }, stat);
    // The listener is triggered to update the ZNode data
    zooKeeper.setData("/java"."fly".getBytes(), stat.getVersion());
Copy the code

If the result is printed, the listener of the exists() method is called first, and then the listener of the getData() method is called. Because the exists() method is registered first.

  • Lightweight. WatchedEvent is the smallest notification unit of ZK’s entire Watcher notification mechanism. WatchedEvent consists of three parts: notification status, event type, and node path. Watcher notifications simply tell clients what happened, not what happened.

Write in the last

I remember Li Yongle, the UP host of STATION B, said that only when you make more people’s lives better, can your own life become better.

This quote was one of the reasons I started writing tech Share this year. I hope you find this article useful

Famous aviator Ma teacher said: return to the city is charged, and like is free ~