【5. Zookeeper 高级知识点】

【5. Zookeeper 高级知识点】,第1张

【5. Zookeeper 高级知识点】 Zookeeper 高级 一致性协议概述

​ 前面已经讨论过,在分布式环境下,有很多不确定性因素,故障随时都回发生,也讲了 CAP理论,base 理论
​ 我们希望达到,在分布式环境下能搭建一个高可用的,且数据高一致性的服务,目标是这样, 但 CAP 理论告诉我们要达到这样的理想环境是不可能的。这三者最多完全满足 2 个。在这个前提下,P(分区容错性)是必然要满足的,因为毕竟是分布式,不能把所有的应用全放到一个服务器里面,这样服务器是吃不消的,而且也存在单点故障问题。所以,只能从一致性和可用性中找平衡。

​ 怎么个平衡法?在这种环境下出现了 base 理论:
​ 即使无法做到强一致性,但分布式系统可以根据自己的业务特点,采用适当的方式来使系统达到最终的一致性;

​ base 由 Basically Avaliable 基本可用、Soft state 软状态、Eventually consistent 最终一致性组成,一句话概括就是:平时系统要求是基本可用,除开成功失败,运行有可容忍的延迟状态,但是,无论如何经过一段时间的延迟后系统最终必须达成数据是一致的。

​ 其实可能发现不管是 CAP 理论,还是 base 理论,他们都是理论,这些理论是需要算法来实现的,今天讲的 2PC、3PC、Paxos 算法,ZAB 算法就是干这事情。

​ 这些的前提一定是分布式,解决的问题全部都是在分布式环境下,怎么让系 统尽可能的高可用,而且数据能最终能达到一致。

两阶段提交 two-phase commit (2PC)

​ 首先来看下 2PC,翻译过来叫两阶段提交算法,它本身是一致强一致性算法,所以很适合用作数据库的分布式事务。其实数据库的经常用到的 TCC 本身就是一种 2PC.
​ 回想下数据库的事务,数据库不管是 MySQL 还是 MSSql,本身都提供的很完善的事务支持。MySQL 后面学分表分库的时候会讲到在 innodb 存储引擎,对数据库的修改都会写到 undo和 redo 中,不只是数据库,很多需要事务支持的都会用到这个思路。

​ 对一条数据的修改 *** 作首先写 undo 日志,记录的数据原来的样子,接下来执行事务修改 *** 作,把数据写到 redo 日志里面,万一捅娄子,事务失败了,可从 undo 里面回复数据。

​ 不只是数据库,在很多企业里面,比如华为等提交数据库修改都回要求这样,你要新增一个 字段,首先要把修改数据库的字段 SQL 提交给 DBA(redo),这不够,还需要把删除你提交字段,把数据还原成你修改之前的语句也一并提交者叫(undo)数据库通过 undo 与 redo 能保证数据的强一致性,要解决分布式事务的前提就是当个节点是支持事务的。

​ 这在个前提下,2pc 借鉴这失效,首先把整个分布式事务分两节点,首先第一阶段叫准备节点,事务的请求都发送给一个个的资源,这里的资源可以是数据库,也可以是其他支持事务 的框架,他们会分别执行自己的事务,写日志到 undo 与 redo,但是不提交事务。

​ 当事务管理器收到了所以资源的反馈,事务都执行没报错后,事务管理器再发送 commit 指令让资源把事务提交,一旦发现任何一个资源在准备阶段没有执行成功,事务管理器会发送rollback,让所有的资源都回滚。这就是 2pc,非常非常简单。


​ 说他是强一致性的是他需要保证任何一个资源都成功,整个分布式事务才成功。

优点

​ 优点:原理简单,实现方便

缺点

​ 缺点:同步阻塞,单点问题,数据不一致,容错性不好

同步阻塞

​ 在二阶段提交的过程中,所有的节点都在等待其他节点的响应,无法进行其他 *** 作。这种同 步阻塞极大的限制了分布式系统的性能。

单点问题

​ 协调者在整个二阶段提交过程中很重要,如果协调者在提交阶段出现问题,那么整个流程将 无法运转。更重要的是,其他参与者将会处于一直锁定事务资源的状态中,而无法继续完成事务 *** 作。

数据不一致

​ 假设当协调者向所有的参与者发送 commit 请求之后,发生了局部网络异常,或者是协调者在尚未发送完所有 commit 请求之前自身发生了崩溃,导致最终只有部分参与者收到了

