本文作者:HelloGitHub- 老荀
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,收费开源、乏味、入门级的 ZooKeeper 教程,面向有编程根底的老手。
我的项目地址:https://github.com/HelloGitHu…
明天开始咱们将深刻 ZK 集群相干常识~
一、为什么须要集群
1.1 马果果病了
ZKr~老规矩~
马果果 毕竟年纪大了,这办事处的事件越来越多,终于有一天扛不住,生病了,住院了,听医生说要劳动好几天。办事处负责人不在的话就不能给村民们提供服务了。大家平时也要留神身材啊~
一连好几天都没收到告诉的 坤坤 急死了,还有其余十分依赖办事处的村民们都一起跑去村委会投诉了,村委会也很无奈啊,最终磋商了下,决定请村里权威同样很高的驰名企业家,太极爱好者并且还是村里首富的 马小云 成立第二办事处,地点离原来的办事处也很近,同样负责解决之前 马果果 办事处的事务。马小云 之前也是办事处的常客,对其中的流程曾经是十分分明了,始终想为人民做实事的他,怅然许可了下来。
而且曾经有了之前的成功经验,所以间接照搬之前的解决流程就行了。然而仔细的村民很快就发现了问题,之前在 马果果 的办事处很多曾经记录过的事务,当初都隐没了,在新的办事处这里须要从新注销,十分不不便,然而 马小云 示意也没方法,马果果 病得太忽然了,还没交接过,只能示意让大家忍忍。
就这样,过了两周,马果果 痊愈入院了,在住院期间他也曾经得悉了 马小云 这两周代他帮忙村民解决大小事务,他心田非常感激 马小云 所做的所有,热爱工作的他,第一工夫就回到了工作岗位,把办事处的大门从新关上,也播送通知了村民,本人这里又能办理事务了,心愿大家能够持续过去。因为 马小云 毕竟业务能力稍差点,处理速度没那么快,导致第二办事处排队更重大了。
听到第一办事处又倒闭的村民们非常高兴,毕竟谁也不心愿排长队浪费时间,于是都来到了第一办事处
然而呢,马果果 劳动了两周,这两周期间村民的注销的事务,他全副都没有,村民们纷纷表示这不行啊:“咱们不论你们有几个办事处,你们得保证数据都是统一的啊!”。村委会也批准村民的诉求,勒令两个办事处整改,须要解决这个问题!而且因为 马果果 资格更老,更有教训,所以让 马小云 所有听 马果果 的指挥,计划也由 马果果 去想方法出台。
1.2 马果果的新规定
马果果 不愧姜还是老的辣,很快就想出了一个好方法,出台了一系列的规定:
- 数据必须以 马果果 为主
- 两个办事处间须要买通分割,随时放弃沟通
- 之前把村民前来注销的事务辨别成读和写,是十分正确的决定。之后写操作必须通过 马果果 ,读操作 马小云 能够自行解决
然而光出台规定还不够,还须要一系列能够落地的操作,于是 马果果 向村委会申请,办事处须要扩招人,村委会决定让 马果果 撒手干,批准了他的申请。
马果果 把本人办公室的安排从新调整了下变成了这样:
简略介绍下新来的共事们:
- 小 PS负责辨别村民的申请是否须要发动提案,并把申请再次转发给 小 C 以及 小 S
- 小 C 负责管理 小 PS提案的提交工作,这个职位十分重要,所以 马果果 很有公心的请了一个妹子来承当这个职位
- 当初的 小 S 不再和 小 F 打交道了而是和 小 A 打交道,等他归档完后就会告诉 小 A
- 因为当初有两个办事处了,所以须要延聘一个话务员,专门负责和隔壁的 马小云 办事处进行沟通
光是安顿好本人还不够,马果果 替马小云 也设计了一套新的办公室计划:
和 马果果 不太一样,这里也简略介绍下:
- 应用 小 FR替换了原来的 小 P 作为办事处第一接待人
- 小 S 也不和 小 F 打交道了,间接和 小 SA打交道,等他归档完就会告诉 小 SA
- 和 马果果 一样也延聘了一个话务员负责和 马果果 进行分割
原来只有 马果果 负责的一个办事处,随着 马果果 的病倒,村民的业务就无奈持续开展了,这就是单点故障,所以在原来的根底上减少一个办事处,能够减少整个办事处的吞吐量的同时也能够在一个办事处无奈提供服务时,不至于导致村民们无奈应用,这就是高可用。这也是为什么须要集群部署的最重要起因!
二、第一办事处
引入了集群前,本来一个节点数据本人外部运作治理就行,十分不便,然而引入集群后,集群间的节点如何沟通成了问题,让咱们一起来看看 马果果 的新员工们是怎么做的吧?
不同于之前的单机流程,当初流程简单了很多,减少了很多出场的人物,为了让大家能疾速记忆,我这里提前把名字的由来剧透给大家:
- 小 P 对应代码中的
PrepRequestProcessor
负责预处理 - 小 PS对应代码中的
ProposalRequestProcessor
负责写事务的提案 - 小 C 对应代码中的
CommitProcessor
负责对事务申请提交 - 小 S 对应代码中的
SyncRequestProcessor
负责数据的归档 - 小 A 对应代码中的
AckRequestProcessor
负责通知 马果果 以后事务的 ACK 信息 - 小 F 对应代码中的
FinalRequestProcessor
负责对内存模型的操作
2.1 负责的小 PS
原先 小 P 在第一工夫询问村民后,并对当次申请进行标记后,就会把该申请转发给 小 PS,小 PS做的事件也很简略:
次要就是看是不是写申请,如果是的话就要发动提案并且本地要告诉 小 S 归档。
2.2 繁忙的小 C
小 C 是除了 小 F 最繁忙的人了,她在承受到上一个共事传递过去的申请后会:
不是说 小 C 是最忙的吗?就这?
别急,小 C 的处理过程确实是比拟繁琐,然而我这里先给出简略的流程,最重要的提交操作,我临时不开展,之后会讲~
2.3 小 S 和小 A
小 S 解决的流程产生了扭转,他后面的共事不再是 小 P ,而他解决完归档后也不再把申请交给 小 F 而是交给 小 A ,而 小 A 做的事件更简略,仅仅只是通知 马果果 办事处此次事务申请归档胜利,其实就是 ACK。
2.4 话务员
为了更顺畅的和隔壁的 马小云 办事处互相沟通,马果果 定下了几个暗号,而话务员则负责用暗号去告诉 马小云
- REQUEST
- PROPOSAL
- ACK
- COMMIT
当然暗号不止这些,之后有遇到再说。
在具体开展流程细节前,我感觉还是要把 马小云 的流程简略介绍下,等两边都介绍完后,再合并在一起解说~
三、第二办事处
同样因为当初有两个办事处的关系,马小云 也无奈单纯应用之前的流程,并且新员工中有显著区别于 马果果 的小 FR和 小 SA,这里也介绍下:
- 小 FR对应代码中的
FollowerRequestProcessor
负责 马小云 这边的预处理 - 小 SA对应代码中的
SendAckRequestProcessor
和 马果果 的小 A 相似,通过话务员告诉 马果果 以后事务的 ACK
3.1 同样仔细的小 FR 和小 SA
和 小 PS有点相似,也是须要辨别读写,但区别是写申请须要告诉 马果果。
小 SA的逻辑是承受到 小 S 的归档信息后,把 ACK 告诉给 马果果,太简略了就不画图了。
四、实战
刚刚咱们把两个办事处逻辑都大抵介绍了下,然而太过于碎片化了和简略,所以上面开始进入实战环节,会别离假设不同的业务场景和复杂程度,从简略到简单,把从村民来办事处注销事务到办事处解决实现之间的逻辑依照工夫程序进行整顿。
前排揭示,多图预警
4.1 一个读申请(马果果)
假如咱们的 坤坤 来到 马果果 的办事处,想要查问 鸡太美 最新的跳舞视频 / 鸡太美 / 跳舞
小 P 首先晓得 坤坤 是非法的村民,而后询问得悉,此次来办事处的目标是为了查问,就会把此次注销标记为读申请,就把 坤坤 的申请交给下一个柜台的 小 PS。
小 PS拿到申请后,先把申请一成不变的给到了 小 C ,之后通过 小 P 的标记晓得了这是一个读申请,便不做其余解决。
小 C 取到这个申请后也发现这是一个读申请,所以也间接交给了 小 F ,本人不须要其余解决。
小 F 拿出了小红本查看,假如 / 鸡太美 / 跳舞
存在,把对应的数据就返回给了 坤坤。
坤坤 拿到了后果称心如意的回去了并且定好了 17 点的闹钟守在电脑前等着 鸡太美 的开播了
能够看到一个读申请的解决流程是非常简单的,别急,难度会一点点的减少哦
4.2 一个读申请(马小云)
同样还是咱们的 坤坤 ,然而这次来到 马小云 的办事处,同样想要查问 鸡太美 最新的跳舞视频 / 鸡太美 / 跳舞
与 马果果 不同的是,先解决 坤坤 申请的是 小 FR,他会先把申请发给 小 C ,之后通过询问 坤坤 得悉此次目标是查问,就不会做其余解决。你可能会问,小 FR不须要对 坤坤 的身份进行核实吗?我认为可能是因为以后是读申请所以不会对数据造成毁坏,所以并没有做校验。
之后的 小 C 和 小 F 和 马果果 版本没有任何不同,就不赘述了。让咱们进入下一个难度吧。
4.3 一个写申请(马果果)
写申请就和读申请不一样了,因为依据 马果果 的规定,两个办事处的数据得保持一致,所以就会波及到如何告诉对方了,让咱们一起来看看吧。
假如咱们的 坤坤 来到 马果果 的办事处,想要为本人创立一个事务注销 / 坤坤 / 日记
小 P 晓得 坤坤 是非法的村民并且 坤坤 此次的目标是写数据,所以就给 坤坤 的申请打了一个写事务的标记,就把申请交给了 小 PS了。
小 PS还是先把申请交给了 小 C 先解决。
小 C 看到此次是写申请就拿出本人的小本子记了下来
小 PS曾经得悉此次是写申请。留神!这里开始就不一样了,小 PS会让话务员给 马小云 办事处打电话。
话务员通知他们这次的申请并带着 PROPOSAL 的暗号。
这里必须要提一下事务编号,为了严格保障村民来注销的程序,马果果 还规定了必须给每一次的写事务调配一个惟一的递增数字,从 0 开始。
并且告诉 马小云 的同时,马果果 也会把以后的提案记录下来:
这时候咱们把视角切换到 马小云 这边,马小云 的话务员承受到 马果果 那边的 PROPOSAL 的暗号后,会间接让本人这边的 小 S 进行归档,马小云 则会在备忘录里记录:
等 小 S 归档完后,就会把 坤坤 的申请交给 小 SA
小 SA事件很简略就是让话务员告诉 马果果 归档实现
接着 马小云 这边的话务员就会给 马果果 办事处打电话告诉他们归档实现
视角再一次回到 马果果 这边,在 小 PS让话务员告诉 马小云 那边的同时 小 S 也没闲着,进行了归档的操作
小 S 归档实现后,会把申请交给 小 A ,小 A 做的事件很简略就是告诉 马果果 此次归档实现。
咱们这里假如先是 马果果 这边的 小 S 归档实现,马果果 在收到归档实现音讯后会拿出刚刚的小本本找到对应的提案记录,并把曾经归档实现的给记下来:
因为 马果果 晓得一共有两个办事处,所以还须要期待 马小云 的归档实现告诉。
过了一会会,马小云 的归档告诉也来了,就再在小本本上记下来
至此,两个办事处对于以后提案都曾经实现了归档,马果果 就会让话务员告诉 马小云 能够提交了,并且会将小本本上事务 0 的这条记录删除(图就不画了)。
告诉完,马果果 就让 小 C 能够进行提交了
小 C 就会拿出刚刚的备忘录,找到 坤坤 的期待解决的事务的第一条(以后场景只有一条)就是:创立 / 坤坤 / 日记
。就马上把这个事务交给了 小 F 解决
小 F 就会在小红本上把以后事务记录下来:
交给 小 F 后,小 C 发现 坤坤的 所有事务都解决完了,就把他从备忘录上删除了:
让咱们把视角再切到 马小云 , 马果果 这边的 小 C 在解决的时候,马小云 的话务员收到了来自 马果果 的 COMMIT 音讯并通知了 马小云 ,而 马小云 会从备忘录中找出最早的一条申请就是:坤坤,创立,/ 坤坤 / 日记
,而后就会把该申请交给 小 C
至于之后 小 C 解决以及解决完交给 小 F 解决,和 马果果 那边的逻辑是一样的,就不赘述了。
至此,一个写申请(马果果)的根本流程就算实现了。
4.4 一个写申请(马小云)
假如咱们的 坤坤 这次来到 马小云 的办事处,同样为本人创立一个事务注销 / 坤坤 / 日记
小 FR先把申请交给了 小 C ,而后发现了 坤坤 这次来办理的是写申请,就会要求话务员告诉 马果果。
话务员就会打电话给 马果果 办事处,并且通知他们此次的申请以及携带上 REQUEST 暗号
而 马小云 这边的 小 C 会和之前的例子一样,也会在备忘录里记录下
当初咱们把视角切到 马果果 这边,话务员承受到 REQUEST 的申请后,通知了 马果果 ,而 马果果 会间接把这个申请交给 小 P 去解决
好像就是 坤坤 间接来本人办事处办理业务一样,从 小 P 之后的流程和之前的例子能够说是截然不同了,就不赘述了。
我当初举了 4 种无并发的场景,除了写申请都很简略,我这里就再把写申请 马果果 从新用图画一遍
为了简洁图中省略了故事中的话务员以及 马果果 和马小云,雷同色彩代表处于同一时间解决,工夫程序从小到大。
好了,让咱们持续晋升难度进入并发实战,作为一个公共的办事处是不可能同时只解决一件事务的!
4.5 多个村民多种申请
这一章节我不会再从头开始画图了,只画重要的局部,咱们先看看,如果有多个村民的话,那几个小本本是怎么记的吧!
小 C 的备忘录的特点总结:
- 以村民作为 key,之后的申请是依照申请的程序摆放的队列
- 队列中的第一个申请必定是写申请,如果是读申请的话,就基本不会记录
- 当村民对应的申请队列为空后,整条记录删除
咱们以图中的 坤坤 举例,假如当初期待的申请是这样的(我省略了门路,这里只关怀事务的类型)
当第一个创立的申请入队后,之后的查问申请也无奈被执行,都须要等到创立申请执行结束后能力持续,所以当第一个创立的申请被提交后,之后的查问 1、查问 2、查问 3 会被立马按程序移除出队列并执行,而查问 4 则须要期待后面的删除和创立全副提交后才会被执行。
这样的逻辑保障了,同一个客户端的申请是依照工夫程序执行的,不会呈现后到的读申请先于后面的写申请执行,造成脏读,然而须要留神的是不同的客户端的程序是无奈保障的,很可能 坤坤 的创立申请还未提交,之后 东东 的查问操作就能被返回了。
马果果 的小本本如果有多条记录的话就是这样
你可能会问:鸡太美 的那条记录不是归档实现了吗,为什么还在小本本里?因为 ZK 必须保障事务执行的程序!所以只有有比以后事务编号小的其余事务依然未提交,本事务就不能提交,图里就是 鸡太美 必须等到 坤坤 和东东 都提交完能力进行提交!
马小云 这边也有一个备忘录,如果有多条记录的话会是这样:
这个备忘录其实是一个先进先出的队列,每次 马小云 的提交会从队列中移除最后面的一条记录来操作。
故事差不多讲完了,有些细节用程序员的语言再说一下,我其实省略了两个处理器:
ToBeAppliedRequestProcessor
这个处理器在 马果果 这边才是紧接着 小 C 的,然而我个人感觉下来没什么用就不讲了,大家有趣味能够去理解下LeaderRequestProcessor
这个处理器才是 马果果 的第一个处理器,他的逻辑波及到会话、ACL,其余就没什么用,留到之后有机会讲
大家先看下这个图:
用红框标记的都是线程对象,次要逻辑都在 run
办法中,小 P 和 小 S 咱们之前就讲过了,这里就多了 小 C 和 小 FR。这里我得提一下,凡是你们只有在 ZK 中看到线程对象,那么他基本上是应用了生产者 - 消费者的模型,对象外部保护了一个阻塞队列,我这次就不画图了,因为重要的逻辑之前都曾经讲了。
画了这么多图,这里先进行下小结:
- 马果果 就是咱们平时在 ZK 中听到的 Leader 节点,负责对写事务申请发动提案并最终决定提交
- 马小云 对应就是 ZK 中的 Follower,只能单独解决读申请,写申请须要转发给 Leader 去解决
- 读申请无论客户端申请给哪个服务端的节点,解决流程都绝对简略,可能简直不须要节点之间的通信,本人就能解决(前提是没有待处理的写申请)
- 写申请如果客户端申请到的是 Leader,Leader 就会对此次事务申请在集群中发动提案,承受到提案的 Follower 各自进行归档,并返回给 Leader 胜利的 ACK 信息,Leader 对 ACK 进行统计,达到集群数量半数以上就集群中发动 COMMIT 申请,Follower 们接管到提交申请后,才会批改各自内存中的数据
- 写申请如果客户端申请到的是 Follower,Follower 在本地做简略记录后就会把申请转发给 Leader 去解决,之后和上一条是一样的状况
- 分布式事务的实践中是有回滚阶段的,当集群中的节点本地提交失败后,会告诉 Leader 失败信息,而 Leader 统计 ACK 之后发现本次事务无奈提交就会发送回滚的申请给各个节点。然而!很遗憾我并没有在 ZK 的源码中找到和事务回滚无关的逻辑(当然也很有可能是我忽略了,如果你晓得逻辑在哪儿的话,请肯定通知我),我当初的认为 小 S 解决归档的时候是不容许失败的,如果失败报错了,整个服务节点会报错退出
五、剧透
在本篇文章的最初,咱们再看看动物村又产生了哪些故事吧。
马果果 毕竟年事已高,须要定期去医院进行体检,就会耽搁办事处这边的工作,而慢慢的随着工夫的推移,马小云 的业务能力越来越强了,心里就产生了:凭什么我要听这老头的?于是被动向村委会提议,倡议 Leader 的人选要进行选举,不能就始终让 马果果 占着这个位子,村委会听后也觉得很有情理,于是拉来 马果果 一起磋商,马果果 必定不能批准啊,然而无奈 马小云 毕竟是首富,很快就通过高低打点让村委会统一通过了这个倡议
然而当初只有两个办事处,如果单方各执一词,就平票了,所以村委会再次通过磋商决定引入第三个办事处,这个新办事处的负责人抉择了村里的驰名企业家 马小腾,这样就不会呈现平票的状况,具体选举规定如下:
- 每天三个办事处倒闭前必须要先投票选出一个 Leader
- Leader 必须是经手解决过事务编号最大的
- 须要各个办事处半数以上的批准
- 所有以 Leader 为主,读写申请恪守之前 马果果 的定下的流程
- 当 Leader 无奈处理事务的时候,须要立刻选出新的 Leader,选出之前办事处不能对外提供服务
所以当初有了三个办事处成了这样
所以下一篇的主题大家应该晓得了吧~就是:选举!会讲讲 ZK 集群是如何选举出 Leader。敬请期待吧~
老规矩,如果你有任何对文章中的疑难也能够是倡议或者是对 ZK 原理局部的疑难,欢送来仓库中提 issue 给咱们,或者来语雀话题探讨。
地址:https://www.yuque.com/kaixin1…
老哥们转评赞安顿一下好吗,ZKr~