天天看点

zookeeper分布式锁原理及实现

zookeeper分布式锁原理及实现

前言

写zookeeper分布式锁之前,先说下CAP理论吧

C 一致性、A 可用性、P分区容错性。三者不能同时存在,由于P是必要因素,所以分为CP和AP两种模型

前段时间写了redis怎样实现分布式锁,redis实现分布式锁效率是比较高的,但是什么事情都是相对性的,因为redis支持了 AP那么就放弃了CP。

当我们对一致性要求特别高的时候,就需要考虑一种别的分布式锁技术了,

zookeeper因为它集群的选举和同步机制,使得它是支持CP,而放弃了AP,接下来来看看zookeeper是怎么实现分布式锁的吧。

zookeeper的数据结构

zookeeper分布式锁原理及实现

类似liux系统的文件目录结构,根节点是/ 下边有很多的子节点 子节点下边也可以有自己的子节点,这个节点叫做znode,当然除了节点以外每个节点都可以存储数据,今天咱们就来说下节点znode

节点类型

1,持久化目录节点–客户端与zookeeper断开连接后,该节点依旧存在

2,持久化顺序目录节点–客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

3,临时节点–客户端与zookeeper断开连接后,节点被删除

4,临时顺序节点–客户端与zookeeper断开连接后,只是Zookeeper给该节点名称进行顺序编号

5,容器节点–3.5.3新增的特性,没有子节点的容器节点会被清除掉。

6,TTL节点–3.5.3新增的特性,位节点设定了失效时间。具体失效时间却决于后台检测失效线程的轮询频率

分布式锁的实现

分布式锁的实现就是根据临时顺序节点这个点来实现的

具体步骤如下

1、每个线程都会在zookeeper中的一个持久节点生成一个临时顺序节点

2、然后判断自己的节点是不是当前顺序最靠前的

3、如果是那么获取到锁,如果不是那么监视它上一个临时顺序节点

4、获取到锁的线程执行完逻辑后,删除当前节点

Curator是Netflix公司开源的一个Zookeeper客户端,Curator框架在zookeeper原生API接口上进行了包装,大大降低了我们操作zookeeper的复杂度,下面来看下Curator是怎么实现的分布式锁

依赖

<dependency>
        <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>
           

代码如下

//这段代码放在启动类用于初始化Curator客户端
public  CuratorFramework getZkClient() {
        String zkServerAddress = "127.0.0.1:2181";
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);
        CuratorFramework zkClient = CuratorFrameworkFactory.builder()
                .connectString(zkServerAddress)
                .sessionTimeoutMs(5000)
                .connectionTimeoutMs(5000)
                .retryPolicy(retryPolicy)
                .build();
        zkClient.start();
        return zkClient;
    }
 @Service
 public class testService {
       @Resource
    private CuratorFramework zkClient;

    //操作库存业务
    public String stock() {
      
        String lockPath = "/lock1";
        //在根节点上创建lock1节点
        InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);

            try {
                //加锁 这块参数2000代表时间,后边单位,代表线程等待时间,如果传-1代表永久等待
                boolean flag=lock.acquire(2000, TimeUnit.SECONDS);
                if (flag) {
                    //操作库存业务

                    return "";
                } else {
                    return "业务繁忙请稍后重试";
                }
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            } finally {
                //解锁
                try {
                    lock.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }


        }


           

如果对redis分布式锁感兴趣的请点击redis分布式锁实现

欢迎大家一起交流一起学习,风里雨里我在这里等你

继续阅读