博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Zookeeper--数据同步
阅读量:2444 次
发布时间:2019-05-10

本文共 3577 字,大约阅读时间需要 11 分钟。

数据同步

ZooKeeper集群服务器启动的过程中,整个集群完成Leader选举之后,Learner 会向Leader 服务器进行注册。当Learner 服务器向Leader完成注册后,就进入数据同步环节。

简单地讲,数据同步过程就是Leader服务器将那些没有在Learner服务器上提交过的事务请求同步给Learner服务器,大体过程如下图所示。

在这里插入图片描述

获取Learner状态

在注册Learner的最后阶段,Learner服务器会发送给Leader服务器-一个ACKEPOCH数据包,Leader 会从这个数据包中解析出该Learner的currentEpoch和lastZxid。

数据同步初始化

在开始数据同步之前,Leader 服务器会进行数据同步初始化,首先会从ZooKeeper的内存数据库中提取出事务请求对应的提议缓存队列(用“提议缓存队列”来指代该队列): proposals, 同时完成对以下三个ZXID值的初始化。

  • peerLastZxid:该Learner服务器最后处理的ZXID。
  • minCommittedLog: Leader服务器提议缓存队列committedLog中的最小ZXID。
  • maxCommittedLog:Leader服务器提议缓存队列committedLog中的最大ZXID。

ZooKeeper集群数据同步通常分为四类,分别是:

  • 直接差异化同步(DIFF 同步)
  • 先回滚再差异化同步(TRUNC+DIFF 同步)
  • 仅回滚同步(TRUNC 同步)
  • 全量同步(SNAP同步)。

在初始化阶段,Leader服务器会优先初始化以全量同步方式来同步数据。当然,这并非最终的数据同步方式,在以下步骤中,会根据Leader和Learner服务器之间的数据差异情况来决定最终的数据同步方式。

直接差异化同步(DIFF同步)

场景:peerlastZxid介于minCommittedLog和maxCommittedLog之间

对于这种场景,就使用直接差异化同步(DIFF 同步)方式即可。Leader 服务器会首先向这个Learner发送一个DIFF指令,用于通知Learner“进人差异化数据同步阶段,Leader服务器即将把一些Proposal同步给自己”。

在实际Proposal同步过程中,针对每个Proposal,Leader服务器都会通过发送两个数据包来完成,分别是PROPOSAL内容数据包和COMMIT指令数据包一这 和ZooKeeper运行时Leader和Follower之间的事务请求的提交过程是一致的。

举个例子来说,假如某个时刻Leader服务器的提议缓存队列对应的ZXID依次是:

0x500000001 0x500000002 0x500000003 0x500000004 0x500000005

而Learner服务器最后处理的ZXID为0x500000003,于是Leader服务器就会依次将0x500000004和0x500000005 两个提议同步给Learner 服务器,同步过程中的数据包发送顺序如下:

在这里插入图片描述

通过以上四个数据包的发送,Learner服务器就可以接收到自己和Leader服务器的所有差异数据。Leader 服务器在发送完差异数据之后,就会将该Learner 加入到forwardingFollowers或observingLearners队列中,这两个队列在ZooKeeper运行期间的事务请求处理过程中都会使用到。随后Leader 还会立即发送一个NEWLEADER指令,用于通知Learner,已经将提议缓存队列中的Proposal 都同步给自己了。

再来看Learner对Leader发送过来的数据包的处理。根据上面讲解的Leader服务器的数据包发送顺序,Learner会首先接收到一个DIFF指令,于是便确定了接下来进入DIFF同步阶段。然后依次收到表中的四个数据包,Learner 会依次将其应用到内存数据库中。紧接着,Learner还会接收到来自Leader 的NEWLEADER指令,此时Learner就会反馈给Leader一个ACK消息,表明自己也确实完成了对提议缓存队列中Proposal的同步。

Leader在接收到来自Learner 的这个ACK消息以后,就认为当前Learner已经完成了数据同步,同时进入“过半策略”等待阶段——Leader 会和其他Learner 服务器进行上述同样的数据同步流程,直到集群中有过半的Learner机器响应了Leader这个ACK消息。一旦满足“过半策略”后,Leader服务器就会向所有已经完成数据同步的Learner发送一个UPTODATE指令,用来通知Learner已经完成了数据同步,同时集群中已经有过半机器完成了数据同步,集群已经具备了对外服务的能力了。

Learner在接收到这个来自Leader的UPTODATE指令后,会终止数据同步流程,然后向Leader再次反馈一个ACK消息。

整个直接差异化通过过程中涉及的Leader和Learner之间的数据包通信入下图:

在这里插入图片描述

先回滚再差异化同步(TRUNC+DIFF同步)

