Zookeeper如何保证数据一致性

 我来答
科创17
2022-06-17 · TA获得超过5918个赞
知道小有建树答主
回答量:2846
采纳率:100%
帮助的人:177万
展开全部
ZooKeeper保证数据一致性用的是ZAB协议。通过这个协议来进行ZooKeeper集群间的数据同步,保证数据的一致性。

两阶段提交+过半写机制:

ZooKeeper写数据的机制是客户端把写请求发送到leader节点上(如果发送的是follower节点,follower节点会把写请求转发到leader节点),leader节点会把数据通过proposal请求发送到所有节点(包括自己),所有到节点接受到数据以后都会写到自己到本地磁盘上面,写好了以后会发送一个ack请求给leader,leader只要接受到过半的节点发送ack响应回来,就会发送commit消息给各个节点,各个节点就会把消息放入到内存中(放内存是为了保证高性能),该消息就会用户可见了。

那么这个时候,如果ZooKeeper要想保证数据一致性,就需要考虑如下两个情况,情况一:leader执行commit了,还没来得及给follower发送commit的时候,leader宕机了,这个时候如何保证消息一致性?情况二:客户端把消息写到leader了,但是leader还没发送proposal消息给其他节点,这个时候leader宕机了,leader宕机后恢复的时候此消息又该如何处理?

针对情况一,当leader宕机以后,ZooKeeper会选举出来新的leader,新的leader启动以后要到磁盘上面去检查是否存在没有commit的消息,如果存在,就继续检查看其他follower有没有对这条消息进行了commit,如果有过半节点对这条消息进行了ack,但是没有commit,那么新对leader要完成commit的操作。

针对情况二,客户端把消息写到leader了,但是leader还没发送portal消息给其他节点,这个时候leader宕机了,这个时候对于用户来说,这条消息是写失败的。假设过了一段时间以后leader节点又恢复了,不过这个时候角色就变为了follower了,它在检查自己磁盘的时候会发现自己有一条消息没有进行commit,此时就会检测消息的编号,消息是有编号的,由高32位和低32位组成,高32位是用来体现是否发生过leader切换的,低32位就是展示消息的顺序的。这个时候当前的节点就会根据高32位知道目前leader已经切换过了,所以就把当前的消息删除,然后从新的leader同步数据,这样保证了数据一致性。

Q:

A:
1.zookeeper不保证读一致性,是弱一致性,如果要保证读到的数据是最新的,读取之前要使用sync方法

2.旧leader commit完就挂掉了,因为写入的follower肯定超过一半,新leader具有最大zxid,因此新leader就拥有commit的proposal,这时候只要提交该proposal并进行同步即可。如果旧leader只同步了一个follower就挂掉,该follower就是新leader,新leader同步该proposal然后同步即可。如果旧leader还没来得及同步就挂掉,该proposal在新集群中也不会存在,也不会成功,因此当旧leader恢复时就会被rollback。

Q:
客户端连接到某台follow,先执行写数据的操作,此时该操作会被发送到leader,然后原子广播事务提议,有半数follow同意了(假设发送这条写请求的follow由于某种原因没有没有同意),然后leader发送commit并让所有follow都commit(恰好发送写请求的follow又没有收到commit),然后leader返回写成功,之后同一个客户端再读取这个数据,因为这个客户端连接的follow并没有最终提交前面的写事务,就导致了写后读不一致,这个问题怎么解决的?

zab在崩溃选择时,根据什么决定proposal该被抛弃或者该被提交?比如最开始有5台server, leader把日志复制到了另外2台,leader在本地提交日志(或者还没来得及提交),然后立即挂了。剩下4台server, 有2台有这个日志,有2台没有,那么这个日志要不要保留?

A:

问题1:你说的是对的,但是 zookeeper 的读写一致不是在 server 做的,而是 server & client 配合的;client 会记录它见过的最大的 zxid (在你的场景下,就是这条写入 的 zkid),读取的时候,如果 server 发现 这条 zxid 比 server 端的最大 zxid 大,则拒绝,client 会自动重连到其他server(还在同一个 session) —— 最终会落到有新数据的 server 上,因为半数已经同意;

问题2:这个和选主有关系了,zookeeper 的选主,会尽量让 zxid 最大的那个 server 成为主;所以,在你的场景下,有最新数据的 leader 会成为主;然后再同步数据到其他机器,那么,这条 commit 的 log 便没有丢(相当于保留了);

读数据不是不保证一致性吗?有可能读到旧的

做sync后再读。当然,永远读到最新是不可能的。

sync后再读也不能保证读到新的. 因为sync之前如果刚好发生了选举,自己又连到老的leader上,老的leader还没有过期, 而sync目前又不要求quorum, 这种情况老leader就可能漏掉其他节点(新leader所在集群的)在sync之前发出的写请求. 不过ZK正在修复这点,会把sync改成要求quorum的.

对于问题2.只要数据被写进新leader的log了,均不会丢失,zk只要选出了leader,数据就是从leader这里为准了。leader的选举规则可以额外看看,总之就是zxid最大的当选。那么什么数据会被同步呢?只要被记录到log中的事务都不会丢失。那么可能你会疑问,如果事务没提交呢? leader在做restore的时候,会将日志中的proposal重新广播。

针对问题1;会有一个类似场景,就是比如clientA连接的服务端server1(follower),clientB连接的服务端server2(follower);clientA发起一个事务请求,只有server2没有应用这个事务。clientB去getData的时候,还是旧的数据。这种情况,哪些时机会去补偿?除了getData之前先执行下sync操作这个方法外,还有哪些时机吗?

没有了,zk不保证强一致性,所以clientb得到的数据可能为旧,这是zk cap设计中舍弃的,强一致性的数据可以从leader那里拿。

选举时发送的zxid是已经commit的还是log的? 我看源码FastLeaderElection里getLastLoggedZxid最终调的是zkDatabase的lastProcessedZxid,那么就算某个proposal被过半的follower log了,也有可能丢,因为选出的新leader不一定log了那个proposal

是log的,选举的时候是选取zxid最大的那个。选举成功需要过半节点在线,所以只要记录过半节点的记录就不会丢,因为新leader一定会含有这条记录

请教下大佬,对于第一个问题,Client写请求:leader对follow发送propose得到超过一半的follow的ack,那么对所有的follow执行commit。这里的是等所有follow都commit提交成功再返回给client写成功,还是发送完commit一半followcommit成功就给client返回写成功了?
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式