ZooKeeper之Java API的基本使用以及常见应用场景的实现

本文详细介绍了如何使用ZooKeeper的Java API进行节点操作,包括创建、读取、修改和删除节点,以及实现分布式共享锁、配置管理和同步队列。还探讨了ZooKeeper在集群高可用中的应用。
摘要由CSDN通过智能技术生成

Java API的基本使用

添加依赖

<dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.7.0</version>
        </dependency>
复制代码

创建ZK连接

@SpringBootTest
public class ZKTest {

    /**
     * 获取zookeeper连接时所需要的服务器连接信息,格式为主机名:端口号;多个服务使用“,”分割
     */
    public final String CONNECT_STRING = "127.0.0.1:2181";

    /**
     * 请求会话超时时长
     */
    public final int SESSIONT_IMEOUT = 5000;

    private ZooKeeper zk;
    
    private String path = "/zk";
    
    private String sonPath = "/zk/son";
    
    private String value = "zk_Data";

    /**
     * 获取ZooKeeper链接
     *
     * @return
     * @throws Exception
     */
    @Before
    public void getZKConnection() throws Exception {
        zk = new ZooKeeper(CONNECT_STRING, SESSIONT_IMEOUT, null);
    }

    /**
     * 关闭ZK连接
     *
     * @throws InterruptedException
     */
    @After
    public void closeZKConnection() throws InterruptedException {
        zk.close();
    }
}
复制代码

创建持久不带序列编号的节点

@Test
    public void createZKNode1() throws Exception {
        // 四个参数: 节点路径,节点数据,权限信息,节点的类型
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }
复制代码

创建持久带序列编号的节点

@Test
    public void createZKNode2() throws Exception {
        // 四个参数: 节点路径,节点数据,权限信息,节点的类型
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
    }
复制代码

创建临时不带序列编号的节点

@Test
    public void createZKNode3() throws Exception {
        // 四个参数: 节点路径,节点数据,权限信息,节点的类型
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }
复制代码

创建临时带序列编号的节点

@Test
    public void createZKNode4() throws Exception {
        // 四个参数: 节点路径,节点数据,权限信息,节点的类型
        zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    }
复制代码

查看节点数据

@Test
    public void getZNodeData() throws Exception {
        String znodeData = new String(zk.getData(path, false, null));
        System.out.println("查看节点数据:" + znodeData);
    }
复制代码

修改节点数据

@Test
    public void updateZNodeData() throws Exception {
        String value="update_data";
        zk.setData(path, value.getBytes(), -1);
        String newData = new String(zk.getData(path, false, null));
        if (newData.equals(value)) {
            System.out.println("修改节点数据: " + true);
        } else {
            System.out.println("修改节点数据: " + false);
        }
    }
复制代码

判断节点是否存在

@Test
    public void existsZNode() throws Exception {
        boolean existsZNode = (zk.exists(path, false) != null) ? true : false;
        System.out.println("判断节点是否存在: " + existsZNode);
    }
复制代码

查看节点的子节点列表

