Apache > ZooKeeper
 

Oracle 法定人数简介

Oracle 法定人数简介提高了 2 个 ZooKeeper 实例集群的可用性,其中故障检测器称为 Oracle。Oracle 被设计为在故障检测器(即 Oracle)将另一个实例识别为有故障时,向 2 实例配置中唯一剩余的实例授予权限。

Oracle 的实现

每个实例都应访问一个文件,其中包含 0 或 1,以指示该实例是否得到 Oracle 授权。但是,此设计可以更改,因为故障检测器算法彼此不同。因此,人们可以覆盖 QuorumOracleMaj 中的 askOracle() 方法,以适应从 Oracle 解密消息的首选方式。

部署上下文

Oracle 被设计为提高 2 个 ZooKeeper 实例集群的可用性;因此,投票成员的大小为 2。换句话说,Oracle 解决了两实例集成中可能出现故障实例的共识问题。

如果投票成员的大小超过 2,则使 Oracle 正确工作的预期方式是在识别出故障机器时重新配置集群的大小。例如,在 5 个实例的配置中,当故障机器与 Leader 断开连接时,预期会向集群发送一个 reconfig 客户端请求,这会使集群重新形成 4 个实例的配置。因此,一旦投票成员的大小等于 2,配置就会陷入 Oracle 被设计为解决的问题域。

如何在 zoo.cfg 中部署 Oracle

无论集群规模如何,都必须在初始化时配置 oraclePath,这与其他静态参数类似。以下显示了指定和启用 Oracle 的正确方法。

oraclePath=/to/some/file

zoo.cfg 示例

dataDir=/data
dataLogDir=/datalog
tickTime=2000
initLimit=5
syncLimit=2
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
maxClientCnxns=60
standaloneEnabled=true
admin.enableServer=true
oraclePath=/chassis/mastership
server.1=0.0.0.0:2888:3888;2181
server.2=hw1:2888:3888;2181

QuorumOracleMaj 被设计为读取故障检测器的结果,该结果写入文本文件(即 Oracle 文件)。
zoo.cfg 中的配置如下所示

oraclePath=/to/some/file

假设故障检测器的结果已写入 /some/path/result.txt,则正确的配置如下所示

oraclePath=/some/path/result.txt

那么,提供的文件的正确内容是什么?可以使用以下命令从终端创建示例文件

$echo 1 > /some/path/result.txt

任何等效文件都适用于 QuorumOracleMaj 的当前实现。Oracle 文件的数量应等于配置为启用 Oracle 的 ZooKeeper 实例的数量。换句话说,每个 ZooKeeper 实例都应有其 Oracle 文件,并且这些文件不得共享;否则,下一部分中的问题将会出现。

启用 Oracle 后有什么不同

QuorumPeerConfig 读取包含 oraclePathzoo.cfg 时,它将创建一个 QuorumOracleMaj 实例,而不是默认的 QuorumVerifier QuorumMaj。QuorumOracleMaj 继承自 QuorumMaj,并且通过覆盖 containsQuorum() 方法而与其超类不同。QuorumOracleMaj 被设计为在 Leader 失去所有 Follower 且无法维持法定人数时执行其版本的 containsQuorum。在其他情况下,QuorumOracleMaj 将作为 QuorumMaj 执行。

我们应该注意 Oracle 的是什么

我们考虑一个异步分布式系统,该系统由 2 个 ZooKeeper 实例和一个 Oracle 组成。

活性问题

当我们考虑 Oracle 满足 [CT] 引入的以下属性时

Strong Completeness: There is a time after which every process that crashes is permanently suspected by every correct processes

Oracle 确保了系统的活性。但是,当引入的 Oracle 无法维持此属性时,预计会失去活性,如下例所示,

假设我们有一个 Leader 和一个 Follower,它们在广播状态下运行,系统将在以下情况下失去活性

  1. Leader 发生故障,但 Oracle 未检测到故障 Leader,这意味着 Oracle 不会授权 Follower 成为新的 Leader。
    1. 当 Follower 发生故障时,但 Oracle 未检测到故障 Follower,这意味着 Oracle 将授权 Leader 推动系统向前发展。