​ commit 请求。这将导致严重的数据不一致问题。

容错性不好

​ 二阶段提交协议没有设计较为完善的容错机制,任意一个节点是失败都会导致整个事务的失败。

三阶段提交 three-phase commit (3PC)

​ 由于二阶段提交存在着诸如同步阻塞、单点问题,所以,研究者们在二阶段提交的基础上做 了改进,提出了三阶段提交。

第一阶段 canCommit

​ 确认所有的资源是否都是健康、在线的,以约女孩举例,你会打个电话问下她是不是在家, 而且可以约个会。

​ 如果女孩有空,你在去约她。

​ 就因为有了这一阶段,大大的减少了 2 段提交的阻塞时间,在 2 段提交,如果有 3 个数据库, 恰恰第三个数据库出现问题,其他两个都会执行耗费时间的事务 *** 作,到第三个却发现连接 不上。3 段优化了这种情况

第二阶段 PreCommit

​ 如果所有服务都 ok,可以接收事务请求,这一阶段就可以执行事务了,这时候也是每个资源都回写 redo 与 undo 日志,事务执行成功,返回 ack(yes),否则返回 no

第三阶段 doCommit

​ 这阶段和前面说的 2 阶段提交大同小异,这个时候协调者发现所有提交者事务提交者事务都正常执行后,给所有资源发送 commit 指令。

​ 和二阶段提交有所不同的是,他要求所有事务在协调者出现问题,没给资源发送 commit 指令的时候,三阶段提交算法要求资源在一段时间超时后回默认提交做 commit *** 作。

​ 这样的要求就减少了前面说的单点故障,万一事务管理器出现问题,事务也回提交。

​ 但回顾整个过程,不管是 2pc,还是 3pc,同步阻塞,单点故障,容错机制不完善这些问题都没本质上得到解决,尤其是前面说得数据一致性问题,反而更糟糕了。

​ 所有数据库的分布式事务一般都是二阶段提交,而者三阶段的思想更多的被借鉴扩散成其他 的算法。

Paxos 算法


​ 这个算法还是有点难度的,本身这算法的提出者莱斯利·兰伯特在前面几篇论文中都不是以严谨的数学公式进行的。

​ 其实这个 paxos 算法也分成两阶段。首先这个图有 2 个角色,提议者与接收者

第一阶段

​ 提议者对接收者吼了一嗓子,我有个事情要告诉你们,当然这里接受者不只一个,它也是个分布式集群

​ 相当于星期一开早会,可耻的领导吼了句:“要开会了啊,我要公布一个编号为 001 的提案,收到请回复”。

​ 这个时候领导就会等着,等员工回复 1“好的”,如果回复的数目超过一半,就会进行下一步。

​ 如果由于某些原因(接收者死机,网络问题,本身业务问题),导通过的协议未超过一半,

​ 这个时候的领导又会再吼一嗓子,当然气势没那凶残:“好了,怕了你们了,我要公布一个新的编号未 002 的提案,收到请回复 1”

第二阶段

​ 接下来到第二阶段,领导苦口婆心的把你们叫来开会了,今天编号 002 提案的内容是:“由于项目紧张,今天加班到 12 点,同意的请举手”这个时候如果绝大多少的接收者都同意, 那么好,议案就这么决定了,如果员工反对或者直接夺门而去,那么领导又只能从第一个阶段开始:“大哥,大姐们,我有个新的提案 003,快回会议室吧。。”

详细说明:

​ 【注意:不懂没事,记住上面那简单情况就好】
​ 上面那个故事描绘的是个苦逼的领导和凶神恶煞的员工之间的斗争,通过这个故事你们起码要懂 paxos 协议的流程是什么样的(paxos 的核心就是少数服从多数)。

​ 上面的故事有两个问题:
​ 苦逼的领导(单点问题):有这一帮凶残的下属,这领导要不可能被气死,要不也会辞职, 这是单点问题。

​ 凶神恶煞的下属(一致性问题):如果员工一种都拒绝,故意和领导抬杆,最终要产生一个一致性的解决方案是不可能的。

​ 所以 paxos 协议肯定不会只有一个提议者,作为下属的员工也不会那么强势协议要求:如果接收者没有收到过提案编号,他必须接受第一个提案编号如果接收者没有收到过其他协议,他必须接受第一个协议。

​ 举一个例子:
​ 有 2 个 Proposer(老板,老板之间是竞争关系)和 3 个 Acceptor(政府官员):

