Apache > ZooKeeper
 

Oracle 法定人數簡介

Oracle 法定人數簡介增加了 2 個 ZooKeeper 執行個體叢集的可用性,並將故障偵測器稱為 Oracle。Oracle 的設計目的是授予權限給執行個體,該執行個體是 2 個執行個體組態中唯一剩下的執行個體,當其他執行個體被故障偵測器(Oracle)識別為有故障時。

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 後有什麼不同

當讀取包含 oraclePath 的 zoo.cfg 時,QuorumPeerConfig 將建立 QuorumOracleMaj 執行個體,而非預設的 QuorumVerifier,QuorumMaj。QuorumOracleMaj 繼承自 QuorumMaj,且透過覆寫 containsQuorum() 方法與其超類別不同。QuorumOracleMaj 旨在在 Leader 失去所有追隨者且無法維持法定人數時執行其版本的 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 和一個追隨者,它們在廣播狀態中執行,當

  1. Leader 失敗,但 Oracle 未偵測到有問題的 Leader,這表示 Oracle 不會授權追隨者成為新的 Leader。
    1. 當追隨者失敗,但 Oracle 未偵測到有問題的追隨者,這表示 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. 故障的執行個體從故障中復原時

無法在 Leader 選舉階段維護此屬性時,預計會發生腦裂。

故障偵測器實作概念範例

應該考慮故障偵測器的結果是授權查詢的 ZooKeeper 執行個體,在不等待故障偵測器識別的故障執行個體的情況下,是否有權讓系統向前推進。

硬體實作

假設兩個專用硬體 hw1 和 hw2 可以分別託管 ZooKeeper 執行個體 zk1 和 zk2,並形成一個叢集。一個硬體裝置連接到兩個硬體,並且能夠判斷硬體是否已開啟電源。因此,當 hw1 未開啟電源時,zk1 肯定有故障。因此,硬體裝置會將 hw2 上的 Oracle 檔案更新為 1,表示 zk1 有故障,並授權 zk2 讓系統向前推進。

軟體實作

使用 USB 裝置作為 Oracle 來維護進度

在 macOS 10.15.7 (19H2) 中,外部儲存裝置會掛載在 /Volumes 下。因此,我們可以插入包含所需資訊的 USB 裝置作為 Oracle。當裝置連接時,Oracle 會授權 Leader 推動系統前進,這也表示其他執行個體會失敗。有 個步驟可以重現此模擬。

(注意) 由於此模擬中只有一個 USB 裝置,因此不會發生腦裂問題。 此外,mastership 不應由多個執行個體共用。 因此,只有一個 ZooKeeper 執行個體會設定 Oracle。 更多資訊請參閱安全性問題區段。

  1. 發生 Leader 故障,而剩餘的執行個體會因為 Oracle 而自行完成 Leader 選舉。
  2. 由於 Oracle,法定人數仍維持。

透過這些步驟,我們可以輕鬆展示和練習 Oracle 如何與兩個執行個體系統搭配使用。

參考文獻

[CT] Tushar Deepak Chandra 和 Sam Toueg。1991。非同步系統的不可靠故障偵測器(初稿)。在第十屆 ACM 分散式運算原理研討會論文集PODC '91)。紐約、美國紐約州的計算機器協會,325-340。DOI:https://doi.org/10.1145/112600.112627