ZooKeeper 分布式锁实践(下):读写锁

栏目: 编程工具 · 发布时间: 5年前

内容简介:作者 | Sunny杏仁后端工程师,专注高并发和分布式编程,Golang爱好者。

作者 | Sunny

ZooKeeper 分布式锁实践(下):读写锁

杏仁后端工程师,专注高并发和分布式编程,Golang爱好者。

ZooKeeper 分布式锁实践(上篇)排它锁   中我们通过代码实践了如何使用 ZooKeeper 组件来实现排他锁。

排他锁简单易用,但是缺点也很明显:

  • 竞争压力大:当锁被占用之后,其他获取锁的操作只能阻塞等待;当锁释放后,所有等待锁的进程会在同一时刻争抢锁的使用权。

  • 羊群响应:锁释放后,会通知所有等待锁的进程,如果等待者特别多,一时间锁的竞争压力将会特别大。

简单来说就是: 通知范围太广、锁的粒度太大 。我们可以分别从这两个层面去寻找解决方案:

  • 缩小通知范围:等待锁的小伙伴们按先来后到的顺序排队吧,排好队了,接下来我只需要关心我前面一个节点的状态,当前一个节点被释放,我再去抢锁。

  • 缩小锁的粒度:锁不关心业务,但是可以简单地通过操作的读、写性质来二分锁的粒度:

    • 读锁:又称共享锁,如果前面没有写节点,可以直接上锁;当前面有写节点时,则等待距离自己最近的写节点释放( 删除 )。

    • 写锁:如果前面没有节点,可以直接上锁;如果前面有节点,则等待前一个节点释放( 删除 )。

    思考:为什么不是关注前面距离自己最近的写节点?

    如果两个写节点之间有读节点,必需等待读节点释放之后再进行写节点请求,否则会有不可重复读的问题。

数据结构 和排他锁一样,我们通过 ZooKeeper 的节点来表示一个读写锁的父节点,如 /SHARE_LOCK ,通过父节点下的临时自增子节点来表示一个读写操作请求,如 /SHARE_LOCK/R_0000000001  。整体数据结构如下图所示。

ZooKeeper 分布式锁实践(下):读写锁

算法

获取锁

