编程语言
首页 > 编程语言> > 一致性算法原理

一致性算法原理

作者:互联网

一致性算法原理

一致性算法的出现是为了解决一致性问题,一致性问题是指对于一组服务器(集群),给定一组操作,需要使用一种协议使得他们的结果最终达成一致,看起来好像是一台服务器一样。

弱一致性 (DNS)

DNS 就是典型的弱一致性,访问不同的 DNS 服务器可能在一开始不一致,但是等待一段时间后会一致。

强一致性 (主从同步)

  1. Master 接受写请求
  2. Master 复制日志至 slave
  3. Master 等待,直到所有从库范围

问题:
一个节点失败,Master 阻塞,导致整个集群不可用,保证了一致性,可用性却大大降低。

强一致性 (多数派)

在并发环境下,无法保证系统正确性,顺序非常重要。

强一致性 - Paxos

Paxos 算法是莱斯利·兰伯特 于 1990 年提出的一种基于消息传递的一致性算法且具有高度容错一致性算法。这个算法被认为是类似算法中最有效的。

Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品

Paxos 算法有三种版本。下面我们一个一个来介绍。

Basic Paxos

在 Paxos 主要有3种角色 Proposer(提案者)、Acceptor(提议投票和接受者)、Learners(提议接受者)。外部角色 Client(请求发起者)。在具体实现种,一个进程可能同时充当多种角色。比如一个进程可能既是Proposer又是Acceptor又是Learner。还有一个很重要的概念叫提案(Proposal)。最终要达成一致的value就在提案里。

时序图如下:(成功的情况)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IRRhLObG-1624337364102)(一致性算法原理详解.assets/image-20210621142354500.png)]

只要 Accepted 达到多数派,则表示成功。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xnaJrSK6-1624337364104)(一致性算法原理详解.assets/image-20210621143952422.png)]

当第一次失败,或者第二次在第一次还未成功之前发送了有一次 prepare2 。那么会执行编号大的一次 prepare2 请求。比如在 Accept 期间,新的 proposer 发起 prepare2 请求。那么之前 prepare1 提案则将被拒绝。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KteERIDe-1624337364105)(一致性算法原理详解.assets/image-20210621144849870.png)]

这种情况成为活锁情况,当 prepare1 的提案还未被通过,然后出现 prepare2 提案,当 prepare2 提案未通过又出现 prepare3 .如此循环导致不断出现提案并且所有提案都未通过。举个例子,你和你女朋友去吃饭,她先提议说“吃火锅吧”。还没等她说完然后你说"我觉得烤鱼好一些",然后她又说"昨天新开的一家海鲜排档还不错"。最后无尽的推翻前一次的提议。最后无法得到结论最后吃啥,导致产生活锁。

Multi-Paxos

兰伯特提到的 Multi-Paxos 是一种思想,不是算法。而Multi-Paxos 算法是一个统称,它是指基于 Multi-Paxos思想,通过多个 Basic Paxos实例实现一系列值的共识的算法(比如 Chubby 的 Multi-Paxos 实现、Raft算法等)。

通过多次执行 Basic Paxos 实例,来实现一系列值的共识,会存在一下问题:

解决方案

引入领导者(Leader)解决问题

可以通过引入领导者节点,领导者节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提案冲突的情况了。但是在论文中,兰伯特没有说如何选举领导者,需要我们在实现 Multi-Paxos 算法的时候自己实现。 比如在 Chubby中,主节点(也就是领导者节点)是通过执行 Basic Paxos 算法,进行投票选举产生的。

减少交互次数

采用“当领导者处于稳定状态时,省掉准备阶段,直接进入接受阶段”这个优化机制,优化Basic Paxos 执行。也就是说,领导者节点上,序列中的命令是最新的,不再需要通过准备请求来发现之前被大多数节点通过的提案,领导者可以独立指定提案中的值。这时,领导者在提交命令时,可以省掉准备阶段,直接进入到接受阶段。

