关于java:持续输出面试题之分布式锁

3次阅读

共计 2199 个字符,预计需要花费 6 分钟才能阅读完成。

分布式锁

1、在分布式系统环境下,一个办法在同一时间只能被一个机器的一个线程执行
2、高可用的获取锁与开释锁
3、高性能的获取锁与开释锁
4、具备可重入个性(可了解为从新进入,由多于一个工作并发应用,而不用放心数据谬误)
5、具备锁生效机制,避免死锁
6、具备非阻塞锁个性,即没有获取到锁将间接返回获取锁失败

基于 zookeeper 的分布式锁

1.zookeeper 的一些个性

  • 有序节点:如果以后有一个父节点为 /lock,咱们能够在这个父节点上面创立子节点;zookeeper 提供了一个可选的有序个性,例如咱们能够创立子节点“/lock/node-”并且指明有序,那么 zookeeper 在生成子节点时会依据以后的子节点数量主动增加整数序号,也就是说如果是第一个创立的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,顺次类推。
  • 长期节点:客户端能够建设一个长期节点,在会话完结或者会话超时后,zookeeper 会主动删除该节点。
  • 事件监听:在读取数据时,咱们能够同时对节点设置事件监听,当节点数据或构造变动时,zookeeper 会告诉客户端。以后 zookeeper 有如下四种事件:

1. 节点创立;
2. 节点删除;
3. 节点数据批改;
4. 子节点变更。

2. 实现
①客户端连贯 zookeeper,并在 /lock 下创立长期的且有序的子节点,第一个客户端对应的子节点为 /lock/lock-1,第二个为 /lock/lock-2,以此类推。
②客户端获取 /lock 下的子节点列表,判断本人创立的子节点是否为以后子节点列表中序号最小的子节点,如果是则认为取得锁,否则监听 /lock 的子节点变更音讯,取得子节点变更告诉后反复此步骤直至取得锁;
③执行业务代码;
④实现业务流程后,删除对应的子节点开释锁。

基于 curator 的 zookeeper 分布式锁实现

    public static void main(String[] args) throws Exception {
        // 创立 zookeeper 的客户端
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);

        CuratorFramework client = CuratorFrameworkFactory.newClient("10.21.41.181:2181,10.21.42.47:2181,10.21.49.252:2181", retryPolicy);

        client.start();

        // 创立分布式锁, 锁空间的根节点门路为 /curator/lock
        InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock");

        mutex.acquire();

        // 取得了锁, 进行业务流程
        System.out.println("Enter mutex");

        // 实现业务流程, 开释锁
        mutex.release();

        // 敞开客户端
        client.close();}

基于 redis 的分布式锁

1. 流程
1、服务 A 为了取得锁,向 Redis 发动如下命令: SET productId:lock 0xx9p03001 NX PX 30000 其中,”productId” 由本人定义,能够是与本次业务无关的 id,”0xx9p03001″ 是一串随机值,必须保障全局惟一(起因在后文中会提到),“NX” 指的是当且仅当 key(也就是案例中的 ”productId:lock”) 在 Redis 中不存在时,返回执行胜利,否则执行失败。”PX 30000″ 指的是在 30 秒后,key 将被主动删除。执行命令后返回胜利,表明服务胜利的取得了锁。
2、服务 B 为了取得锁,向 Redis 发动同样的命令: SET productId:lock 0000111 NX PX 30000 因为 Redis 内曾经存在同名 key,且并未过期,因而命令执行失败,服务 B 未能取得锁。服务 B 进入循环申请状态,比方每隔 1 秒钟 (自行设置) 向 Redis 发送申请,直到执行胜利并取得锁。
3、服务 A 的业务代码执行时长超过了 30 秒,导致 key 超时,因而 Redis 主动删除了 key。此时服务 B 再次发送命令执行胜利,假如本次申请中设置的 value 值为 0000222。
4、服务 A 执行结束,为了开释锁,服务 A 会被动向 Redis 发动删除 key 的申请。

2. 实现
加锁
客户端集成 Redisson,在加锁之前,首先须要通过 hash 算法选定集群内某一个 Redis Master,后续加锁、解锁等各种过程都是在这个 Redis Master 和与之绑定的 slave 节点之间。
执行 lua 脚本实现加锁
watch dog 主动延期
watch dog 是一个后盾线程,它会每隔 10 秒察看以后客户端是否依然持有锁,如果持有,阐明客户端可能依然在应用锁,因而缩短锁的残余生存工夫。
开释锁机制 如果执行 lock.unlock(),Redis 会找到上方 test 数据结构,将加锁次数减一。如果减完后发现加锁次数为 0,则阐明以后客户端不再持有锁,因而执行: del test 命令,从 Redis 中删除这条 key。

// 筹备为名为 "test" 的 key 加锁
RLock lock = redisson.getLock("test");
// 加锁
lock.lock();
// 解锁
lock.unlock();
正文完
 0