空心|最全分布式锁设计方案( 二 )

  • 解决办法:针对上面的缺点 , 我们可以采用redis的RedLock算法 。 假如集群中有n个redis , 我们先从这n个redis中尝试获取锁(锁的过期时间为x) , 并记录获取锁的消耗的总时间t , 获取锁成功数量为s , 当且仅当t < x 并且 s >= (n/2 + 1)时 , 认为获取锁成功 。
  • 四、基于Redisson实现1、是什么?
    官网地址: Redisson是一个功能十分强大的redis客户端 , 封装了很多分布式操作 , 比如分布式对象、分布式集合、分布式锁等 。 它的分布式锁也很多 , 什么公平锁、可重入锁、redlock等一应俱全 , 下面来看看如何在springboot项目中使用它 。
    2、使用redisson做分布式锁:
    • 添加依赖:
    org.redisson redisson-spring-boot-starter 3.12.3 io.netty netty-all
    • application.yml:
    【空心|最全分布式锁设计方案】spring:application:name: distributed-lockredis:# redis单机版的写法host: 192.168.2.43port: 6379# 集群的写法#cluster:#nodes:#- 192.168.0.106,192.168.0.107#哨兵的写法#sentinel:#master: 192.168.0.106#nodes:#- 192.168.0.107,192.168.0.108
    • 用法:直接注入RedissonClient , 然后用它获取锁 , 得到锁之后就可以进行占锁和释放锁了 。有阻塞式锁 , 也有非阻塞式锁 , 具体用法如下:
    @Autowiredprivate RedissonClient redisson;/** * 未设置过期时间 , 没获取到就会一直阻塞着 * @return */@GetMapping("/testLock")public String testLock() { log.info("进入testLock方法 , 开始获取锁"); String key = "testLock"; RLock lock = redisson.getLock(key); lock.lock(); log.info("获取锁成功 , 开始执行业务逻辑……"); try {TimeUnit.SECONDS.sleep(10L); } catch (Exception e) { e.printStackTrace();}; log.info("执行完业务逻辑 , 释放锁"); lock.unlock(); return "success";} /** * 尝试获取锁 , 没获取到就直接失败 , 不会阻塞 * @return */@GetMapping("/testTryLock")public String testTryLock() { log.info("进入testTryLock方法 , 开始获取锁"); String key = "testTryLock"; RLock lock = redisson.getLock(key); boolean res = lock.tryLock(); if (!res) {log.error("尝试获取锁失败");return "fail"; } else {log.info("获取锁成功 , 开始执行业务逻辑……");try {TimeUnit.SECONDS.sleep(30L); } catch (Exception e) { e.printStackTrace();};log.info("执行完业务逻辑 , 释放锁");lock.unlock();return "success"; }} /** * 锁设置了过期时间 , 即使最后面的unlock失败 , 20秒后也会自动释放锁 * @return */@GetMapping("/testLockTimeout")public String testLockTimeout() { log.info("进入testLockTimeout方法 , 开始获取锁"); String key = "testLockTimeout"; RLock lock = redisson.getLock(key); // 20秒后自动释放锁 lock.lock(20, TimeUnit.SECONDS); log.info("获取锁成功 , 开始执行业务逻辑……"); try {TimeUnit.SECONDS.sleep(10L); } catch (Exception e) { e.printStackTrace();}; lock.unlock(); return "success";} /** * 尝试获取锁 , 15秒还没获取到就获取锁失败;获取到了会持有20秒 , 20秒后自动释放锁 * @return */@GetMapping("/testTryLockTimeout")public String testTryLockTimeout() { log.info("进入testTryLockTimeout方法 , 开始获取锁"); String key = "testTryLockTimeout"; RLock lock = redisson.getLock(key); boolean res = false; try {res = lock.tryLock(15, 20, TimeUnit.SECONDS); } catch (InterruptedException e1) {e1.printStackTrace(); } if (!res) {log.error("尝试获取锁失败");return "fail"; } else {log.info("获取锁成功 , 开始执行业务逻辑……");try {TimeUnit.SECONDS.sleep(10L); } catch (Exception e) { e.printStackTrace();};log.info("执行完业务逻辑 , 释放锁");lock.unlock();return "success"; }}


    推荐阅读