Curator基于zookeeper实现分布式锁

Curator基于zookeeper实现分布式锁

一、背景

Curator是Netflix公司开源的一个ZooKeeper客户端封装。通过在zookeeper的某路径节点下创建临时序列节点来实现分布式锁。即每个线程(跨进程的线程)获取同一把锁前,都需要在同样的路径下创建一个节点,节点名字由uuid + 递增序列组成。而通过对比自身的序列数是否在所有子节点的第一位,来判断是否成功获取到了锁。当获取锁失败时,它会添加watcher来监听前一个节点的变动情况,然后进行等待状态。直到watcher的事件生效将自己唤醒,或者超时时间异常返回。

由于原生zookeeper实现的分布式锁实现步骤繁琐且不好控制,Curator提供了很好的基于zookeeper的实现,提供了InterProcessMutex(可重入锁)、InterProcessSemaphoreMutex、InterProcessReadWriteLock(读写锁)相关锁的操作。

注:该文是本博主记录学习之用,没有太多详细的讲解,敬请谅解!

二、基于ZooKeeper的实现方式

ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:

(1)创建一个目录mylock;
(2)线程A想获取锁就在mylock目录下创建临时顺序节点;
(3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
(4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
(5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

优点:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。

缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。

三、添加Maven依赖

<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-recipes</artifactId>
			<version>2.12.0</version>
</dependency>

四、代码实现

package com.lance.net.server;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;



public class CuratorTest {


    private static int count=10;

    public static void main(String[] args) {
        //重试策略 (初始休眠时间为 1000ms, 最大重试次数为3)
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        //zookeeper地址,集群用逗号分隔(127.0.0.1:2181,27.0.0.1:2182)
        String connUrl="127.0.0.1:2181";
        for (int i=0;i<10;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    CuratorFramework zk=CuratorFrameworkFactory.newClient(connUrl,retryPolicy);	
                    zk.start();
                    //可重入锁,即是获锁后,还可以再次获取
                    InterProcessLock lock=new InterProcessMutex(zk,"/lock");  
                    try {
                        //获得锁
                        if( lock.acquire()){
                              get();
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        try {
                            //释放锁
                            lock.release();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

    public static void get() throws InterruptedException {
        count--;
        if(count==3){
            Thread.sleep(2000);//这里设置该线程睡眠2秒,已达到锁住效果
        }
        System.out.println(count);
    }
}

五、关键点说明

  1. CuratorFramework对象创建方式
    第一种创建方式,通过newClient创建对象
    CuratorFramework zk=CuratorFrameworkFactory.newClient(connUrl,retryPolicy);

    第二张创建方式,通过builder()创建对象
    CuratorFramework zk=CuratorFrameworkFactory.builder()
    .connectString(connUrl)
    .sessionTimeoutMs(2000)
    .retryPolicy(retryPolicy)
    .build();

  2. 锁对象的说明
    //可重入锁,即是获锁后,还可以再次获取
    InterProcessLock lock=new InterProcessMutex(zk,"/lock");

    // 不可重入锁,即是获锁后,不可再次获取
    InterProcessLock interProcessLock = new InterProcessSemaphoreMutex(zk,"/lock");

    //读写锁
    InterProcessReadWriteLock lock=new InterProcessReadWriteLock(zk,"/lock");

    // 创建多重锁对象
    // InterProcessLock lock = new InterProcessMultiLock(Arrays.asList(zk,"/lock"));

六、curator的重连策略

curator连接zookeeper服务器时有自动重连机制,而curator的重连策略有五种。

第一种就是我们以上demo中使用到的:
/**

  • (推荐)
  • 同步创建zk示例,原生api是异步的
  • 这一步是设置重连策略
  • 构造器参数:
  • curator链接zookeeper的策略:ExponentialBackoffRetry
  • baseSleepTimeMs:初始sleep的时间
  • maxRetries:最大重试次数
  • maxSleepMs:最大重试时间
    */
    RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

第二种,可设定重连n次:

/**

  • (推荐)
  • curator链接zookeeper的策略:RetryNTimes
  • 构造器参数:
  • n:重试的次数
  • sleepMsBetweenRetries:每次重试间隔的时间
    */
    RetryPolicy retryPolicy = new RetryNTimes(3, 5000);

第三种,只会重连一次:

/**

  • (不推荐)
  • curator链接zookeeper的策略:RetryOneTime
  • 构造器参数:
  • sleepMsBetweenRetry:每次重试间隔的时间
  • 这个策略只会重试一次
    */
    RetryPolicy retryPolicy2 = new RetryOneTime(3000);

第四种,永远重连:

/**

  • 永远重试,不推荐使用
    */
    RetryPolicy retryPolicy3 = new RetryForever(retryIntervalMs)

第五种,可设定最大重试时间:

/**

  • curator链接zookeeper的策略:RetryUntilElapsed
  • 构造器参数:
  • maxElapsedTimeMs:最大重试时间
  • sleepMsBetweenRetries:每次重试间隔
  • 重试时间超过maxElapsedTimeMs后,就不再重试
    */
    RetryPolicy retryPolicy4 = new RetryUntilElapsed(2000, 3000);

七、获得锁以及释放锁的流程

在这里插入图片描述

JedisLock基于Redis实现分布式锁
https://blog.csdn.net/weixin_43947588/article/details/84977357

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值