分布式锁3: zk实现分布式锁1 znode节点特性

一 zk 实现分布式锁

1.1 zk分布式操作命令

1.1.1 常用命令说明

1.查看某个节点下的子节点:  ls /
2.查看某个节点的内容:  get   /zookeeper      
3.创建持久化节点:  create /aa "test"
4.删除节点:  delete /aa 
5.查看节点状态:stat /
6. 设置节点的内容   set /aa "test1"

分布式锁实现原理与最佳实践

1.1.2 znode节点类型

        永久节点:create /path content
        临时节点:create -e /path content 。只要客户端程序断开链接自动删除
        永久序列化节点:create -s /path content 
        临时序列化节点:create -s -e /path content 

1.1.3 znode节点独占排它特性

相同节点具有唯一性,只允许创建一次,具有独占排它的特性。

1.2 zk的4种目录树

zookeeper提供一个多层级的节点命名空间(节点称为znode),每个节点都用一个以斜杠(/)分隔的路径表示,而且每个节点都有父节点(根节点除外),非常类似于文件系统。并且每个节点都是唯一的。znode节点有四种类型:

1.PERSISTENT:永久节点。客户端与zookeeper断开连接后,该节点依旧存在

2.EPHEMERAL:临时节点。客户端与zookeeper断开连接后,该节点被删除

3.PERSISTENT_SEQUENTIAL:永久节点、序列化。客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

4.EPHEMERAL_SEQUENTIAL:临时节点、序列化。客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

1.3 实战操作

1.进入zk客户端

./zkCli.sh        # 查看zk客户端

2.创建节点命令

[zk: localhost:2181(CONNECTED) 12] get /sz
test
[zk: localhost:2181(CONNECTED) 13] set /sz test123
[zk: localhost:2181(CONNECTED) 14] get /sz
test123
[zk: localhost:2181(CONNECTED) 15] 

3.案例

[zk: localhost:2181(CONNECTED) 0] create /aa test  # 创建持久化节点
Created /aa
[zk: localhost:2181(CONNECTED) 1] create -s /bb test  # 创建持久序列化节点
Created /bb0000000001
[zk: localhost:2181(CONNECTED) 2] create -e /cc test  # 创建临时节点
Created /cc
[zk: localhost:2181(CONNECTED) 3] create -e -s /dd test  # 创建临时序列化节点
Created /dd0000000003
[zk: localhost:2181(CONNECTED) 4] ls /   # 查看某个节点下的子节点
[aa, bb0000000001, cc, dd0000000003, zookeeper]
[zk: localhost:2181(CONNECTED) 5] stat /  # 查看某个节点的状态
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x5
cversion = 3
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 5
[zk: localhost:2181(CONNECTED) 6] get /aa  # 查看某个节点的内容
test
[zk: localhost:2181(CONNECTED) 11] delete /aa  # 删除某个节点
[zk: localhost:2181(CONNECTED) 7] ls /  # 再次查看
[bb0000000001, cc, dd0000000003, zookeeper]

1.4 zk的监听事件

1.4.1 说明

在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zookeeper会通知客户端。当前zookeeper针对节点的监听有如下四种事件:

1.监听节点创建 :使用监听命令:    stat -w /xx 
2.监听节点删除: 使用监听命令:  stat -w /xx

3.监听节点数据变化:  使用监听命令 : get -w  /xx

4.监听子节点变化:  使用监听命令  ls   -w   /xxx 

1.4.2 案例,监听节点创建

1.客户端1

2.客户端2

 1.4.3 案例,监听节点删除

1.客户端1

2.客户端2:   stat -w  /bb

1.4.4 案例,监听数据变化

1.客户端1

[zk: localhost:2181(CONNECTED) 28] set /teng 1234
[zk: localhost:2181(CONNECTED) 29] 
2.客户端2:会提示目录/teng 发生了改变

 1.客户端1

2.客户端2

 1.4.5 案例,子节点变化

1.客户端1

2.客户端2: 子节点发生变化

1.5 zk的Java Api的操作

1.java代码

package com.atguigu.distributed.lock.util;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName: TestZk
 * @Description: TODO
 * @Author: admin
 * @Date: 2023/12/29 11:21:01 
 * @Version: V1.0
 **/