安全问题

进度丢失

当系统在不同时间发生多个故障时,可能会丢失进度,如下例所示,

假设我们在广播状态下有一个 Leader(Ben)和一个 Follower(John),

At T1 with zxid(0x1_1): L-Ben fails, and the F-John takes over the system under the authorization from the Oracle.
At T2 with zxid(0x2_1): The F-John becomes a new Leader, L-John, and starts a new epoch.
At T3 with zxid(0x2_A): L-John fails
At T4 with zxid(0x2_A): Ben recovers up and starts its leader election.
At T5 with zxid(0x3_1): Ben becomes the new leader, L-Ben, under the authorization from the Oracle.

在这种情况下,系统在 L-Ben 失败后会丢失进度。

但是,可以通过让 Oracle 能够引用最新的 zxid 来防止进度丢失。当 Oracle 可以引用最新的 zxid 时,

At T5 with zxid(0x2_A): Ben will not end his leader election because the Oracle would not authorize although John is down.

尽管如此,我们还是用活性换取了安全性。

脑裂问题

我们认为 Oracle 满足 [CT] 引入的以下期望属性,

Accuracy: There is a time after which some correct processes is never suspected by any processes

尽管如此,Oracle 给出的决策应该是互斥的。

换句话说,

假设我们在广播状态下有一个 Leader(Ben)和一个 Follower(John),

当 Oracle 在

  1. 系统启动
    1. 失败的实例从故障中恢复。

故障检测器实现概念示例

应该考虑故障检测器的结果是授权查询 ZooKeeper 实例,它是否有权在不等待故障检测器识别的故障实例的情况下推进系统。

硬件实现

假设两块专用硬件 hw1 和 hw2 可以分别托管 ZooKeeper 实例 zk1 和 zk2,并形成一个集群。一个硬件设备连接到这两块硬件,它能够确定硬件是否已通电。因此,当 hw1 未通电时,zk1 肯定是有故障的。因此,硬件设备将 hw2 上的 oracle 文件更新为 1,这表示 zk1 有故障并授权 zk2 推进系统。

软件实现

假设两块专用硬件 hw1 和 hw2 可以分别托管 ZooKeeper 实例 zk1 和 zk2,并形成一个集群。可以在 hw1 和 hw2 上分别再有两个服务 o1 和 o2。o1 和 o2 的工作是检测其他硬件是否处于活动状态。例如,o1 可以不断 ping hw2 以确定 hw2 是否已通电。当 o1 无法 ping 通 hw2 时,o1 会识别出 hw2 有故障,然后将 zk1 的 oracle 文件更新为 1,这表示 zk2 有故障并授权 zk1 推进系统。

使用 USB 设备作为 Oracle 来维护进度

在 macOS 10.15.7 (19H2) 中,外部存储设备挂载在 /Volumes 下。因此,我们可以插入一个包含所需信息的 USB 设备作为 oracle。当设备连接时,oracle 授权领导者推进系统,这也意味着另一个实例失败。有个步骤来重现此模拟。

(注意)由于此仿真中只有一个 USB 设备,因此不会出现脑裂问题。 此外,mastership 不应由多个实例共享。 因此,只有一个 ZooKeeper 实例配置了 Oracle。 有关更多信息,请参阅安全问题部分。

  1. 由于 oracle,发生领导者故障,剩余的实例自行完成领导者选举。
  2. 由于 oracle,法定人数仍然保持。

通过这些步骤,我们可以轻松展示和演练 oracle 如何与双实例系统配合使用。

参考

[CT] Tushar Deepak Chandra 和 Sam Toueg。1991 年。异步系统的不可靠故障检测器(初步版本)。在分布式计算原理第十届年度 ACM 研讨会论文集PODC '91)中。美国纽约州纽约市计算机协会,325-340。DOI:https://doi.org/10.1145/112600.112627