Zookeeper实践与应用--分布式锁实现

分布式锁

  • 分布式锁是控制分布式系统之间同步访问资源的一种方式,如果不同系统是同一个系统的不同主机之间共享一个或一组资源,那么访问这些资源的时候,往往需要通过一些呼哧手段来防止彼此之间的干扰保证统一性,因此需要分布式锁。
排他锁
  • 简称X锁,或写锁,独占锁,是一种基本的锁类型,如果事务T1对数据对象Q1加上排他锁,那么整个加锁期间,只允许事务T1对Q1进行读,写操作,其他任何事务不能对Q1操作,直到T1释放
定义锁
  • Java开发中有两种方式,synchronized机制和JDK5中的ReentrantLock,然而,在Zookeeper中,没有类似于这样的API可以使用,Zookeeper通过数据节点表示一个锁,例如/exclusive_lock/lock节点被定义位一个锁
    -
获取锁
  • 获取排他锁时,所有客户端调用create接口在/exclusive_lock节点下创建临时子节点/exclusive_lock/lock,Zookeeper保证只有一个客户端创建成功,我们认为这个创建成功的客户端就获取到锁,其他客户端需要在/exclusive_lock/lock节点上注册一个watcher监听,以便实时监听Lock节点变化
释放锁
  • /exclusive_lock/lock是一个临时节点,以下两种情况可认为释放
    • 当前获取锁的客户端机器宕机,ZooKeeper上的临时节点会被自动移除
    • 正常执行业务逻辑后,客户端自行删除临时节点
  • 无论上面两种哪一种,Zookeeper删除临时节点后/exclusive_lock/lock上注册Watcher监听的客户端都会收到Watcher通知,再次重新发起分布式锁的获取,重复以上流程,如下图所示排他锁流程
    在这里插入图片描述
共享锁
  • 共享锁简称S锁,又称为读锁,同样是一种基本锁,如果T1对Q1加上共享锁,那么当前事务只能多Q1进行读,其他事务也只能对这个数据加共享锁,直到所有共享锁都释放。下面借助ZooKeeper来实现共享锁
定义锁
  • 与排他锁一样,同样通过ZooKeeper节点表示锁,类似/shared_lock/[Hostname]-请求类型-序号,的临时顺序节点,例如/shared_lock/129.168.1.1-R-0000001那么这个代表一个共享锁
    在这里插入图片描述
获取锁
  • 客户端到/shared_lock这个节点下创建一个临时顺序节点,如果当前是读请求,那么就叉棍就如/shared_lock/129.168.1.1-R-0000001的节点,如果是写/shared_lock/129.168.1.1-W-0000001
判断读写顺序
  • 根据共享锁定义,不同事务可以同一时间多一个数据读,而更新只能单独进行,我们通过Zoo keep如下方式来进行:
    1. 创建节点后,获取/shared_lock节点下的所有子节点,并对该节点注册子节点变化的Watcher监听
    2. 确定字节节点序号在所有子节点中顺序
    3. 对于读请求:如果没有比字节序号小的子节点,或者是所有比字节序号小的子节点都是读,表明字节已经成功获取共享锁,同时开始读
    4. 对于写请求:如果子不是序号最小的子节点,进入等待
    5. 接收Watcher后,重复步骤1
释放锁
  • 与排他锁一致,删除释放
  • 用如下图解释
    在这里插入图片描述
羊群效应
  • 在规模不大,10台机器作业,上面方案能有很高的效率,如果规模变大,会存如下的这种问题,在判断读写顺序的时候,会给子节点列表添加watcher监听,这样任何一个子节点修改都会有watcher通知信息,如下图:
    在这里插入图片描述
  1. 192.168.0.1 这条机器首先进行读,然后删除节点
  2. 余下四台机器都能收到子节点移除通知,然后从/shared_lock节点上获取一份新子节点列表
  3. 每个机器判断自己读写顺序,其中192。168.0.2这台机器检测自己是最小序号,开始写操作,余下继续等待
  4. 继续2 步骤
  • 上面操作是共享锁实现主要步骤,当任意一个子节点变化后,Watcher通知会给所有其他集群通知,然而现实是这个通知其实只对192.168.0.2这个机器有用,对其他节点来说无任何作用。
  • 后果: 分布式竞争中,满天飞的无效watcher通知,和无效的子节点获取,然后进行等待,无意义的操作会消耗非常多的系统性能,对Zookeeper服务器造成巨大性能影响和网络冲击,更严重的是如果同一时间有多个节点对应的客户端完成事务或是事务中断引起节点变化,Zookeeper需要在短时间内向其余客户端发送大量事件通知—这就是羊群效应。
改进后的分布式锁实现
  • 主要改动:每个竞争者,只需关注/shared_lock节点下序号比自己小的节点是否存在即可:
  1. 客户端create创建"类似/shared_lock/[Hostname]-请求类型-序号" 的临时节点
  2. 客户端调用getChildren接口获取所有已经创建子节点列表(不注册watcher)
  3. 如果无法获取共享锁,调用exist对比比自己小的节点注册watcher(id比自己小,可用时间戳)
  4. 读请求:向比自己序号小的最后一个写请求节点注册watcher监听
  5. 写请求:向比自己序号小的最后一个节点注册watcher监听
  6. 等待watcher通知,继续2 步骤
  • 如下图:
    在这里插入图片描述
注意
  • 并不是一定每次都用改进后的,因为改进版本流程复杂,如同我们在多线程并发编程中会尽量缩小锁的范围,对分布式锁的实现改进也是这样的思路,对开发时候来说,应该具体情况具体分析:集群规模不大,网络资源丰富,第一张分布式锁简单,如果集群达到一定程度,希望能精细化处理分布式锁,可以用第二种分布式锁实现。