public class TestZk {
    public static void main(String[] args) throws KeeperException, InterruptedException {
        // 获取zookeeper链接
        CountDownLatch countDownLatch = new CountDownLatch(1);
        ZooKeeper zooKeeper = null;
        try {
            zooKeeper = new ZooKeeper("192.168.43.4:2181", 30000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (Event.KeeperState.SyncConnected.equals(event.getState())
                            && Event.EventType.None.equals(event.getType())) {
                        System.out.println("获取链接成功。。。。。。" + event);
                        countDownLatch.countDown();
                    }
                    else if(Event.KeeperState.Closed.equals(event.getState())){
                        System.out.println("==================关闭链接成功!!");
                    }
                }
            });
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
       //创建节点
       createInfo(zooKeeper);
      //判断节点是否存在
        Stat  stat = existInfo(zooKeeper);
      //监听节点
        listenerInfo(zooKeeper);
       //获取节点内容
        getNodenfo(zooKeeper);
        //查询子节点
        getChildrenInfo(zooKeeper);
        //更新节点内容
        updateNodeContent(zooKeeper);
        // 删除一个节点
        System.out.println("version:"+stat.getVersion());
        //-1表示不关心版本号
        zooKeeper.delete("/pabank/aa", -1);
//        if (zooKeeper != null){
//            System.out.println("关闭...");
//            zooKeeper.close();
//        }
        System.out.println("over......");
    }
    /**
    * @author admin
    * @description     创建节点
    * @date 2023/12/29 11:25
    * @param [zooKeeper]
    * @return void
    */
    public static void createInfo( ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 创建一个节点,1-节点路径 2-节点内容 3-节点的访问权限 4-节点类型
        // OPEN_ACL_UNSAFE:任何人可以操作该节点
        //CREATOR_ALL_ACL:创建者拥有所有访问权限
        //READ_ACL_UNSAFE: 任何人都可以读取该节点
        //1.创建一个,任何人都可以操作的永久节点
        System.out.println("eee");
      //  zooKeeper.create("/pabank", "aa".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
       // zooKeeper.create("/pabank/aa", "aa".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        //2.创建一个,任何人都可以操作的临时节点
     //   zooKeeper.create("/pabank/bb", "bb~~".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
//        //3.创建一个,任何人都可以操作的永久顺序节点
       zooKeeper.create("/pabank/cc", "cc~~".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
//        //4.创建一个,任何人都可以操作的临时顺序节点
//        zooKeeper.create("/pabank/dd", "dd~~".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
//        //6.创建一个创建者拥有所有访问权限,可以操作的临时顺序节点
//        zooKeeper.create("/atguigu/dd", "haha~~".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("创建成功...");

    }
    /**
    * @author admin
    * @description       创建节点是否存在
    * @date 2023/12/29 11:57
    * @param [zooKeeper]
    * @return void
    */
    public static Stat existInfo(ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 判断节点是否存在
        Stat stat = zooKeeper.exists("/pabank", true);
        if (stat != null){
            System.out.println("当前节点存在!" + stat.getVersion());
        } else {
            System.out.println("当前节点不存在!");
        }
        return stat;
    }
    public static void   listenerInfo(ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 判断节点是否存在,同时添加监听
        zooKeeper.exists("/pabank", event -> {
            System.out.println("监听event:"+event);
        });
    }
    /**
    * @author admin
    * @description       获取节点的数据
    * @date 2023/12/29 16:44
    * @param [zooKeeper]
    * @return void
    */
    public static void  getNodenfo(ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 获取一个节点的数据
        byte[] data = zooKeeper.getData("/pabank/aa", false, null);
        System.out.println("节点内容"+new String(data));
    }
    /**
    * @author admin
    * @description     查询一个节点的所有子节点
    * @date 2024/1/2 17:28
    * @param [zooKeeper]
    * @return void
    */
    public  static void  getChildrenInfo(ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 查询一个节点的所有子节点
        List<String> children = zooKeeper.getChildren("/pabank", false);
        System.out.println("子节点内容children:"+children);
    }
    /**
    * @author admin
    * @description       更新节点内容
    * @date 2024/1/2 17:29
    * @param []
    * @return void
    */
    public static void updateNodeContent(ZooKeeper zooKeeper) throws KeeperException, InterruptedException {
        // 更新
        Stat stat=existInfo(zooKeeper);
        zooKeeper.setData("/pabank", "wawa...".getBytes(), stat.getVersion());
        System.out.println("修改内容:"+"wawa");
    }

}

2.执行结果

3.删除节点:  子节点pabank/aa 中 /aa进行了删除

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值