我是靠谱客的博主 超级枫叶,最近开发中收集的这篇文章主要介绍分布式系统原理 之4 Quorum 机制分布式系统原理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

分布式系统原理

Quorum 机制

Quorum 机制是一种简单有效的副本管理机制。本节首先讨论一种最简单的副本控制规则write-all-read-one,在此基础上,放松约束,讨论 quorum 机制。

1. 约定

为了简化讨论,本节先做这样的约定:更新操作(write)是一系列顺序的过程,通过其他机制确定更新操作的顺序(例如 primary-secondary 架构中由 primary 决定顺序),每个更新操作记为 w i ,i 为更新操作单调递增的序号,每个 w i 执行成功后副本数据都发生变化,称为不同的数据版本,记作 v i 。假设每个副本都保存了历史上所有版本的数据。

2. Write-all-read-one

Write-all-read-one(简称 WARO)是一种最简单的副本控制规则,顾名思义即在更新时写所有的副本,只有在所有的副本上更新成功,才认为更新成功,从而保证所有的副本一致,这样在读取数据时可以读任一副本上的数据。

  • 假设有一种 magic 的机制,当某次更新操作 w i 一旦在所有 N 个副本上都成功,此时全局都能知道这个信息,此后读取操作将指定读取数据版本为 v i 的数据,称在所有 N 个副本上都成功的更新操作为“成功提交的更新操作”,称对应的数据为“成功提交的数据”。在 WARO 中,如果某次更新操作 w i 在某个副本上失败,此时该副本的最新的数据只有 v i-1 ,由于不满足在所有 N 个副本上都成功,则 w i 不是一个“成功提交的更新操作”,此时,虽然其他 N-1 个副本上最新的数据是 v i ,但 v i 不是一个“成功提交的数据”,最新的成功提交的数据只是 v i-1 。

  • 分析一下 WARO 的可用性。由于更新操作需要在所有的 N 个副本上都成功,更新操作才能成功,所以一旦有一个副本异常,更新操作失败,更新服务不可用。对于更新服务,虽然有 N 个副本,但系统无法容忍任何一个副本异常。另一方面,N 个副本中只要有一个副本正常,系统就可以提供读服务。对于读服务而言,当有 N 个副本时,系统可以容忍 N-1 个副本异常。

  • 从上述分析可以发现 WARO 读服务的可用性较高,但更新服务的可用性不高,甚至虽然使用了副本,但更新服务的可用性等效于没有副本。

  • WARO 牺牲了更新服务的可用性,最大程度的增强读服务的可用性。

3. Quorum 定义

在 Quorum 机制下,当某次更新操作 w i 一旦在所有 N 个副本中的 W 个副本上都成功,则就称该更新操作为“成功提交的更新操作”,称对应的数据为“成功提交的数据”。令 R>N-W,由于更新操作 w i 仅在 W 个副本上成功,所以在读取数据时,最多需要读取 R 个副本则一定能读到 w i 更新后的数据 v i 。如果某次更新 w i 在 W 个副本上成功,由于 W+R>N,任意 R 个副本组成的集合一定与成功的 W 个副本组成的集合有交集,所以读取 R 个副本一定能读到 w i 更新后的数据 v i 。

例 2.4.1,某系统有 5 个副本,W=3,R=3,最初 5 个副本的数据一致,都是 v 1 , 某次更新操作w 2 在前 3 副本上成功,副本情况变成(v 2 v 2 v 2 v 1 v 1 )。此时,任意 3 个副本组成的集合中一定包括v 2 。

在上述定义中,令 W=N,R=1,就得到 WARO,即 WARO 是 Quorum 机制的一种特例。

与分析 WARO 相似,分析 Quorum 机制的可用性。限制 Quorum 参数为 W+R=N+1。由于更新操作需要在 W 个副本上都成功,更新操作才能成功,所以一旦 N-W+1 个副本异常,更新操作始终无法在 W 个副本上成功,更新服务不可用。另一方面,一旦 N-R+1 个副本异常,则无法保证一定可以读到与 W 个副本有交集的副本集合,则读服务的一致性下降。

Quorum 机制的三个系统参数 N、W、R 控制了系统的可用性,也是系统对用户的服务承诺:数据最多有 N 个副本,但数据更新成功 W 个副本即返回用户成功。