阶段一
  1. 现在需要对一项议题来进行 paxos 过程,议题是“A 项目我要中标!”,这里的“我”指每个带着他的秘书Proposer的Client老板。

  2. Proposer 当然听老板的话了,赶紧带着议题和现金去找Acceptor政府官员。

  3. 作为政府官员,当然想谁给的钱多就把项目给谁。

  4. Proposer-1小姐带着现金同时找到了 Acceptor-1~Acceptor-3 官员,1 与 2 号官员分别收取了 10 比特币,找到第 3 号官员时,没想到遭到了 3 号官员的鄙视,3 号官员告诉她,Proposer-2给了 11 比特币。不过没关系,Proposer-1 已经得到了 1,2 两个官员的认可,形成了多数派(如果没有形成多数派,Proposer-1 会去银行提款在来找官员们给每人 20 比特币,这个过程一直重复每次+10 比特币,直到多数派的形成),满意的找老板复命去了,但是此时 Proposer-2 保镖找到了 1,2 号官员,分别给了他们 11 比特币,1,2 号官员的态度立刻转变,都说Proposer-2的老板懂事,这下子 Proposer-2 放心了,搞定了 3 个官员,找老板复命去了,当然这个过程是第一阶段提交,只是官员们初步接受贿赂而已。故事中的比特币是编号,议题是 value。

这个过程保证了在某一时刻,某一个 proposer 的议题会形成一个多数派进行初步支持

阶段二
  1. 现在进入第二阶段提交,现在 proposer-1 小姐使用分身术(多线程并发)分了 3 个自己分别去找 3 位官员,最先找到了 1 号官员签合同,遭到了 1 号官员的鄙视,1 号官员告诉他proposer-2 先生给了他 11 比特币,因为上一条规则的性质 proposer-1 小姐知道 proposer-2 第一阶段在她之后又形成了多数派(至少有 2 位官员的赃款被更新了);此时她赶紧去提款准备重新贿赂这 3 个官员(重新进入第一阶段),每人 20 比特币。刚给 1 号官员 20 比特币, 1 号官员很高兴初步接受了议题,还没来得及见到 2,3 号官员的时候

    ​ 这时 proposer-2 先生也使用分身术分别找 3 位官员(注意这里是 proposer-2 的第二阶段),被第 1 号官员拒绝了告诉他收到了 20 比特币,第 2,3 号官员顺利签了合同,这时 2,3 号官员记录 client-2 老板用了 11 比特币中标,因为形成了多数派,所以最终接受了 Client2 老板中标这个议题,对于 proposer-2 先生已经出色的完成了工作;

    ​ 这时 proposer-1 小姐找到了 2 号官员,官员告诉她合同已经签了,将合同给她看,proposer-1 小姐是一个没有什么职业 *** 守的聪明人,觉得跟 Client1 老板混没什么前途,所以将自己的议题修改为“Client2 老板中标”,并且给了 2 号官员 20 比特币,这样形成了一个多数派。顺利的再次进入第二阶段。由于此时没有人竞争了,顺利的找 3 位官员签合同,3 位官员看到议题与上次一次的合同是一致的,所以最终接受了,形成了多数派,proposer-1 小姐跳槽到 Client2 老板的公司去了。

总结:

​ Paxos 过程结束了,这样,一致性得到了保证,算法运行到最后所有的 proposer 都投“client2 中标”所有的 acceptor 都接受这个议题,也就是说在最初的第二阶段,议题是先入为主的,谁先占了先机,后面的 proposer 在第一阶段就会学习到这个议题而修改自己本身的议题,因为这样没职业 *** 守,才能让一致性得到保证,这就是 paxos 算法的一个过程。原来paxos 算法里的角色都是这样的不靠谱,不过没关系,结果靠谱就可以了。该算法就是为了追求结果的一致性。

Zookeeper 集群一致性协议 ZAB 解析

​ 懂了 paxos 算法,其实 zab 就很好理解了。很多论文和资料都证明 zab 其实就是 paxos 的一种简化实现,但 Apache 自己的立场说 zab 不是 paxos 算法的实现,这个不需要去计较。

​ zab 协议解决的问题和 paxos 一样,是解决分布式系统的数据一致性问题

​ zookeeper 就是根据 zab 协议建立了主备模型完成集群的数据同步(保证数据的一致性), 前面介绍了集群的各种角色,这说所说的主备架构模型指的是,在 zookeeper 集群中,只有一台 leader(主节点)负责处理外部客户端的事务请求(写 *** 作),leader 节点负责将客户端的写 *** 作数据同步到所有的 follower 节点中。

