ZooKeeper commands and JavaAPI operations

ZooKeeper data model

  • ZooKeeper is a tree directory service, its data model is very similar to Uiix's file directory tree, and has a hierarchical structure.
  • Each node here is called: ZNode, and each node will save its own data and node information.
  • Nodes can have child nodes, and a small amount (1MB) of data is allowed to be stored under the node.
  • Nodes can be divided into four categories:
    • PEFSISTENT persistent node
    • Ephemeral ephemeral node: -e
    • PERSISTENT_SEQUENTIAL persistent sequential node: -s
    • EPHEMERAL_SEQUENTIAL ephemeral sequential nodes: -es

Common Commands of ZooKeeper Server

  • Start the ZooKeeper service:./zkServer.sh start
  • View ZooKeeper service:./zkServer.sh status
  • Stop the ZooKeeper service:./zkServer.sh stop
  • Restart the ZooKeeper service:./zkServer.sh restart

ZooKeeper client commands

  • ./zkCli.sh -server localhost:2181 to connect to the server, if it is a single machine, you can omit it.
  • ls [/] : View the child nodes under the specified node
  • create [/app] [hrbu]: Create a child node named /app1 and store data.
  • get [/app] : Get the data under the node.
  • set [/app] [hrbu]: set data for the specified node
  • delete [/app]: Delete the specified node ps: This command cannot delete the node with child nodes. If you want to delete the node with child nodes, you can use the deleteall [/app] command.
  • quit disconnect
  • help View command help
  • create -e [/app] Create a temporary node, it will be deleted when the session is closed
  • create -s [/app] Create a sequential node
  • create -es [/app] create a temporary sequence node
  • ls -s [/app] View the detailed information of the node

Use the Curator API to operate Zookeeper

establish connection

@Test
public void testConnect() {
    
    
    //重试策略
    ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000, 10);
    //第一种方式
    CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.130.120:2181", 60 * 1000, 15 * 1000, retry);

    //第二种方式
    CuratorFramework client1 = CuratorFrameworkFactory.builder().connectString("192.168.130.120:2181")
        .sessionTimeoutMs(60 * 1000)
        .connectionTimeoutMs(15 * 1000)
        .retryPolicy(retry).namespace("hrbu").build();
    //开启连接
    client.start();
}

Interpretation of parameters

  • connectString – list of servers to connect to (ZooKeeper address)
    sessionTimeoutMs – session timeout (session timeout)
    connectionTimeoutMs – connection timeout (connection timeout)
    retryPolicy – ​​retry policy to use (retry policy)

insert image description here

There are default values ​​for session timeout and connection timeout.

The second chain programming method can specify a workspace, and all operations under this client will use this workspace as the root directory.

Notice

If you are using a cloud server, you need to open the specified port

firewall-cmd --zone=public --add-port=2181/tcp --permanentopen port

firewall-cmd --zone=public --list-portsView open ports

systemctl restart firewalldRestart the firewall to take effect

Finally, don’t forget to add the port in the server’s security group and open port 2181

add node

@Test
public void testCreate1() throws Exception {
    
    
    //基本创建
    CreateBuilder createBuilder = client.create();
    //创建时不指定数据,会将当前客户端ip存到里面
    createBuilder.forPath("/app1");
    //指定数据
    createBuilder.forPath("/app2", "hello".getBytes());
}

@Test
public void testCreate2() throws Exception {
    
    
    CreateBuilder createBuilder = client.create();

    //设置节点类型,默认的类型是持久化
    //CreateMode是枚举类型
    createBuilder.withMode(CreateMode.EPHEMERAL).forPath("/app3");
}

@Test
public void testCreate3() throws Exception {
    
    
    CreateBuilder createBuilder = client.create();
    //创建多级节点,如果父节点不存在,则创建父节点。
    createBuilder.creatingParentContainersIfNeeded().forPath("/app4/app4_1");
}

query node

@Test
public void testGet() throws Exception {
    
    
    //查询数据
    byte[] bytes = client.getData().forPath("/app1");
    System.out.println(new String(bytes));

    //查询子节点
    List<String> strings = client.getChildren().forPath("/app4");
    strings.forEach(System.out::println);

    //查询节点状态信息
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app1");
    System.out.println(stat);
}

modify node

@Test
public void testSet() throws Exception {
    
    
    //修改数据
    client.setData().forPath("/app1","hrbu".getBytes());

    //根据版本修改
    int version  = 0;
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app1");
    version = stat.getVersion();

    client.setData().withVersion(version).forPath("/app1", "HRBU".getBytes());
}

delete node

@Test
public void testDelete() throws Exception {
    
    
    //删除单个节点
    client.delete().forPath("/app4/app4_1");

    //删除带有子节点的节点
    client.delete().deletingChildrenIfNeeded().forPath("/app4");

    //强制删除
    client.delete().guaranteed().forPath("/app4");

    //回调
    client.delete().guaranteed().inBackground(new BackgroundCallback() {
    
    
        @Override
        public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
    
    
            System.out.println("执行删除操作");
        }
    }).forPath("/app4");

}