场景:针对上面的场景,我们已经介绍了直接差异化同步的详细过程。但是在这种场景中,会有一个罕见但是确实存在的特殊场景:设有A、B、C三台机器,假如某一时刻B是Leader服务器,此时的LeaderEpoch为5,同时当前已经被集群中绝大部分机器都提交的ZXID包括: 0x500000001和0x500000002。此时,Leader 正要处理ZXID:0x500000003,并且已经将该事务写人到了Leader 本地的事务日志中去一就在 Leader恰好要将该Proposal发送给其他Follower机器进行投票的时候,Leader服务器挂了,Proposal没有被同步出去。此时ZooKeeper集群会进行新一轮的Leader选举,假设此次选举产生的新的Leader是A,同时Leader_Epoch变更为6,之后A和C两台服务器继续对外进行服务,又提交了0x600000001 和0x600000002两个事务。此时,服务器B再次启动,并开始数据同步。

简单地讲,上面这个场景就是Leader服务器在已经将事务记录到了本地事务日志中,但是没有成功发起Proposal流程的时候就挂了。在这个特殊场景中,我们看到,peerLastZxid、minCommittedLog和maxCommittedLog 的值分别是0x500000003、 0x500000001 和0x600000002,显然,peerLastZxid 介于minCommittedLog和maxCommittedLog之间。

对于这个特殊场景,就使用先回滚再差异化同步(TRUNC+DIFF同步)的方式。当Leader服务器发现某个Learner包含了一条自己没有的事务记录,那么就需要让该Learner进行事务回滚一回滚到Leader服务器上存在的,同时也是最接近于peerLastZxid的ZXID。在上面这个例子中,Leader会需要Learner回滚到ZXID为0x500000002的事务记录。

先回滚再差异化同步的数据同步方式在具体实现上和差异化同步是一样的,都是会将差,异化的Proposal发送给Learner。同步过程中的数据包发送顺序如下表所示。

在这里插入图片描述

仅回滚同步(TRUNC同步)

场景:peerLastZxid大于maxCommittedLog

这种场景其实就是上述先回滚再差异化同步的简化模式,Leader会要求Learner回滚到ZXID值为maxCommitedLog对应的事务操作。

全量同步(SNAP同步)

场景1: peerLastZxid 小于minCommittedLog。场景2: Leader 服务器上没有提议缓存队列,peerLastZxid 不等于lastProcessedZxid(Leader服务器数据恢复后得到的最大ZXID)。j

上述这两个场景非常类似,在这两种场景下,Leader服务器都无法直接使用提议缓存队列和Learner进行数据同步,因此只能进行全量同步(SNAP 同步)。

所谓全量同步就是Leader服务器将本机上的全量内存数据都同步给Learner。Leader服务器首先向Learner发送一个 SNAP指令,通知Learner即将进行全量数据同步。后,Leader会从内存数据库中获取到全量的数据节点和会话超时时间记录器,将它们序列化后传输给Learner。 Learner 服务器接收到该全量数据后,会对其反序列化后载入到内存数据库中。

转载地址:http://yapqb.baihongyu.com/

你可能感兴趣的文章
react和外部函数交互_带有React和Cloudinary的交互式产品页面
查看>>
vue项目构建和部署_如何使用Vue设置,构建和部署本机应用程序
查看>>
mac文件损坏解决方法_您的源地图已损坏。 这是解决方法
查看>>
hapi_带有节点和Hapi后端的Angular文件上传
查看>>
使用Visual Studio Code改进开发的5种方法
查看>>
vue watchers_具有Vue Watchers的简单异步无限滚动
查看>>
apollo服务器使用教程_使用Apollo Server和AdonisJS构建GraphQL服务器
查看>>
javascript 闭包_了解JavaScript闭包:实用方法
查看>>
laravel集成谷歌验证_如何将Google的两因素身份验证添加到Laravel
查看>>
rails 创建_使用Rails和Icecast创建在线流媒体广播
查看>>
票务小程序源码_使用AdonisJs构建支持票务应用程序-第2部分
查看>>
使用Vue,ASP.NET Core和Okta构建安全的待办应用
查看>>
前端长列表渲染优化_用于前端开发的浏览器渲染优化
查看>>
使用Vue.js和Electron创建桌面测验应用程序
查看>>
js 数组从头添加到数组_编码练习:从头开始构建JavaScript数组方法
查看>>
react-hooks_使用React Hooks构建一个React To-Do应用(无类组件)
查看>>
chrome开发者工具_如何使用Chrome开发者工具查找性能瓶颈
查看>>
vue 使用人脸识别_使用Vue.js和Kairos构建简单的人脸识别应用
查看>>
vue 构建单页应用_如何使用Vue 2构建简单的单页应用程序(第1部分)
查看>>
使用Webtask.io构建无服务器MERN Story应用程序-部署零:1
查看>>