​ zab 协议核心是在整个 zookeeper 集群中只有一个节点既 leader 将所有客户端的写 *** 作转化为事务(提议 proposal).leader 节点再数据写完之后,将向所有的 follower 节点发送数据广播请求(数据复制),等所有的 follower 节点的反馈,在 zab 协议中,只要超过半数 follower 节点反馈 ok,leader 节点会向所有 follower 服务器发送 commit 消息,既将 leader 节点上的数据同步到 follower 节点之上。

​ 发现,整个流程其实和 paxos 协议其实大同小异。说 zab 是 paxos 的一种实现方式其实并不过分。

​ Zab 再细看可以分成两部分。第一的消息广播模式,第二是崩溃恢复模式。

​ 正常情况下当客户端对 zk 有写的数据请求时,leader 节点会把数据同步到 follower 节点,这个过程其实就是消息的广播模式
​ 在新启动的时候,或者 leader 节点奔溃的时候会要选举新的 leader,选好新的 leader 之后会进行一次数据同步 *** 作,整个过程就是奔溃恢复。

消息广播模式

​ 为了保证分区容错性,zookeeper 是要让每个节点副本必须是一致的

  1. 在 zookeeper 集群中数据副本的传递策略就是采用的广播模式

  2. Zab 协议中的 leader 等待 follower 的 ack 反馈,只要半数以上的 follower 成功反馈就好, 不需要收到全部的 follower 反馈。

zookeeper 中消息广播的具体步骤如下:

  1. 客户端发起一个写 *** 作请求
  2. Leader 服务器将客户端的 request 请求转化为事物 proposql 提案,同时为每个 proposal 分配一个全局唯一的 ID,即 ZXID。
  3. leader 服务器与每个 follower 之间都有一个队列,leader 将消息发送到该队列
  4. follower 机器从队列中取出消息处理完(写入本地事物日志中)毕后,向 leader 服务器发送ACK 确认。
  5. leader 服务器收到半数以上的 follower 的 ACK 后,即认为可以发送 commit
  6. leader 向所有的 follower 服务器发送 commit 消息。(在什么时候给client答复?)

​ zookeeper 采用 ZAB 协议的核心就是只要有一台服务器提交了 proposal,就要确保所有的服务器最终都能正确提交 proposal。这也是 CAP/base 最终实现一致性的一个体现。

​ 回顾一下:前面还讲了 2pc 协议,也就是两阶段提交,发现流程 2pc 和 zab 还是挺像的, zookeeper 中数据副本的同步方式与二阶段提交相似但是却又不同。二阶段提交的要求协调者必须等到所有的参与者全部反馈 ACK 确认消息后,再发送 commit 消息。要求所有的参与者要么全部成功要么全部失败。二阶段提交会产生严重阻塞问题,但 paxos 和 zab 没有这要求。

​ 为了进一步防止阻塞,leader 服务器与每个 follower 之间都有一个单独的队列进行收发消息,使用队列消息可以做到异步解耦。leader 和 follower 之间只要往队列中发送了消息即可。如果使用同步方式容易引起阻塞。性能上要下降很多

崩溃恢复

背景(什么情况下会崩溃恢复)

​ zookeeper 集群中为保证任何所有进程能够有序的顺序执行,只能是 leader 服务器接受写请求,即使是 follower 服务器接受到客户端的请求,也会转发到 leader 服务器进行处理。

​ 如果 leader 服务器发生崩溃(重启是一种特殊的奔溃,这时候也没 leader),则 zab 协议要求zookeeper 集群进行崩溃恢复和 leader 服务器选举。

最终目的(恢复成什么样)

ZAB 协议崩溃恢复要求满足如下 2 个要求:
确保已经被 leader 提交的 proposal 必须最终被所有的 follower 服务器提交。确保丢弃已经被 leader 提出的但是没有被提交的 proposal。

​ 新选举出来的 leader 不能包含未提交的 proposal,即新选举的 leader 必须都是已经提交了的proposal 的 follower 服务器节点。同时,新选举的 leader 节点中含有最高的 ZXID。这样做的好处就是可以避免了 leader 服务器检查 proposal 的提交和丢弃工作。

  • 每个 Server 会发出一个投票,第一次都是投自己。投票信息:(myid,ZXID)
  • 收集来自各个服务器的投票
  • 处理投票并重新投票,处理逻辑:优先比较 ZXID,然后比较 myid
  • 统计投票,只要超过半数的机器接收到同样的投票信息,就可以确定 leader
  • 改变服务器状态

