分布式系统基础-- 注册中心Zookeeper应用4(分布式锁)

文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。

相关文章:

  1. 分布式系统基础--注册中心Zookeeper初识1
  2. 分布式系统基础--注册中心Zookeeper相遇2
  3. 分布式系统基础-- 注册中心Zookeeper应用3
  4. 分布式系统基础-- 注册中心Zookeeper应用4(分布式锁)

ZooKeeper 是一个分布式协调服务,常用于实现分布式系统中的各种协调任务。分布式锁是其中一个典型的应用场景。在分布式系统中,分布式锁用于控制多个进程或节点对共享资源的访问,确保在同一时间只有一个进程能够访问或修改该资源。

ZooKeeper 分布式锁的实现原理

在 ZooKeeper 中,实现分布式锁通常使用的是临时顺序节点(Ephemeral Sequential Znodes)。具体步骤如下:

  1. 创建临时顺序节点:

    • 每个进程试图获取锁时,都会在指定的节点目录下创建一个临时顺序节点(例如 /lock/lock_0000001)。
    • 这些节点的名称包含了创建顺序,所以不同进程创建的节点有不同的序号。
  2. 判断节点的序号:

    • 创建节点后,进程会获取这个目录下的所有子节点,并判断自己创建的节点是否是序号最小的。
    • 如果是最小序号的节点,说明该进程获得了锁,可以执行对共享资源的操作。
  3. 监控前一个节点:

    • 如果进程创建的节点不是最小序号,它就会找到比自己序号小的上一个节点,并在其上注册一个监听器。
    • 当上一个节点被删除(即上一个进程释放锁)时,ZooKeeper 会通知当前进程。
    • 当前进程收到通知后,再次检查自己是否成为序号最小的节点,如果是,则获得锁。
  4. 释放锁:

    • 当进程完成对共享资源的操作后,它会删除自己创建的临时顺序节点。
    • 由于是临时节点,如果进程因故障断开连接,ZooKeeper 会自动删除该节点,从而释放锁。

ZooKeeper 分布式锁的优点

  1. 可靠性: 使用临时节点,即使持有锁的进程崩溃,ZooKeeper 也会自动释放锁。
  2. 公平性: 通过顺序节点,锁的获取顺序是严格按时间顺序来的,不会出现某个进程长时间得不到锁的情况。

前面讲了zookeeper的基础,现在基于zookeeper来实现分布式锁。

基于ZooKeeper分布式锁的流程:

在zookeeper指定节点(locks)下创建跟节点 /locks

获取locks下所有子节点children(孩子节点是临时节点)

通过当前的节点和子节点中最小的节点进行比较,如果相等,表示获得锁成功

监听当前节点的上一个节点

具体实现

1.利用watcher机制手动实现(核心代码)

 @Override
    public boolean tryLock() {

        try {
            //创建临时有序节点
            CURRENT_LOCK = zk.create(ROOT_LOCK + "/", "0".getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println(Thread.currentThread().getName() + "->" +
                    CURRENT_LOCK + ",尝试竞争锁");
            List<String> childrens = zk.getChildren(ROOT_LOCK, false); //获取根节点下的所有子节点
            SortedSet<String> sortedSet = new TreeSet();//定义一个集合进行排序
            for (String children : childrens) {
                sortedSet.add(ROOT_LOCK + "/" + children);
            }
            String firstNode = sortedSet.first(); //获得当前所有子节点中最小的节点
            SortedSet<String> lessThenMe = ((TreeSet<String>) sortedSet).headSet(CURRENT_LOCK); //
            if (CURRENT_LOCK.equals(firstNode)) {//通过当前的节点和子节点中最小的节点进行比较,如果相等,表示获得锁成功
                return true;
            }
            if (!lessThenMe.isEmpty()) {
                WAIT_LOCK = lessThenMe.last();//获得比当前节点更小的最后一个节点,设置给WAIT_LOCK
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

2.利用curator客户端方式实现(核心代码)

@Override
        public void run() {
            InterProcessMutex lock = new InterProcessMutex(client, "/distributeLock");
            try {
                if (lock.acquire(120, TimeUnit.SECONDS)) {
                    try {
                        //System.out.println("----" + this.name + "获得资源");
                        System.out.println("-----" + this.name + "正在处理资源");
                        Thread.sleep(10 * 1000);
                        // System.out.println("-----" + this.name + "资源使用完毕-------");
                        latch.countDown();
                    } finally {
                        lock.release();
                        System.out.println("-------" + this.name + "释放----------");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

代码github地址:

https://github.com/zhangyu345293721/distributelock

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值