• ZooKeeper系列:实现分布式锁


    锁是为了在多线程的场景中保证数据安全而增加的一种手段,Java中常用的有CountdownLatch,ReentrantLock等单应用中的锁,在现在处处都是分布式的场景需求下就不能满足了,所以就出现了分布式锁。

    不同的物理节点有各自的线程,但是他们会访问同一个资源,但是不允许同一时刻访问,所以就有了分布式锁

    例如

    我们可以通过数据库编写sql来实现分布式锁,但是这种在高并发下性能会出问题,

    还有常用的redis实现分布式锁,这个是我们用的最多的一种高性能高并发的实现方式。

    今天介绍的一种是通过中间件zookeeper实现分布式锁,也是支持高性能高并发的。

    想想实现一个锁想到哪些关键点 ?

    争抢锁:只有一个人可以获取锁
    
    获得锁的节点挂了,临时节点 会自动释放
    
    获得锁的人,可以主动释放锁
    
    锁被释放,删除 其他人怎么知道
    
    主动轮训,监听心跳:存在延迟,节点多的情况话压力很大。
    
    复制代码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    根据zk的节点看看是否满足锁

    创建持久化节点

    zk是创建节点保存数据的,相同节点只允许创建一次,所以我们可以通过成功创建节点实现获取锁的情况。

    关键代码

    zk.create("/lock",  threadId.getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    复制代码
    
    • 1
    • 2

    结果:

    如图只有一个线程获取锁,其他线程都出现异常:NodeExists for /lock ,可以保证同一时刻只有一个线程获取锁。然后获得锁的线程逻辑执行结束后应该删除锁。

    存在的问题:如果线程崩溃了,锁就无法释放了,最终导致死锁

    持久化节点不行,持久化顺序节点自然也不行了

    创建临时节点

    临时节点:在客户端断开连接的时候就会自动删除

    关键代码:

    zk.create("/lock",  threadId.getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    
    • 1

    CreateMode.EPHEMERAL意思就是创建临时节点 ,也就是当线程崩溃,无法主动释放锁的时候,会自动删除,避免死锁。

    但是

    还存在的问题:没有获取锁的线程会出现错误,则需要不断重试,通过死循环直到获取锁。

  • 相关阅读:
    杂谈 跟编程无关的事情22
    Hystrix超时熔断机制源码分析
    经历多次面试后,来自美团面试官给我的建议(附:java岗经验分享)
    Claude: ChatGPT替代大语言模型
    华为NFC设置教程(门禁卡/公交卡/校园卡等)
    【数据结构】链表OJ第一篇 —— 移除链表元素 && 反转链表 && 合并两个有序链表
    【零基础入门MyBatis系列】第十五篇——分页插件与注解式开发
    聊聊Java的单元测试
    spring+redis docker
    MQ进阶面试题
  • 原文地址:https://blog.csdn.net/Huangjiazhen711/article/details/127767004