和重复执行 Basic Paxos 相比,Multi-Paxos 引入领导者节点之后,因为只有领导者节点一个提议者,只有它说了算,所以就不存在提案冲突。另外,当主节点处于稳定状态时,就省掉准备阶段,直接进入接受阶段,所以在很大程度上减少了往返的消息数,提升了性能,降低了延迟。

Chubby 的 Multi-Paxos 实现

  1. 通过引入主节点,实现了兰伯特提到的领导者(Leader)节点的特性。主节点作为唯一提议者,这样就不存在多个提议者同时提交提案的情况,也就不存在提案冲突的情况了;
  2. 在 Chubby 中,主节点是通过执行 Basic Paxos 算法,进行投票选举产生的,并且在运行过程中,主节点会通过不断续租的方式来延长租期(Lease)。比如在实际场景中,几天内都是同一个节点作为主节点。如果主节点故障了,那么其他的节点又会投票选举出新的主节点,也就是说主节点是一直存在的,而且是唯一的。
  3. 在 Chubby 中实现了兰伯特提到的,“当领导者处于稳定状态时,省掉准备阶段,直接进入接受阶段”这个优化机制;
  4. 在 Chubby 中,实现了成员变更(Group membership),以此保证节点变更的时候集群的平稳运行。

Chubby 中,为了实现了强一致性读操作也只能在主节点上执行。 也就是说,只要数据写入成功,之后所有的客户端读到的数据都是一致的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EU26gQfr-1624337364111)(一致性算法原理详解.assets/image-20210621151635489.png)]

Raft 算法

raft是一个共识算法(consensus algorithm),所谓共识,就是多个节点对某个事情达成一致的看法,即使是在部分节点故障、网络延时、网络分割的情况下。这些年最为火热的加密货币(比特币、区块链)就需要共识算法,而在分布式系统中,共识算法更多用于提高系统的容错性,比如分布式存储中的复制集(replication),raft协议就是一种leader-based的共识算法,与之相应的是leaderless的共识算法。

Raft implements consensus by first electing a distinguished leader, then giving the leader complete responsibility for managing the replicated log. The leader accepts log entries from clients, replicates them on other servers, and tells servers when it is safe to apply log entries to their state machines. A leader can fail or become disconnected from the other servers, in which case a new leader is elected.

上面的引文对raft协议的工作原理进行了高度的概括:raft会先选举出leader,leader完全负责replicated log的管理。leader负责接受所有客户端更新请求,然后复制到follower节点,并在“安全”的时候执行这些请求。如果leader故障,followes会重新选举出新的leader。

下面分别介绍 raft 算法中 leader election(领导选举)、log replication(日志复制)、safety(安全性)、corner case (极端情况) 进行介绍。

ZAB 算法

ZAB 协议介绍

  1. ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议)。

  2. Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面,Zookeeper 并没有使用 Paxos ,而是采用了 ZAB 协议。

  3. ZAB 协议定义:ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复原子广播 协议。下面我们会重点讲这两个东西。

  4. 基于该协议,Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。具体如下图所示:

    image.png

    上图显示了 Zookeeper 如何处理集群中的数据。所有客户端写入数据都是写入到 主进程(称为 Leader)中,然后,由 Leader 复制到备份进程(称为 Follower)中。从而保证数据一致性。从设计上看,和 Raft 类似。

    1. 那么复制过程又是如何的呢?复制过程类似 2PC,ZAB 只需要 Follower 有一半以上返回 Ack 信息就可以执行提交,大大减小了同步阻塞。也提高了可用性。

简单介绍完,开始重点介绍 消息广播崩溃恢复整个 Zookeeper 就是在这两个模式之间切换。 简而言之,当 Leader 服务可以正常使用,就进入消息广播模式,当 Leader 不可用时,则进入崩溃恢复模式。

消息广播

ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个 二阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follwer)。

基本上,整个广播流程分为 3 步骤:

1.将数据都复制到 Follwer 中

image.png

  1. 等待 Follwer 回应 Ack,最低超过半数即成功image.png
  2. 当超过半数成功回应,则执行 commit ,同时提交自己image.png

