分布式锁的Redis,Zookeeper实现

7 篇文章 1 订阅
1 篇文章 0 订阅
1. 什么是分布式锁

  分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性。,区别于单实例部署的场景,单实例部署只需要使用synchronized,Reenterlock实现,分布式场景需要借助中间件实现。

2. redis实现

(1)利用 setnx (set not exist),某个键不存在的时候才会成功

// example 1
if(setnx(key,1) == 1){
    expire(key,30)
    try {
        do something ......
    } finally {
        del(key)
    }
}

不足:如果setnx后此节点崩了,则锁永远被占用

(2) 替换成 set(key,1,30,NX)让设置和过期原子化

// example 2
if(set(key,1,30,NX) == 1){
    try {
        do something ......
    } finally {
        del(key)
    }
}

不足:多个进程可能导致误删
=> X获取lockA
=> lockA 过期(X操作未执行完)
=> Y获取lockA
=> X操作完,执行del lockA ,此时X 自己获取的那个锁已经过期了,删掉的是Y获取的锁
=> 其他线程进来,发现没有锁,直接获取,锁被破坏

(3) 使用守护进程为锁续命
  创建锁的时候,同时创建一个守护进程,每10s为锁重新设置一次过期时间,任务执行完后删除守护进程,则不再继续续命,同时删掉锁,释放资源。

看程序员小灰公众号

3. redission 实现

参考:https://www.jianshu.com/p/cde0700f0128

  如果负责储存某些分布式锁的某些Redis节点宕机以后,而且这些锁正好处于锁住的状态时,这些锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

  另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

public void testReentrantLock(RedissonClient redisson){

    RLock lock = redisson.getLock("anyLock");
    try{
        // 1. 最常见的使用方法
        //lock.lock();

        // 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
        //lock.lock(10, TimeUnit.SECONDS);

        // 3. 尝试加锁,最多等待3秒,上锁以后10秒自动解锁
        boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
        if(res){    //成功
            // do your business

        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }

}
4. zookeeper实现

参考:https://blog.csdn.net/u011191463/article/details/78658036

不好的方案:
  对于一个锁都有一个节点locker,所有client监听这个locker的子节点,如果子节点被删掉则说明锁被释放,有子节点则说明锁被占用。
缺点:
  所有client都监听locker,locker的任何动作都会惊动所有client,但是最终只有一个client会获得锁,这就是所谓的惊群

  为了解决惊群的问题,采用下面的方案。

  原理:
  利用zk的临时顺序节点,首先创建一个locker节点,如果有线程要访问,则创建一个临时顺序节点node1,判断node1是否第一个节点,是的话就执行,不是则监听前一个节点,等前一个节点删除后再执行。
zk 分布式锁

锁的获取过程
获取过程

Curator 实现:
  Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等等。

  Curator实现了大部分锁,重入锁,不可重入锁,读锁,写锁,信号量等等。

<!-- curator 客户端 -->
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>2.12.0</version>
</dependency>
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-recipes</artifactId>
	<version>2.12.0</version>
</dependency>
String connectionInfo = "100.69.12.9:2881,100.69.12.9:2882";
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client =
      CuratorFrameworkFactory.builder()
              .connectString(connectionInfo)
              .sessionTimeoutMs(5000)
              .connectionTimeoutMs(5000)
              .retryPolicy(retryPolicy)
              .build();
client.start();

InterProcessMutex lock = new InterProcessMutex(client,"/path/lock");

try {
  // 获得一个锁
  lock.acquire();
  // 获得一个锁,并设置过期时间
  lock.acquire(5, TimeUnit.MICROSECONDS);
} catch (Exception e) {
  e.printStackTrace();
} finally{
  try {
      lock.release();
  } catch (Exception e) {
      e.printStackTrace();
  }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值