@Test
    public void getChildrenZNodes() throws Exception {
        zk.create(sonPath, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        List<String> children = zk.getChildren(path, false);
        for (String child : children) {
            System.out.println("查看节点的子节点列表: " + child);
        }
    }
复制代码

删除节点

@Test
    public void deleteZNode() {
        try {
            zk.delete(path, -1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
        System.out.println("删除znode节点成功");
    }
复制代码

级联删除节点

@Test
    public void deleteAllNode() throws Exception {
        zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        zk.create(sonPath, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        this.deleteAllNode(this.path);
    }

    /**
     * 删除一个节点,不管有有没有任何子节点
     *
     * @return
     * @throws Exception
     */
    public void deleteAllNode(String path) throws Exception {
        if (zk.exists(path, null) == null) {
            System.out.println("该路径 " + path + " 不存在");
        }

        List<String> children = zk.getChildren(path, null);
        if (children.size() == 0) {
            zk.delete(path, -1);
        } else {
            // 删除child路径下的所有子节点,但是并不删除child节点
            for (String child : children) {
                String deletePath = path + "/" + child;
                deleteAllNode(deletePath);
            }
            // 节点所有子节点删除之后,直接当前节点
            zk.delete(path, -1);
        }
    }
复制代码

级联创建节点

@Test
    public void createAllNode() throws Exception {
        this.createAllNode(this.sonPath);
    }

    /**
     * 级联创建任意节点
     *
     * @throws Exception
     */
    public boolean createAllNode(String znodePath) throws Exception {
        // 判断该节点是否存在,如果存在,则不创建
        if (zk.exists(znodePath, null) != null) {
            return false;
        } else {
            try {
                // 直接创建,捕捉异常,根据对应的异常如果是发现没有父节点,那么就创建父节点
                zk.create(znodePath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            } catch (KeeperException e) {
                // 截取父节点
                String parentPath = znodePath.substring(0, znodePath.lastIndexOf("/"));
                // 创建父节点
                createAllNode(parentPath);
                try {
                    // 父节点创建好后,创建该节点
                    zk.create(znodePath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                } catch (KeeperException e1) {
                    e1.printStackTrace();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
复制代码

清空子节点

@Test
    public void clearChildNode() throws Exception {
        this.clearChildNode(this.path);
    }

    /**
     * 清空子节点
     *
     * @throws Exception
     */
    public boolean clearChildNode(String path) throws Exception {
        List<String> children = zk.getChildren(path, null);
        for (String child : children) {
            String childNode = path + "/" + child;
            if (zk.getChildren(childNode, null).size() != 0) {
                clearChildNode(childNode);
            }
            zk.delete(childNode, -1);
        }
        return true;
    }
复制代码

实现节点监听

ZooKeeper可以作为注册中心,原因就在于其可以实现节点监听。

比如:在分布式系统中,一个服务启动后就可以向ZK注册中心的某个节点注册,记录服务器的信息,服务下线则删除节点下记录的服务器信息。

创建监听节点

private String sonPath = "/watch_zk/son";
    
    private String value = "zk_Data";
    
    private String watchPath = "/watch_zk";

    @Test
    public void createWatchNode() throws Exception {
        zk.create(watchPath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }
复制代码

实现监听

public class ZKWatch {

    /**
     * 获取zookeeper连接时所需要的服务器连接信息,格式为主机名:端口号;多个服务使用“,”分割
     */
    public static final String CONNECT_STRING = "127.0.0.1:2181";

    /**
     * 请求会话超时时长
     */
    public static final int SESSIONT_IMEOUT = 5000;

    private static ZooKeeper zk;

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        String watchPath = "/watch_zk";
        zk = new ZooKeeper(CONNECT_STRING, SESSIONT_IMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 事件类型
                Event.EventType type = event.getType();
                // 节点路径
                String path = event.getPath();
                System.out.println("节点路径 = " + path+" 事件类型 = " + type);

                try {
                    // 注册监听 节点的数据变化
                    // 事件: NodeDeleted, NodeDataChanged
                    // 触发: delete, setData
                    zk.getData(watchPath, true, null);

                    // 注册监听 子节点个数变化
                    // 事件: NodeChildrenChanged, NodeDeleted
                    // 触发: create/delete子节点, delete当前给定节点
                    zk.getChildren(watchPath, true);

                    // 注册监听 该节点的变化(被创建,被删除,数据被改变)
                    // 事件: NodeCreated, NodeDeleted, NodeDataChanged
                    // 触发: create,  delete,  setData
                    zk.exists(watchPath, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                // 根据监听的相应的事件类型和节点,编写对应业务逻辑
                if (type == Event.EventType.NodeDeleted && event.getPath().equals(watchPath)) {
                    System.out.println("节点的数据变化---删除");
                } else if (type == Event.EventType.NodeDataChanged) {
                    System.out.println("节点的数据变化---修改");
                } else if (type == Event.EventType.NodeCreated) {
                    System.out.println("节点的数据变化---创建");
                } else if (type == Event.EventType.NodeChildrenChanged) {
                    System.out.println("子节点个数变化---创建/删除");
                } else if (type == Event.EventType.NodeDeleted) {
                    System.out.println("子节点个数变化---删除");
                }

            }
        });

        // 判断监听节点是否,不存在则创建
        if (zk.exists(watchPath, null) == null) {
            zk.create(watchPath, "watchData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }

        // 保证watcer线程一直工作
        Thread.sleep(Long.MAX_VALUE);

        // 启动监听就不会关闭zk链接
        // zk.close();
    }
}
复制代码

执行测试

@Test
    public void createZKNode() throws Exception {
        zk.setData(watchPath,value.getBytes(),-1);

        zk.create(sonPath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        zk.setData(sonPath,value.getBytes(),-1);
        zk.delete(sonPath,-1);
    }
复制代码
15:31:05.201 [main] INFO org.apache.zookeeper.ZooKeeper - Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=5000 watcher=com.example.demo.zk.ZKWatch$1@23e028a9
15:31:05.206 [main] INFO org.apache.zookeeper.common.X509Util - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
15:31:05.576 [main] INFO org.apache.zookeeper.ClientCnxnSocket - jute.maxbuffer value is 1048575 Bytes
15:31:05.618 [main] INFO org.apache.zookeeper.ClientCnxn - zookeeper.request.timeout value is 0. feature enabled=false
15:31:05.624 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.SaslServerPrincipal - Canonicalized address to activate.navicat.com
15:31:05.625 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Opening socket connection to server activate.navicat.com/127.0.0.1:2181.
15:31:05.626 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - SASL config status: Will not attempt to authenticate using SASL (unknown error)
15:31:05.627 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Socket connection established, initiating session, client: /127.0.0.1:2955, server: activate.navicat.com/127.0.0.1:2181
15:31:05.628 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Session establishment request sent on activate.navicat.com/127.0.0.1:2181
15:31:05.633 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Session establishment complete on server activate.navicat.com/127.0.0.1:2181, session id = 0x1000f36f14d001b, negotiated timeout = 5000
节点路径 = null 事件类型 = None
15:31:05.638 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 1,4  replyHeader:: 1,300,0  request:: '/watch_zk,T  response:: #7a6b5f44617461,s{290,295,1661412554041,1661412576797,1,2,0,0,7,0,298} 
15:31:05.642 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 2,8  replyHeader:: 2,300,0  request:: '/watch_zk,T  response:: v{} 
15:31:05.644 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 3,3  replyHeader:: 3,300,0  request:: '/watch_zk,T  response:: s{290,295,1661412554041,1661412576797,1,2,0,0,7,0,298} 
15:31:07.311 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got ping response for session id: 0x1000f36f14d001b after 0ms.
15:31:08.977 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got ping response for session id: 0x1000f36f14d001b after 0ms.
15:31:09.104 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got notification session id: 0x1000f36f14d001b
15:31:09.105 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got WatchedEvent state:SyncConnected type:NodeDataChanged path:/watch_zk for session id 0x1000f36f14d001b
节点路径 = /watch_zk 事件类型 = NodeDataChanged
15:31:09.107 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 4,4  replyHeader:: 4,303,0  request:: '/watch_zk,T  response:: #7a6b5f44617461,s{290,303,1661412554041,1661412669092,2,2,0,0,7,0,298} 
15:31:09.108 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 5,8  replyHeader:: 5,303,0  request:: '/watch_zk,T  response:: v{} 
15:31:09.109 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值