通过以上 3 个步骤,就能够保持集群之间数据的一致性。实际上,在 Leader 和 Follwer 之间还有一个消息队列,用来解耦他们之间的耦合,避免同步,实现异步解耦。

还有一些细节:

  1. Leader 在收到客户端请求之后,会将这个请求封装成一个事务,并给这个事务分配一个全局递增的唯一 ID,称为事务ID(ZXID),ZAB 兮协议需要保证事务的顺序,因此必须将每一个事务按照 ZXID 进行先后排序然后处理。
  2. 在 Leader 和 Follwer 之间还有一个消息队列,用来解耦他们之间的耦合,解除同步阻塞。
  3. zookeeper集群中为保证任何所有进程能够有序的顺序执行,只能是 Leader 服务器接受写请求,即使是 Follower 服务器接受到客户端的请求,也会转发到 Leader 服务器进行处理。
  4. 实际上,这是一种简化版本的 2PC,不能解决单点问题。等会我们会讲述 ZAB 如何解决单点问题(即 Leader 崩溃问题)。

崩溃恢复

刚刚我们说消息广播过程中,Leader 崩溃怎么办?还能保证数据一致吗?如果 Leader 先本地提交了,然后 commit 请求没有发送出去,怎么办?

实际上,当 Leader 崩溃,即进入我们开头所说的崩溃恢复模式(崩溃即:Leader 失去与过半 Follwer 的联系)。下面来详细讲述。

假设1:Leader 在复制数据给所有 Follwer 之后崩溃,怎么办?

假设2:Leader 在收到 Ack 并提交了自己,同时发送了部分 commit 出去之后崩溃怎么办?

针对这些问题,ZAB 定义了 2 个原则:

  1. ZAB 协议确保那些已经在 Leader 提交的事务最终会被所有服务器提交。
  2. ZAB 协议确保丢弃那些只在 Leader 提出/复制,但没有提交的事务

所以,ZAB 设计了下面这样一个选举算法:

能够确保提交已经被 Leader 提交的事务,同时丢弃已经被跳过的事务。

针对这个要求,如果让 Leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群总所有机器编号(即 ZXID 最大)的事务,那么就能够保证这个新选举出来的 Leader 一定具有所有已经提交的提案。

而且这么做有一个好处是:可以省去 Leader 服务器检查事务的提交和丢弃工作的这一步操作。

这样,我们刚刚假设的两个问题便能够解决。假设 1 最终会丢弃调用没有提交的数据,假设 2 最终会同步所有服务器的数据。这个时候,就引出了一个问题,如何同步?

数据同步

当崩溃恢复之后,需要在正式工作之前(接收客户端请求),Leader 服务器首先确认事务是否都已经被过半的 Follwer 提交了,即是否完成了数据同步。目的是为了保持数据一致。

当所有的 Follwer 服务器都成功同步之后,Leader 会将这些服务器加入到可用服务器列表中。

实际上,Leader 服务器处理或丢弃事务都是依赖着 ZXID 的,那么这个 ZXID 如何生成呢?

答:在 ZAB 协议的事务编号 ZXID 设计中,ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的递增的计数器,针对客户端的每一个事务请求,Leader 都会产生一个新的事务 Proposal 并对该计数器进行 + 1 操作。

而高 32 位则代表了 Leader 服务器上取出本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对这个值加一。

高 32 位代表了每代 Leader 的唯一性,低 32 代表了每代 Leader 中事务的唯一性。同时,也能让 Follwer 通过高 32 位识别不同的 Leader。简化了数据恢复流程。

基于这样的策略:当 Follower 链接上 Leader 之后,Leader 服务器会根据自己服务器上最后被提交的 ZXID 和 Follower 上的 ZXID 进行比对,比对结果要么回滚,要么和 Leader 同步。

引用

https://www.bilibili.com/video/BV1p4411v7ns
https://www.cnblogs.com/xybaby/p/10124083.html
https://www.cnblogs.com/stateis0/p/9062133.html

标签:节点,log,leader,算法,一致性,原理,Paxos,Leader
来源: https://blog.csdn.net/l154491720/article/details/118104655