上一篇Zookeeper实践与应用-- Nginx负载均衡差异
下一篇Zookeepe实践与应用–分布队列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于 Blazor Server Side 的一些杂项, 感想

在2016年, 本人就开始了一个内部项目, 其特点就是用C#构建DOM树, 然后把DOM同步到浏览器中显示. 并且在一些小工程中使用.3年下来, 效果很不错, 但因为是使用C#来构建控件树, 在没有特定语法的情况下, 代码风格不是那么好.典型的风格大概是这样的:这个模式挺好的, 有点嫌弃C#代…

重现江湖!大数据高并发——架构师秘籍

大数据高并发的话题屡见不鲜,各种应对的方式方法也四处可见。然而笔试面试中一问就懵,简直是高薪拦路虎。为什么呢?究其原因,还是思路不清晰,缺乏实操,所以一问就倒。作为专注.Net领域十几年的老司机&#…

[剑指offer]面试题4:替换空格

面试题4:替换空格 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”,则输出“We%20are%20happy.”。 ❖ 时间复杂度为O(n2)的解法,不足以拿到Offer…

Zookeepe实践与应用--分布队列

分布式队列 接触到不少分布式队列的产品,比如,ActiveMq,RocketMQ,kafka等消息中间价,现在我们看看Zookeeper实现的分布式队列。分布式队列简单讲就可以分两个部分,一种是先进先出,另外一种是等…

[剑指offer]面试题5:从尾到头打印链表

面试题5:从尾到头打印链表 题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。 链表结点定义如下: struct ListNode {int m_nKey;ListNode *m_pNext; };通常打印是一个只读操作,我们不希望打印时修改内容。 假设面…

ASP.NET Core+Quartz.Net实现web定时任务

点击蓝色“Dotnet Plus”关注我哟加个“星标”,每天清晨 07:25,干货推送!作为一枚后端程序狗,项目实践常遇到定时任务的工作,最容易想到的的思路就是利用Windows计划任务/wndows service程序/Crontab程序等主机方法在主…

Redis基础数据结构内部实现简单介绍

5种基础数据结构 Redis有5种基础数据结构,分别是:String(字符串),list(列表),hash(字典),set(集合),zset&…

[剑指offer]面试题7:用两个栈实现队列

面试题7:用两个栈实现队列 题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。 用两个栈模拟一个队列的操作: 代码如下: #include …

ASP.NET CORE WEBAPI文件下载

最近要使用ASP.NET CORE WEBAPI用来下载文件,使用的.NET CORE 3.1。考虑如下场景:文件是程序生成的。文件应该能兼容各种格式。浏览器可以感知进行下载。准备经过简单的调研,得到以下结论。ASP.NET CORE 提供FileResult这种类型的ActionResul…

Redis高级数据结构原理解析-bitmap,hyperloglog

Redis 位图 开发过程中,我们可能遇到这种场景记录用户的打卡情况,签到情况,这些场景只有两种结果,有或者没有,加入记录的数据量比较大,比如用一年的数据,如果用Redis中普通key/value&#xff0…

[剑指offer]面试题8:旋转数组的最小数字

面试题8:旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数…

.NET Core + Kubernetes:快速体验

Kubernetes[1] 是目前非常主流的容器编排工具,在应用创建、应用部署、应用扩容、应用更新等方面都非常的方便,而且在应用故障时,也可以快速自愈。所以基于微服务架构下的产品,了解 Kubernetes 的使用是非常必要的,我猜…

Redis流量控制策略

Reids 简单流控 流控是分布式领域一个被经常用到的一个计数,当系统承载能力有限的时候,如何组织计划外的请求继续对系统施加压力,这是一个需要解决的问题,在系统承载达到峰值的时候,我们需要弃车保帅,保证…

[剑指offer]面试题9:斐波那契数列

面试题9:斐波那契数列 题目一:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下: ❖ 效率很低的解法,挑剔的面试官不会喜欢 代码如下: long long fib(…

海底捞涨价,有错吗?

此前,有媒体报道,海底捞某些门店的菜品除了少部分维持原价,大部分都涨价了。随后,广大网民纷纷对此发表了看法。有人表示理解,理由是餐饮业在疫情期间损失巨大,此前也有一些餐饮业老板表达了资金链断裂的担…

Redis分布式锁奥义

分布式锁 分布式系统进行逻辑处理的时候,经常会遇到并发问题,例如直播场景中,用户需要连麦主播,当多个用户在同一个时刻一起连麦时候,应该保证只有一个用户能连麦成功,我们改怎么保证这种业务场景下保证数…

.NET Core + Kubernetes:Pod

在 .NET Core Kubernetes:快速体验 文章中,已经实现将一个 .NET Core API 服务部署在 Kubernetes 集群中,接下来将逐步了解 Kubernetes 中各核心模块。首先当然是 Pod,我相信 Pod 是在接触 Kubernetes 时听到较多的一个词语&…

[剑指offer]面试题10:二进制中1的个数

面试题10:二进制中1的个数 题目:请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。 ❖ 可能引起死循环的解法 代码如下: …

LBS解决方案

LBS解决方案 LBS(基于地理位置的服务)服务是现在移动互联网中比较常用的功能,例如外卖中我附近的店铺,通常是以客户位置坐标为中心,查询一定范围内的店铺信息,按照距离由近及原进行倒叙排序 方案一&#…

[剑指offer]面试题13:在O(1)时间删除链表结点

面试题13:在O(1)时间删除链表结点 题目:给定单向链表的头指针和一个结点指针,定义一个函数在 O(1)时间删除该结点。链表结点与函数的定义如下: struct ListNode {int value;ListNod…