zookeeper 相关协议、集群特点

一致性协议

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

强一致性算法,很适合用作数据库的分布式事务。其实数据库的经常用到的TCC(Try-Confirm-Cancel)本身就是一种2PC。

对一条数据的修改操作首先写 undo 日志,记录的数据原来的样子,接下来执行事务修改操作,把数据写到 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 算法

在这里插入图片描述
第一阶段
提议者对接收者吼了一嗓子,我有个事情要告诉你们,当然这里接受者不只一个,它也是个分布式集群

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

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

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

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

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


上面的故事有两个问题:
苦逼的领导(单点问题):有这一帮凶残的下属,这领导要不可能被气死,要不也会辞职,这是单点问题。
凶神恶煞的下属(一致性问题):如果员工一种都拒绝,故意和领导抬杆,最终要产生一个一致性的解决方案是不可能的。

所以paxos协议肯定不会只有一个提议者,作为下属的员工也不会那么强势
协议要求:

  • 如果接收者没有收到过提案编号,他必须接受第一个提案编号。
  • 如果接收者没有收到过其他协议,他必须接受第一个协议。

总结:Paxos 追求结果的一致性。

集群解析

集群特点

在这里插入图片描述

  • 顺序一致性
    收到 request 的顺序和它们被发送的顺序一致(通过 leader 处理之后)。
  • 原子性
    更新操作要么成功要么失败,没有第三种结果。
  • 单一视图
    无论客户端连接到哪一个服务器,客户端将看到相同的 ZooKeeper 视图。
  • 可靠性
    一旦一个更新操作被应用,那么在客户端再次更新它之前,它的值将不会改变。
  • 实时性
    连接上一个服务端数据修改,所以其他的服务端都会实时的跟新,不算完全的实时,有一点延时的
  • 角色轮换避免单点故障
    当 leader 出现问题的时候,会选举从 follower 中选举一个新的leader

集群中的角色

  • Leader 集群工作机制中的核心
    事务请求的唯一调度和处理者,保证集群事务处理的顺序性
    集群内部服务器的调度者(管理follower,数据同步)
  • Follower 集群工作机制中的跟随者
    处理非事务请求,转发事务请求给Leader
    参与事务请求 proposal 投票
    参与 leader 选举投票
  • Observer 观察者
    3.30以上版本提供,和follower功能相同,但不参与任何形式投票
    处理非事务请求,转发事务请求给Leader
    提高集群非事务处理能力

集群一致性协议 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 是要让每个节点副本必须是一致的

  • 在 zookeeper 集群中数据副本的传递策略就是采用的广播模式
  • 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消息。

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的提交和丢弃工作。

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

参考:deer——Zookeeper

发布了130 篇原创文章 · 获赞 233 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44367006/article/details/102935852