Watch event monitoring

  • Zookeeper allows users to register some Watchers on designated nodes, and when some specific events are triggered, the ZooKeeper server will notify interested clients of the event. This mechanism is an important feature of ZooKeeper to implement distributed coordination services.

  • ZooKeeper introduces the Watcher mechanism to implement the publish/subscribe function, which allows multiple subscribers to monitor an object at the same time. When an object's own state changes, all subscribers will be notified.

  • ZooKeeper natively supports event monitoring by registering Watcher, but it is not particularly convenient to use, requiring developers to register Watcher repeatedly, which is cumbersome.

  • Curator introduces Cache to time-limit the monitoring of Zookeeper server events.

  • ZooKeeper provides three Watchers:

    • NodeCache: just listen to a specific node.
    • PathChildrenCache: Monitor the child nodes of a Node.
    • TreeCache: It can monitor all nodes on the entire tree, similar to the combination of PathChildrenCache and NodeCache.

NodeCache

@Test
public void testNodeCache() throws Exception {
    
    
    //NodeCache:指定一个节点注册监听器

    //创建NodeCache对象
    final NodeCache nodeCache = new NodeCache(client, "/app1");
    //注册监听
    nodeCache.getListenable().addListener(new NodeCacheListener() {
    
    
        @Override
        public void nodeChanged() throws Exception {
    
    
            System.out.println("app1节点发生变化");

            //获取修改节点后的数据
            byte[] data = nodeCache.getCurrentData().getData();
            System.out.println("变化后的节点:"+new String(data));
        }
    });
    //开启监听,如果为true,则开启则开启监听,加载缓冲数据
    nodeCache.start(true);
}

PathChildrenCache

@Test
public void testPathChildrenCache() throws Exception {
    
    
    //PathChildrenCache:监听某个节点的所有子节点
    //创建监听对象
    PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/hrbu", true);

    //绑定监听器
    pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
    
    
        @Override
        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
    
    
            System.out.println("子节点发生变化");
            System.out.println(pathChildrenCacheEvent);
            //监听子节点的数据变更,并且得到变更后的数据

            //获取类型
            PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();

            //判断类型
            if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
    
    
                //获取数据
                byte[] data = pathChildrenCacheEvent.getData().getData();
                System.out.println(new String(data));
            }
        }
    });

    //开启
    pathChildrenCache.start();
}

TreeCache

@Test
public void testTreeCache() throws Exception {
    
    
    //创建监听器
    TreeCache treeCache = new TreeCache(client, "/");

    //注册监听
    treeCache.getListenable().addListener(new TreeCacheListener() {
    
    
        @Override
        public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
    
    
            System.out.println("节点发生变化");
            System.out.println(treeCacheEvent);
        }
    });

    //开启
    treeCache.start();

}

Distributed lock implementation

overview

  • When we develop stand-alone applications and involve concurrent synchronization, we often use synchronized or lock methods to solve the problem of code synchronization between multiple threads. At this time, multiple threads are running under the same JVM without any problems. .
  • But when our application works in a distributed cluster, it belongs to the working environment under multiple JVMs, and it is no longer possible to solve the synchronization problem through multi-threaded locks between JVMs.
  • Then a more advanced locking mechanism is needed to deal with data synchronization between cross-machine processes, which is a distributed lock.

Zookeeper distributed lock principle

  • Core idea: When the client wants to acquire a lock, it creates a node, and after using the lock, deletes the node.
    • 1. When the client acquires the lock, a temporary sequence node is created under the lock node.
    • 2. Then obtain all the child nodes under the lock. After the client obtains all the child nodes, if it finds that the serial number of the child node it created is the smallest, then it is considered that the client has obtained the lock. After using the lock, delete the node.
    • 3. If you find that the node you created is not the smallest among all the child nodes of the lock, it means that you have not acquired the lock. At this time, the client needs to find the node that is smaller than itself, and register an event listener for it to listen for deletion events.
    • 4. If it is found that the node smaller than itself is deleted, the Watcher of the client will receive a corresponding notification. At this time, it will judge again whether the node created by itself has the smallest serial number among the lock child nodes. If it is, the lock has been acquired. If not Then repeat the above steps to continue to obtain a node smaller than itself and register to monitor.

Curator implements distributed lock API

  • There are five locking schemes in Curator:

    • InterProcessSemaphoreMutex: distributed exclusive lock (non-reentrant lock)
    • InterProcessMutex: Distributed reentrant exclusive lock
    • InterProcessReadWriteLock: distributed read-write lock
    • InterProcessMultiLock: A container for managing multiple locks as a single entity
    • InterProcessSemaphoreV2: shared semaphore

the case

package com.hrbu.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.TimeUnit;

public class Ticket12306 implements Runnable{
    
    

    private int tickets = 10;//数据库的票数

    private InterProcessMutex lock ;


    public Ticket12306(){
    
    
        //重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.130.32.75:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy)
                .build();
        //开启连接
        client.start();
        lock = new InterProcessMutex(client,"/lock");
    }

    @Override
    public void run() {
    
    

        while(true){
    
    
            //获取锁
            try {
    
    
                lock.acquire(3, TimeUnit.SECONDS);
                if(tickets > 0){
    
    
                    System.out.println(Thread.currentThread()+":"+tickets);
                    Thread.sleep(100);
                    tickets--;
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                //释放锁
                try {
    
    
                    lock.release();
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }
        }
    }
}

package com.hrbu.curator;



public class LockTest {
    
    


    public static void main(String[] args) {
    
    
        Ticket12306 ticket12306 = new Ticket12306();

        //创建客户端
        Thread t1 = new Thread(ticket12306,"携程");
        Thread t2 = new Thread(ticket12306,"飞猪");

        t1.start();
        t2.start();
    }
}

Guess you like

Origin blog.csdn.net/weixin_53236380/article/details/129429126