Zookeeper:五、实现分布式锁

前言

Zookeeper实现分布式锁。


文章目录

一、实现思路

在这里插入图片描述

  • 为什么有分布式锁?
    1)分布式情况下多个客户端请求处理同一个资源,如果不加锁可能会产生数据一致性等其他严重问题,但是单机情况下的一些锁(比如ReentrantLock、Synchorized)只能控制对当前机器请求的数据一致性,不能处理多台机器,因此产生了分布式锁。
    2)每个客户在处理资源前先要获取到分布式锁,只有获取到才能操作资源,否则等待。
  • Zookeeper怎么实现?
    1)如图创建一个临时根节点/locks,每当有一个请求发送过来就在该根节点基础上创建一个临时有序节点/locks/seq-xxxxx,然后根据序号判断当前节点是不是当前情况下最小的节点,如果是的话就获取到锁,反之对前一个节点进行监听
    2)当获取到锁的前一个节点处理完数据后,就delete释放掉节点,然后后面的节点会收到通知,重复进行判断。

二、代码实现

/**
 * 分布式锁的实现
 */
public class DistributeClock {
    // Zookeeper客户端
    private ZooKeeper zk = null;
    // 等待连接处理
    private CountDownLatch connectlatch = new CountDownLatch(1);
    // 等待前一个节点删除执行完毕
    private CountDownLatch preNodelatch = new CountDownLatch(1);
    // 远程服务器地址
    private String hostName = "192.168.1.6:2181,192.168.1.7:2181,192.168.1.8:2181";
    // 连接建立时间
    private int connectTimeout = 60000;
    // 前一个被监听的节点名称
    private String waitPath;
    // 当前节点的名称
    private String currentPath;