4. 读取最新成功提交的数据

上节中,假设有某种 magic 的机制使得读取者知道当前已提交的数据版本号。本节取消这种假设,分析在 Quorum 机制下,如何始终读取成功提交的数据,以及如何确定最新的已提交的数据。

Quorum 机制只需成功更新 N 个副本中的 W 个,在读取 R 个副本时,一定可以读到最新的成功提交的数据。但由于有不成功的更新情况存在,仅仅读取 R 个副本却不一定能确定哪个版本的数据是最新的已提交的数据
例 2.4.3,在 N=5,W=3,R=3 的系统中,某时刻副本最大版本号为 ( v 2 v 2 v 2 v 1 v 1 )。注意,这里继续假设有 v 2 的副本也有 v 1 ,上述列出的只是最大版本号。此时,最新的成功提交的副本应该是 v 2 ,因为从全局看 v 2 已经成功更新了 3 个副本。读取任何 3 个副本,一定能读到 v 2 。 但仅读 3 个副本时,有可能读到 ( v 2 v 1 v 1 ),如图 2-11(a)。此时,由于 v 2 蕴含 v 1 , 可知 v 1 是一个成功提交的版本 , 但却不能判定 v 2 一定是一个成功提交的版本 。 这是因为,图 2-11(b),假设副本最大版本号为 ( v 2 v 1 v 1 v 1 v 1 ),当读取 3 个副本时也可能读到 ( v 2 v 1 v 1 ),此时 v 2 是一个未成功提交的版本。所以在本例中,仅仅读到 ( v 2 v 1 v 1 )时,可以肯定的是最新的成功提交的数据要么是 v 1 要么是 v 2 ,却没办法确定究竟是哪一个 。

对于一个强一致性系统,应该始终读取返回最新的成功提交的数据,在 quorum 机制下,要达到这一目的需要对读取条件做进一步加强。

1. 限制提交的更新操作必须严格递增,即只有在前一个更新操作成功提交后才可以提交后一个更新操作,从而成功提交的数据版本号必须是连续增加的。
2. 读取 R 个副本,对于 R 个副本中版本号最高的数据,
    2.1 若已存在 W 个,则该数据为最新的成功提交的数据
    2.2 若存在个数据少于 W 个,假设为 X 个,则继续读取其他副本,直若成功读取到 W 个该版本的副本,则该数据为最新的成功提交的数据;如果在所有副本中该数据的个数肯定不满足 W 个,则 R 中版本号第二大的为最新的成功提交的副本。

例 2.4.4:依旧接例 2.4.3,在读取到 ( v 2 v 1 v 1 )时,继续读取剩余的副本,若读到剩余两个副本为(v 2 v 2 )则 v 2 是最新的已提交的副本;若读到剩余的两个副本为(v 2 v 1 )或(v 1 v 1 )则 v 1 是最新成功提交的版本;若读取后续两个副本有任一超时或失败,则无法判断哪个版本是最新的成功提交的版本。

可以看出,在单纯使用 Quorum 机制时,若要确定最新的成功提交的版本,最多需要读取 R+(W-R-1)=N 个副本,当出现任一副本异常时,读最新的成功提交的版本这一功能都有可能不可用。实际工程中,应该尽量通过其他技术手段,回避通过 Quorum 机制读取最新的成功提交的版本。例如,当 quorum 机制与 primary-secondary 控制协议结合使用时,可以通过读取 primary 的方式读取到最新的已提交的数据。

5. 基于 Quorum 机制选择 primary

本节介绍一种介于 quorum 机制选择 primary 的技术。回忆 2.2.2 节,基本 primary-secondary 协议中,primary 负责进行更新操作的同步工作。现在基本 primary-secondary 协议中引入 quorum 机制,即 primary 成功更新 W 个副本(含 primary 本身)后向用户返回成功。