问题:为什么优先选大的 zxid?

​ 因为zkid最大,表明已提交的事务最大,数据最新,称为leader可以将自己的数据赋值给follower,保证了数据一致性

zxid的编码方式为高32位为epoch(即纪元,可以理解为代),低32位为每个proposal顺序递增的数字。每次变换一个leader,则epoch加一

初始化选举


假设这些服务器从id1-5,依序启动:

因为一共5台服务器,只有超过半数以上,即最少启动3台服务器,集群才能正常工作。

  • 服务器1启动,发起一次选举。
    服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成;
    服务器1状态保持为LOOKING;
  • 服务器2启动,再发起一次选举。
    服务器1和2分别投自己一票,此时服务器1发现服务器2的id比自己大,更改选票投给服务器2;
    此时服务器1票数0票,服务器2票数2票,不够半数以上(3票),选举无法完成;
    服务器1,2状态保持LOOKING;
  • 服务器3启动,发起一次选举。
    与上面过程一样,服务器1和2先投自己一票,然后因为服务器3id最大,两者更改选票投给为服务器3;
    此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数(3票),服务器3当选Leader。
    服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
  • 服务器4启动,发起一次选举。
    此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。
    此时服务器4服从多数,更改选票信息为服务器3;
    服务器4并更改状态为FOLLOWING;
  • 服务器5启动,同4一样投票给3,此时服务器3一共5票,服务器5为0票;
    服务器5并更改状态为FOLLOWING;
崩溃恢复选举

​ 情况1: 现在假设leader3崩溃了,不同follower先后发起选举的结果不一样的。(假设zxid相同)

​ 如果1发起选举:

投票过程:

1投给1, 2投给2,4投给4,5投给5 (2,4,5都不会更改选票)

投票结果是没有选出leader

​ 如果2发起选举结果同1

​ 如果4发起选举:

投票过程:

1投给1改选4, 2投给2改选4,4投给4,5投给5 (5不会更改选票)

投票选出leader4

​ 此时已经选举出leader, 各个节点状态不是looking了,不在发起选举

如果5先发起投票,结果就是5称为leader

​ 情况2: 现在假设leader3崩溃了,不同follower先后发起选举的结果不一样的。(假设节点1 zxid最大(实际已经提交的事务id中, 一定会有三台都是最大的,方便描述,假设1,3最大))

无论哪一个发起投票,最终的leader总是节点1, 因为最终都会把自己的票改成zxid最大的那一个(除非一也挂了,但是更具zab协议,一定还会有一个机器的zxid也是和1,3相同的)

``

Zookeeper 集群解析 Zookeeper 集群特点


前面一种研究的单节点,现在来研究下 zk 集群,首先来看下 zk 集群的特点。

  • 顺序一致性
    客户端的更新顺序与它们被发送的顺序相一致。
  • 原子性
    更新 *** 作要么成功要么失败,没有第三种结果。(没有第三状态)
  • 单一视图
    无论客户端连接到哪一个服务器,客户端将看到相同的 ZooKeeper 视图。
  • 可靠性

​ 一旦一个更新 *** 作被应用,那么在客户端再次更新它之前,它的值将不会改变。

  • 实时性
    连接上一个服务端数据修改,所以其他的服务端都会实时的跟新,不算完全的实时,有一点延时的
  • 角色轮换避免单点故障
    当 leader 出现问题的时候,会选举从 follower 中选举一个新的 leader
集群中的角色
  • Leader 集群工作机制中的核心
    事务请求的唯一调度和处理者,保证集群事务处理的顺序性集群内部个服务器的调度者(管理 follower,数据同步)
  • Follower 集群工作机制中的跟随者
    处理非事务请求,转发事务请求给 Leader
    参与事务请求 proposal 投票参与 leader 选举投票
  • Observer 观察者
    3.30 以上版本提供,和 follower 功能相同,但不参与任何形式投票,处理非事务请求,转发事务请求给 Leader
    提高集群非事务处理能力
Zookeeper 集群配置

不再赘述, 参考前文

【Zookeeper centos8 + zookeeper 3.7.0 环境安装】_努力学习-CSDN博客

【Zookeeper windows 环境安装】_努力学习-CSDN博客

Java 客户端连接集群
ZKClient client = new ZKClient("host1:2181,host2:2181,host3:2181");

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5682750.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存