    public DistributeClock() throws Exception{
        //1.获取连接
        zk = new ZooKeeper(hostName, connectTimeout, new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                // 状态为连接建立完毕
                if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
                    connectlatch.countDown();
                }
                // 监听前一个节点的处理完毕
                if(watchedEvent.getType()==Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){
                    preNodelatch.countDown();
                }
            }
        });
        //2.等待连接建立完毕
        connectlatch.await();
        //3.连接建立完毕,判断根节点 /locks是否存在,不存在则创建该根节点
        Stat stat = zk.exists("/locks", false);
        if(stat == null){
            zk.create("/locks","locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    /**
     * 请求加锁
     */
    public void zkLock(){
        try {
            // 创建带序号的临时节点,同时获取到该根路径下的子节点
            currentPath = zk.create("/locks" + "/seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            List<String> childNodes = zk.getChildren("/locks", true);
            // 只有1个节点直接返回
            if(childNodes.size() == 1){
                return;
            }
            // 多个节点时,当前节点监听前一个节点
            else{
                // 节点名称:seq-00000000
                String thisNode = currentPath.substring("/locks/".length());
                Collections.sort(childNodes);
                int index = childNodes.indexOf(thisNode);
                if(index == -1){
                    throw new RuntimeException("数据异常");
                }
                else if(index == 0){
                    return;
                }
                else{
                    waitPath = "/locks/"+childNodes.get(index-1);
                    zk.getData(waitPath,true,new Stat());
                    preNodelatch.await();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放锁
     */
    public void releaseLock(){
        try {
            zk.delete(currentPath,-1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意以下几点:

  • 连接建立完毕后,需要检查"/clocks" 根路径是否存在,不存需要提前创建好该路径;
  • 每当有一个客户端请求获取锁资源,就先执行创建临时带序号的子节点,然后比较当前节点是不是/clocks路径下序号最小的那个节点,如果是就创建该节点;否则当前节点需要去监听前一个节点。
  • 整个加锁过程中必须等待连接建立完毕才能继续操作、必须等待前一个节点完全释放掉锁之后才能继续操作,因此需要用到CountDownLatch类变量。
    java多线程系列:CountDownLatch
    整齐划一-CountDownLatch如何协调多线程的开始和结束

三、成熟的框架——Curator

自定义的分布式锁存在很多问题,比如需要通过CountDownLatch实现异步连接控制,还需要解决反复重连等问题,因此可以直接使用封装成熟的框架Curator来实现分布式锁的调用。
详细学习Curator

public class CuratorTest {
    private static String hostAddress = "192.168.1.6:2181,192.168.1.7:2181,192.168.1.8:2181";

    public static void main(String[] args) {
        // 创建分布式锁1
        final InterProcessMutex clock1 = new InterProcessMutex(connectClient(), "/clocks");
        // 创建分布式锁2
        final InterProcessMutex clock2 = new InterProcessMutex(connectClient(), "/clocks");

        // 尝试获取锁
        new Thread(new Runnable() {
            public void run() {
                try {
                    clock1.acquire();
                    System.out.println("-----------客户端1成功获取到分布式锁------------");
                    clock1.release();
                    System.out.println("-----------客户端1成功释放分布式锁------------");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    clock2.acquire();
                    System.out.println("-----------客户端2成功获取到分布式锁------------");
                    clock2.release();
                    System.out.println("-----------客户端2成功释放分布式锁------------");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    // 建立客户端连接
    private static CuratorFramework connectClient(){
        /**
         * 建立重试策略
         * 间隔时间、最大重试次数
         */
        RetryPolicy policy = new ExponentialBackoffRetry(3000,3);

        /**
         * 建立连接
         */
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(hostAddress)
                .connectionTimeoutMs(60000)
                .sessionTimeoutMs(60000)
                .retryPolicy(policy).build();
        // 启动Client实例
        client.start();
        return client;
    }
}

原文地址:https://blog.csdn.net/qq_43684985/article/details/118878596

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


#一、什么是ZooKeeper**ZooKeeper是一个分布式服务协调框架**,提供了分布式数据一致性的解决方案,基于ZooKeeper的**数据结构,Watcher,选举机制**等特点,可以**实现数据的发布/订阅,软负载均衡,命名服务,统一配置管理,分布式锁,集群管理**等等。#二、为什么使用ZooKeeperZooKeeper能保证:*
2.ZooKeeper介绍2.1.ZooKeeper由来正式介绍ZooKeeper之前,我们先来看看ZooKeeper的由来,还挺有意思的。下面这段内容摘自《从Paxos到ZooKeeper》第四章第一节,推荐大家阅读一下:ZooKeeper最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很
Zookeeper概述1.ZooKeeper最为主要的使⽤场景,是作为分布式系统的分布式协同服务。2.分布式系统中每台服务器的算力和资源都是有限的,但是我们通过分布式系统组成集群就可以对算力和资源进行无限扩张,但是分布式节点间的协调就成了问题。3.就像我们的开发团队之间的协作一
环境:1.VMware®Workstation12Pro 2.CentOS7 3.zookeeper-3.4.6安装步骤1.下载zookeeper本文使用的zookeeper下载地址如下(大家也可以下载其它版本)链接:https://pan.baidu.com/s/1Ab9F53jNy7upsrYHCacWrw 提取码:jqyn 
###1\.面试官:工作中使用过Zookeeper嘛?你知道它是什么,有什么用途呢?**小菜鸡的我:***有使用过的,使用ZooKeeper作为**dubbo的注册中心**,使用ZooKeeper实现**分布式锁**。*ZooKeeper,它是一个开放源码的**分布式协调服务**,它是一个集群的管理者,它将简单易用的接口提供给用户。*
##2\.ZooKeeper介绍###2.1\.ZooKeeper由来正式介绍ZooKeeper之前,我们先来看看ZooKeeper的由来,还挺有意思的。下面这段内容摘自《从Paxos到ZooKeeper》第四章第一节,推荐大家阅读一下:>ZooKeeper最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很
环境准备:windows:jdk8+nginx+ab压测centos7:redis+zookeeper3.3.6ab下载链接:https://www.apachelounge.com/download/测试思路:windows下使用springboot编写秒杀接口,商品数据存在redis,运行三个服务,利用nginx做代理,使用ab分别测试单机锁,自实现zookeeper分布式锁和Curator
由于只有一台电脑,所以搭建一个伪集群(伪集群就是在一台电脑上模拟搭建集群,走不同端口启动,真实的情况在每台机器上搭建一个zookeeper或者每台机器两个zookeeper等),道理是一样的,只不过要注意别被防火墙或者安全组规则挡住了zookeeper节点间的通信,每个节点直接的网络要是通的。集群数
常用命令总结(linux运行.sh结尾的脚本,window运行.cmd结尾的脚本,一下均为linux运行的,直接将.sh改为.cmd即可):linux环境:1.启动ZK服务:bin/zkServer.shstart2.查看ZK服务状态:bin/zkServer.shstatus3.停止ZK服务:bin/zkServer.shstop4.重启ZK服务:bin/zkServer.shrest
Kubernetes简介Kubernetes(简称K8S,K和S之间有8个字母)是用于自动部署,扩展和管理容器化应用程序的开源系统。它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现。Kubernetes源自Google15年生产环境的运维经验,同时凝聚了社区的最佳创意和实践。Kubernetes具有如下特性:
###正文ZooKeeper很流行,有个基本的疑问:*ZooKeeper是用来做什么的?*之前没有ZK,为什么会诞生ZK?OK,解答一下上面的疑问:(下面是凭直觉说的)*ZooKeeper是用于简化分布式应用开发的,对开发者屏蔽一些分布式应用开发过程中的底层细节*ZooKeeper对外暴露简单的API,用于支持分
#一、什么是ZooKeeper**ZooKeeper是一个分布式服务协调框架**,提供了分布式数据一致性的解决方案,基于ZooKeeper的**数据结构,Watcher,选举机制**等特点,可以**实现数据的发布/订阅,软负载均衡,命名服务,统一配置管理,分布式锁,集群管理**等等。#二、为什么使用ZooKeeperZooKeeper能保证:*
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。zoo.cfg即/usr/local/java/zookeeper/conf下的zoo_sample.cfgzoo.cfg内含参数:tickTime、initLimit、syncLimit、dataDir、dataLogDir、clientPort
正文ZooKeeper很流行,有个基本的疑问:ZooKeeper是用来做什么的?之前没有ZK,为什么会诞生ZK?OK,解答一下上面的疑问:(下面是凭直觉说的)ZooKeeper是用于简化分布式应用开发的,对开发者屏蔽一些分布式应用开发过程中的底层细节ZooKeeper对外暴露简单的API,用于支持分布式应用开
#**NO1:说说zookeeper是什么?**ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现(Chubby是不开源的),它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供
正文ZooKeeper很流行,有个基本的疑问:ZooKeeper是用来做什么的?之前没有ZK,为什么会诞生ZK?OK,解答一下上面的疑问:(下面是凭直觉说的)ZooKeeper是用于简化分布式应用开发的,对开发者屏蔽一些分布式应用开发过程中的底层细节ZooKeeper对外暴露简单的API,用于支持分布式应用开
NO1:说说zookeeper是什么?ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现(Chubby是不开源的),它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供
#**NO1:说说zookeeper是什么?**ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现(Chubby是不开源的),它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供
一、什么是ZooKeeperZooKeeper是一个分布式服务协调框架,提供了分布式数据一致性的解决方案,基于ZooKeeper的数据结构,Watcher,选举机制等特点,可以实现数据的发布/订阅,软负载均衡,命名服务,统一配置管理,分布式锁,集群管理等等。二、为什么使用ZooKeeperZooKeeper能保证:更新请求
#**NO1:说说zookeeper是什么?**ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现(Chubby是不开源的),它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供