在 primary-secondary 协议中,当 primary 异常时,需要选择出一个新的 primary,之后 secondary 副本与 primary 同步数据。通常情况下,选择新的 primary 的工作是由某一中心节点完成的,在引入 quorum 机制后,常用的 primary 选择方式与读取数据的方式类似,即中心节点读取 R 个副本,选择 R 个副本中版本号最高的副本作为新的 primary。新 primary 与至少 W 个副本完成数据同步后作为新 的 primary 提供读写服务。首先,R 个副本中版本号最高的副本一定蕴含了最新的成功提交的数据。 再者,虽然不能确定最高版本号的数是一个成功提交的数据,但新的 primary 在随后与 secondary 同步数据,使得该版本的副本个数达到 W,从而使得该版本的数据成为成功提交的数据。

例 2.4.5:在 N=5,W=3,R=3 的系统中,某时刻副本最大版本号为 ( v 2 v 2 v 1 v 1 v 1 ),此时 v 1 是系统的最新的成功提交的数据 , v 2 是一个处于中间状态的未成功提交的数据。假设此刻原 primary副本异常,中心节点进行 primary 切换工作。这类“中间态”数据究竟作为“脏数据”被删除,还是作为新的数据被同步后成为生效的数据,完全取决于这个数据能否参与新 primary 的选举。下面分别分析这两种情况。

  • 第一、如图 2-12,若中心节点与其中 3 个副本通信成功,读取到的版本号为(v 1 v 1 v 1 ),则任选一个副本作为primary,新primary以v 1 作为最新的成功提交的版本并与其他副本同步,当与第1、第 2 个副本同步数据时,由于第 1、第 2 个副本版本号大于 primary,属于脏数据,可以按照 2.2.2.4节中介绍的处理脏数据的方式解决。实践中,新 primary 也有可能与后两个副本完成同步后就提供数据服务,随后自身版本号也更新到 v 2 , 如果系统不能保证之后的 v 2 与之前的 v 2 完全一样,则新primary 在与第 1、2 个副本同步数据时不但要比较数据版本号还需要比较更新操作的具体内容是否一样。

第二、若中心节点与其他 3 个副本通信成功,读取到的版本号为(v 2 v 1 v 1 ),则选取版本号为v2 的副本作为新的 primary,之后,一旦新 primary 与其他 2 个副本完成数据同步,则符合 v 2 的副本个数达到 W 个,成为最新的成功提交的副本,新 primary 可以提供正常的读写服务。

6. 工程投影

  • GFS 中的 Quorum。GFS 使用 WARO 机制读写副本。GFS 系统不保证异常状态时副本的一致性,GFS 系统需要上层应用通过 Checksum 等机制自行判断数据是否合法。

  • Dynamo 中的 Quorum。Dynamo/Cassandra 是一种去中心化的分布式存储系统。Dynamo 使用 Quorum 机制来管理副本。用户可以配置 N、R、W 的参数,并保证满足 R+W>N 的 quorum 要求。Dynamo 提出了一种 clock vector 的方法,该方法的思路就是记录数据的版本变化,以类似 MVCC(2.7 )的方式帮助用户解决数据冲突。所谓 clock vector即记录了数据变化的路径的向量,为每个更新操作维护分配一个向量元素,记录数据的版本号及主导该次更新的副本名字。

  • Zookeeper 中的 Quorum。Zookeeper 使用的 paxos 协议本身就是利用了 Quorum机制,在 2.8 中有详细分析,这里不赘述。当利用 paxos 协议外选出 primary 后,Zookeeper 的更新流量由 primary 节点控制,每次更新操作,primary 节点只需更新超过半数(含自身)的节点后就返回用户成功。每次更新操作都会递增各个节点的版本号(xzid)。当 primary 节点异常,利用 paxos 协议选举新的 primary 时,每个节点都会以自己的版本号发起 paxos 提议,从而保证了选出的新 primary 是某个超过半数副本集合中版本号最大的副本。

  • Mola*/Armor*中的 Quorum。Mola*和 Armor*系统中所有的副本管理都是基于 Quorum,即数据在多数副本上更新成功则认为成功。

  • Big Pipe*中的 Quorum。Big Pipe*中的副本管理也是采用了 WARO 机制。

参考:《分布式系统原理介绍》 - 刘杰

最后

以上就是超级枫叶为你收集整理的分布式系统原理 之4 Quorum 机制分布式系统原理的全部内容,希望文章能够帮你解决分布式系统原理 之4 Quorum 机制分布式系统原理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部