获取锁的算法步骤:

  1. 开始尝试获取锁

  2. 如果持久化父节点不存在,则创建父节点

  3. 如果当前临时自增子节点不存在,则创建子节点

  4. 获取父节点下的所有子节点

  5. 在所有子节点中,查找序号比当前子节点小的前置子节点( 最近的兄节点 )有两种情况:

  • 读请求:查找比自己小的前置**写**子节点 ( 最近的兄节点 )

  • 写请求:查找比自己小的前置子节点 ( 最近的兄节点 )

  • 如果没有更小的前置子节点,则持有锁

  • 如果有更小的前置子节点,则监听该子节点被释放( 删除 )的事件

  • 释放 ( 删除 )子节点事件被触发后,重复第 1 步

  • 释放锁

    释放锁的算法与排他锁部分的释放锁算法相似,这里不再赘述。

    加锁、解锁流程

    加锁、解锁完整的流程图。

    ZooKeeper 分布式锁实践(下):读写锁

    代码实现

    子节点定义

    子节点属性

    • lockName  读写锁的名称,即父节点的名称

    • name  子节点的名称,格式为 : {请求类型:R/W}_{自增序号}   ( 子节点的路径为: {lockName}/{name}  

    • seq  子节点的自增序号,通过解析   name   属性   _   下划线分隔符后面的数字字符串来获取序号( ZooKeeper 创建临时自增节点时会自动分配 Int 范围内的序号 )

    • isWrite  子节点是否为写请求,通过解析   name   属性   _   下划线分隔符前面的英文字符来判断请求类型 :

      • R :读请求

      • W :写请求

    ZooKeeper 分布式锁实践(下):读写锁

    读写锁定义和初始设置

    读写锁的属性

    • lockName  读写锁的名称,即父节点的路径

    • locker  获取锁的请求方,即锁的持有者,释放锁时需要验证请求者与锁的持有者是否一致

    • isWrite  请求类型:

      • 读: false

      • 写: true

    读写锁的初始设置

    • 连接到 ZooKeeper 实例

    • 连接后,如果父节点不存在,则创建父节点

    ZooKeeper 分布式锁实践(下):读写锁

    尝试获取锁

    尝试获取锁的算法实现

    1. 获取或创建 ZooKeeper 子节点

    2. 获取当前子节点后,遍历所有的子节点,查找:

    • front  离当前子节点最近的兄节点:序号比当前子节点的序号小、且在小于当前序号的子节点中序号是最大的

    • fontWrite  离当前子节点最近的写、兄节点:序号比当前子节点的序号小、且在小于当前序号的子节点中序号是最大的、且为写子节点

  • 查找后,返回序号更小的兄节点:

    • 读请求:返回最近的写、兄节点,用于 Watch 监听释放( 删除 )事件

    • 写请求:返回最近的兄节点,用于 Watch 监听释放( 删除 )事件

  • 如果没有更小的子节点,返回 None   ,表示成功地获取了锁

  • ZooKeeper 分布式锁实践(下):读写锁

    ZooKeeper 分布式锁实践(下):读写锁

    同步获取锁

    同步获取锁的算法实现

    1. 尝试获取锁

    2. 如果没有兄节点,则成功持有锁

    3. 如果得到更小的兄节点,则监听该兄节点的释放( 删除 )事件

    4. 收到兄节点的释放( 删除 )事件通知后,重复第 1 步

    ZooKeeper 分布式锁实践(下):读写锁

    测试验证

    最后,通过一个简单的测试方法来验证读写锁的加、解锁过程:

    ZooKeeper 分布式锁实践(下):读写锁

    测试结果

    ZooKeeper 分布式锁实践(下):读写锁

    测试结果、分析

    # 请求方 操作 输出
    1 LOCK1_读 加锁:成功 [LOCK1] : Lock
    2 LOCK2_写 加锁:等待,因为有未释放的兄节点 LOCK1
    3 LOCK3_写 加锁:等待,因为有未释放的兄节点 LOCK2
    4 LOCK4_读 加锁:等待,因为有未释放的兄、写节点 LOCK3
    5 LOCK5_读 加锁:等待,因为有未释放的兄、写节点 LOCK3
    6 LOCK1_读 解锁:成功,通知到 LOCK2 [LOCK1] : Unlock
    7 LOCK2_写 收到通知,尝试加锁:成功 [LOCK2] : Lock
    8 LOCK2_写 解锁:成功,通知到 LOCK3 [LOCK2] : Unlock
    9 LOCK3_写 收到通知,加锁成功 [LOCK3] : Lock
    10 LOCK3_写 解锁成功,通知到 LOCK4、LOCK5 [LOCK3] : Unlock
    11 LOCK4_读 收到通知,尝试加锁:成功 [LOCK4] : Lock
    12 LOCK5_读 收到通知,尝试加锁:成功 [LOCK5] : Lock
    13 LOCK4_读 解锁:成功 [LOCK4] : Unlock
    14 LOCK5_读 解锁:成功 [LOCK5] : Unlock

    尾声

    通过 ZooKeeper 分布式锁实践,对它的接口最直观的感受就是 简单 。虽然它没有直接提供加锁、解锁这样的原语,但是当你了解了它的数据结构、接口和事件设计之后,加锁、解锁功能简直呼之欲出,实现起来毫无障碍,一切都是那么地合理、妥当。

    而 ZooKeeper 的能力远不止于此,就像前面提到的它能够十分轻松地实现诸如:数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁、分布式队列这些小菜,不得不佩服 ZooKeeper 设计者的抽象能力。本篇只是浅尝了 ZooKeeper 的基本能力,有关它的设计思路、实现细节仍待进一步发掘和探索。

    全文完

    以下文章您可能也会感兴趣:

    我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

    ZooKeeper 分布式锁实践(下):读写锁

    杏仁技术站

    长按左侧二维码关注我们,这里有一群热血青年期待着与您相会。


    以上所述就是小编给大家介绍的《ZooKeeper 分布式锁实践(下):读写锁》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

    查看所有标签

    猜你喜欢:

    本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

    智能家居:商业模式+案例分析+应用实战

    智能家居:商业模式+案例分析+应用实战

    陈国嘉 / 人民邮电出版社 / 2016-4 / 49.80元

    作为万物互联的关键一环,智能家居的出现和普及已经势不可当,以移动互联网为核心的新技术正在重构智能家居。只有成为智能家居行业的先行者,才能抢占“风口”。 《智能家居:商业模式+案例分析+应用实战》紧扣“智能家居”,从3个方面进行专业、深层次的讲解。首要方面是基础篇,从智能家居的发展现状、产业链、商业分析、抢占入口等方面进行阐述,让读者对智能家居有个初步的认识;第二个方面是技术篇,从智能家居的控......一起来看看 《智能家居:商业模式+案例分析+应用实战》 这本书的介绍吧!

    MD5 加密
    MD5 加密

    MD5 加密工具

    RGB CMYK 转换工具
    RGB CMYK 转换工具

    RGB CMYK 互转工具

    HSV CMYK 转换工具
    HSV CMYK 转换工具

    HSV CMYK互换工具