前言
zab的东西呢,全放在这里面,这里主要记录面经看到的,javaguide本身有的我就不写了哈哈哈哈:laughing:
zk的一致性算法原理(Zookeeper 是如何保证一致性的)
zk的一致性算法是zab协议,即zookeeper原子广播协议,其中定义了三个角色
Leader
:集群中 唯一的写请求处理者 ,能够发起投票(投票也是为了进行写请求)。Follower
:能够接收客户端的请求,如果是读请求则可以自己处理,如果是写请求则要转发给Leader
。在选举过程中会参与投票,有选举权和被选举权 。
Observer
:就是没有选举权和被选举权的Follower
。
zab算法保证了主从节点的数据一致性,下面我们从下面分别从client向Leader和Follower写数据场景展开陈述。
写 Leader场景数据一致性
`
- 客户端向 Leader 发起写请求 ;
- Leader 将写请求以 Proposal 的形式发给所有 Follower 并等待 ACK ;
- Follower 收到 Leader 的 Proposal 后返回 ACK ;
- Leader 得到过半数的 ACK(Leader 对自己默认有一个 ACK)后向所有的 Follower 和 Observer 发送 Commmit ;
- Leader 将处理结果返回给客户端。
注意:Leader不需要得到所有Follower的ACK,只要收到过半的ACK即可,同时Leader本身对自己有一个ACK。上图中有4个Follower,只需其中两个返回ACK即可,因为(2+1) / (4+1) > 1/2 - Observer虽然无投票权,但仍须同步Leader的数据从而在处理读请求时可以返回尽可能新的数据。
在ZooKeeper的两阶段提交中,第一阶段是提案阶段,主要目的是将提案发送给所有的follower节点。在这个阶段,发送的提案除了zxid之外,还包括数据。具体来说提案中包含了要进行的操作类型(例如创建、更新或删除节点)、节点路径以及节点数据等信息。
在接收到提案后,follower节点会将提案中的数据写入到本地的内存中,但是并不会将数据写入到磁盘中。这是因为在第一阶段中,follower节点并没有对提案进行投票,因此还不能确定这个提案是否会被最终提交。只有在第二阶段中,当follower节点收到了大多数节点的投票,并且确定要提交这个提案时,才会将数据写入到磁盘中。
总之,在zookeeper的两阶段提交中,第一阶段的提案阶段中,follower节点会将提案中的数据写入到内存中,但是并不会将数据写入到磁盘中。只有在第二阶段中,当follower节点确定要提交这个提案时,才会将数据写入到磁盘中。
写 Follower场景数据一致性
- 客户端向 Follower 发起写请求, Follower将写请求转发给 Leader 处理;
- 其它流程与直接写 Leader 无任何区别。
注意:Observer 与 Follower 写流程相同
最终一致性
Zab 协议消息广播使用两阶段提交的方式,达到主从数据的最终一致性。为什么是最终一致性呢?从上文可知数据写入过程核心分成下面两阶段:
- 第一阶段:Leader 数据写入事件作为提案广播给所有 Follower 结点;可以写入的Follower结点返回确认信息 ACK。
- 第二阶段:Leader 收到一半以上的 ACK 信息后确认写入可以生效,向所有结点广播 COMMIT 将提案生效。
根据写入过程的两阶段的描述,可以知道 ZooKeeper 保证的是最终一致性,即 Leader 向客户端返回写入成功后,可能有部分 Follower 还没有写入最新的数据,所以是最终一致性。
顺序一致性
同时,ZooKeeper 保证的最终一致性也叫顺序一致性,即每个结点的数据都是严格按事务的发起顺序生效的。ZooKeeper 集群的写入是由 Leader 结点协调的,真实场景下写入会有一定的并发量,那 Zab 协议的两阶段提交是如何保证事务严格按顺序生效的呢?
ZK事物的顺序性是借助上文中的Zxid实现的。Leader 在收到半数以上 ACK 后会将提案生效并广播给所有 Follower 结点,Leader 为了保证提案按 ZXID 顺序生效,使用了一个 ConcurrentHashMap,记录所有未提交的提案,命名为 outstandingProposals,key 为 ZXID,Value 为提案的信息。对 outstandingProposals 的访问逻辑如下:
- Leader 每发起一个提案,会将提案的 ZXID 和内容放到 outstandingProposals 中,作为待提交的提案;
- Leader 收到 Follower 的 ACK 信息后,根据 ACK 中的 ZXID 从 outstandingProposals 中找到对应的提案,对 ACK 计数;
- 执行 tryToCommit 尝试将提案提交:判断流程是,先判断当前 ZXID 之前是否还有未提交提案,如果有,当前提案暂时不能提交;再判断提案是否收到半数以上 ACK,如果达到半数则可以提交;如果可以提交,将当前 ZXID 从 outstandingProposals 中清除并向 Followers 广播提交当前提案;
Leader 是如何判断当前 ZXID 之前是否还有未提交提案的呢?由于前提是保证顺序提交的,所以 Leader 只需判断 outstandingProposals 里,当前 ZXID 的前一个 ZXID 是否存在。代码如下:
所以 ZooKeeper 是通过两阶段提交保证数据的最终一致性,并且通过严格按照 ZXID 的顺序生效提案保证其顺序一致性的。
Zookeeper有几种角色
zk的一致性算法是zab协议,即zookeeper原子广播协议,其中定义了三个角色
Leader
:集群中 唯一的写请求处理者 ,能够发起投票(投票也是为了进行写请求)。Follower
:能够接收客户端的请求,如果是读请求则可以自己处理,如果是写请求则要转发给Leader
。在选举过程中会参与投票,有选举权和被选举权 。
Observer
:就是没有选举权和被选举权的Follower
。
zab算法保证了主从节点的数据一致性,下面我们从下面分别从client向Leader和Follower写数据场景展开陈述。
如果选举的时候zxid都相同呢
每个服务器有自己的myid,选举时首先它会比较 ZXID
,ZXID
大的优先为 Leader
,如果相同则比较 myid
,myid
大的优先作为 Leader
。
2PC
两阶段提交是一种保证分布式系统数据一致性的协议,现在很多数据库都是采用的两阶段提交协议来完成 分布式事务 的处理。
在两阶段提交中,主要涉及到两个角色,分别是协调者和参与者。
第一阶段:当要执行一个分布式事务的时候,事务发起者首先向协调者发起事务请求,然后协调者会给所有参与者发送 prepare
请求(其中包括事务内容)告诉参与者你们需要执行事务了,如果能执行我发的事务内容那么就先执行但不提交,执行后请给我回复。然后参与者收到 prepare
消息后,他们会开始执行事务(但不提交),并将 Undo
和 Redo
信息记入事务日志中,之后参与者就向协调者反馈是否准备好了。
第二阶段:第二阶段主要是协调者根据参与者反馈的情况来决定接下来是否可以进行事务的提交操作,即提交事务或者回滚事务。
2PC比较垃圾,有问题:
- 单点故障问题,如果协调者挂了那么整个系统都处于不可用的状态了。
- 阻塞问题,即当协调者发送
prepare
请求,参与者收到之后如果能处理那么它将会进行事务的处理但并不提交,这个时候会一直占用着资源不释放,如果此时协调者挂了,那么这些资源都不会再释放了,这会极大影响性能。 - 数据不一致问题,比如当第二阶段,协调者只发送了一部分的
commit
请求就挂了,那么也就意味着,收到消息的参与者会进行事务的提交,而后面没收到的则不会进行事务提交,那么这时候就会产生数据不一致性问题。
3PC
CanCommit 阶段:协调者向所有参与者发送
CanCommit
请求,参与者收到请求后会根据自身情况查看是否能执行事务,如果可以则返回 YES 响应并进入预备状态,否则返回 NO 。PreCommit 阶段:协调者根据参与者返回的响应来决定是否可以进行下面的
PreCommit
操作。如果上面参与者返回的都是 YES,那么协调者将向所有参与者发送PreCommit
预提交请求,参与者收到预提交请求后,会进行事务的执行操作,并将Undo
和Redo
信息写入事务日志中 ,最后如果参与者顺利执行了事务则给协调者返回成功的响应。如果在第一阶段协调者收到了 任何一个 NO 的信息,或者 在一定时间内 并没有收到全部的参与者的响应,那么就会中断事务,它会向所有参与者发送中断请求(abort),参与者收到中断请求之后会立即中断事务,或者在一定时间内没有收到协调者的请求,它也会中断事务。DoCommit 阶段:这个阶段其实和
2PC
的第二阶段差不多,如果协调者收到了所有参与者在PreCommit
阶段的 YES 响应,那么协调者将会给所有参与者发送DoCommit
请求,参与者收到DoCommit
请求后则会进行事务的提交工作,完成后则会给协调者返回响应,协调者收到所有参与者返回的事务提交成功的响应之后则完成事务。若协调者在PreCommit
阶段 收到了任何一个 NO 或者在一定时间内没有收到所有参与者的响应 ,那么就会进行中断请求的发送,参与者收到中断请求后则会 通过上面记录的回滚日志 来进行事务的回滚操作,并向协调者反馈回滚状况,协调者收到参与者返回的消息后,中断事务。
总之,3PC
通过一系列的超时机制很好的缓解了阻塞问题,但是最重要的一致性并没有得到根本的解决,比如在 DoCommit
阶段,当一个参与者收到了请求之后其他参与者和协调者挂了或者出现了网络分区,这个时候收到消息的参与者都会进行事务提交,这就会出现数据不一致性问题。
Paxos算法
不知道
zk崩溃恢复如何保证一致性?
一个是要保证Leader 提交的提案最终能够被所有的 Follower 提交是什么意思呢
- 这个简单,因为最终提交的提案收到的一方zxid肯定比没收到的一方zxid大,所以没收到的那一方不可能成为新的leader
另一个就是要跳过那些已经被丢弃的提案
- 就是leader挂掉又加入后,要丢弃自己已经同意但是还没提交的事务