Oracle クォーラムの概要
Oracle クォーラムの概要は、Oracle として知られる障害検出器を使用して、2 つの ZooKeeper インスタンスのクラスタの可用性を向上させます。Oracle は、2 インスタンス構成で他のインスタンスが障害検出器である Oracle によって障害があると識別された場合、残りの唯一のインスタンスであるインスタンスに許可を与えるように設計されています。
Oracle の実装
すべてのインスタンスは、このインスタンスが Oracle によって承認されているかどうかを示す 0 または 1 を含むファイルにアクセスする必要があります。ただし、障害検出アルゴリズムはそれぞれ異なるため、この設計は変更される可能性があります。したがって、Oracle からのメッセージの解読方法を調整するために、_QuorumOracleMaj_ の _askOracle()_ メソッドをオーバーライドできます。
デプロイメントコンテキスト
Oracle は、2 つの ZooKeeper インスタンスのクラスタの可用性を向上させるように設計されているため、投票メンバーのサイズは **2** です。言い換えれば、Oracle は、2 インスタンスのアンサンブルで障害のあるインスタンスが発生する可能性のあるコンセンサス問題を解決します。
投票メンバーのサイズが 2 を超える場合、Oracle を正しく動作させるための予想される方法は、障害のあるマシンが識別されたときにクラスタのサイズを再構成することです。たとえば、5 つのインスタンスの構成で、障害のあるマシンがリーダーとの接続を切断した場合、クラスタへの _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
`echo 1 > /some/path/result.txt`
同等のファイルは、QuorumOracleMaj の現在の実装に適しています。oracle ファイルの数は、Oracle を有効にするように構成された ZooKeeper インスタンスの数と等しくする必要があります。言い換えれば、各 ZooKeeper インスタンスは独自の oracle ファイルを持つ必要があり、ファイルは共有してはなりません。そうしないと、次のセクションで問題が発生します。
Oracle のデプロイ後何が変わるか
_QuorumPeerConfig_ は、_zoo.cfg_ に _oraclePath_ が含まれている場合、デフォルトの QuorumVerifier である _QuorumMaj_ の代わりに _QuorumOracleMaj_ のインスタンスを作成します。QuorumOracleMaj は QuorumMaj から継承し、_containsQuorum()_ メソッドをオーバーライドすることでスーパークラスと異なります。QuorumOracleMaj は、リーダーがすべてのフォロワーを失い、クォーラムを維持できない場合に、独自の _containsQuorum_ バージョンを実行するように設計されています。それ以外の場合、_QuorumOracleMaj_ は _QuorumMaj_ として実行されます。
Oracle で注意すべき点
**2** ZooKeeper インスタンスと Oracle で構成される非同期分散システムを考えてみましょう。
活性問題
Strong Completeness: There is a time after which every process that crashes is permanently suspected by every correct processes
oracle が [CT] によって導入された次のプロパティを満たしていると考える場合
システムの活性は Oracle によって保証されます。ただし、導入された oracle がこのプロパティを維持できない場合、次の例のように活性の喪失が予想されます。
- ブロードキャスト状態で実行されているリーダーとフォロワーがあるとします。システムは、次の場合に活性を失います。
- リーダーに障害が発生したが、Oracle は障害のあるリーダーを検出しない。つまり、Oracle はフォロワーが新しいリーダーになることを承認しない。
フォロワーに障害が発生したが、Oracle は障害のあるフォロワーを検出しない。つまり、Oracle はリーダーがシステムを前進させることを承認する。
安全性問題
進捗の喪失
次の例のように、システムで複数の障害が異なる時間に発生した場合、進捗が失われる可能性があります。
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.
ブロードキャスト状態でリーダー(Ben)とフォロワー(John)がいるとします。
この場合、システムは L-Ben に障害が発生した後、進捗を失います。
At T5 with zxid(0x2_A): Ben will not end his leader election because the Oracle would not authorize although John is down.
ただし、Oracle が最新の zxid を参照できるようにすることで、進捗の喪失を防ぐことができます。Oracle が最新の zxid を参照できる場合、
それでも、安全性のために活性を交換します。
スプリットブレイン問題
Accuracy: There is a time after which some correct processes is never suspected by any processes
[CT] によって導入された次の望ましいプロパティを Oracle が満たしていると考える場合、
それでも、Oracle が出す決定は相互排他的でなければなりません。
次の例のように、システムで複数の障害が異なる時間に発生した場合、進捗が失われる可能性があります。
- 言い換えれば、
- 障害検出器が互いに障害があると判断した場合でも、Oracle は Ben と John の両方を承認しない。または
いつでも、2 つの Oracle ファイルのそれぞれにある 2 つの値について、値が両方とも 1 に等しくない。
- スプリットブレインは、Oracle が次のリーダー選出フェーズ中にこのプロパティを維持できない場合に予期されます。
- システムの起動
障害のあるインスタンスが障害から回復する。
障害検出器の実装のための概念の例
障害検出器の結果は、クエリを実行している ZooKeeper インスタンスに、障害検出器によって識別された障害のあるインスタンスを待たずにシステムを前進させる権利があるかどうかを承認することであることを考慮する必要があります。
ハードウェアの実装
2 つの専用ハードウェア hw1 と hw2 が、それぞれ ZooKeeper インスタンス zk1 と zk2 をホストし、クラスタを形成できるとします。ハードウェアデバイスは両方のハードウェアに接続されており、ハードウェアの電源が入っているかどうかを判断できます。そのため、hw1 の電源が入っていない場合、zk1 は間違いなく障害があります。したがって、ハードウェアデバイスは hw2 の oracle ファイルを 1 に更新します。これは、zk1 に障害があり、zk2 がシステムを前進させることを承認していることを示します。
ソフトウェアの実装
2 つの専用ハードウェア hw1 と hw2 が、それぞれ ZooKeeper インスタンス zk1 と zk2 をホストし、クラスタを形成できるとします。hw1 と hw2 にそれぞれ 2 つのサービス o1 と o2 を配置できます。o1 と o2 のジョブは、他のハードウェアが稼働しているかどうかを検出することです。たとえば、o1 は hw2 に常に ping を実行して、hw2 の電源が入っているかどうかを判断できます。o1 が hw2 に ping を実行できない場合、o1 は hw2 に障害があると識別し、zk1 の oracle ファイルを 1 に更新します。これは、zk2 に障害があり、zk1 がシステムを前進させることを承認していることを示します。
USB デバイスを Oracle として使用して進捗を維持する
- macOS 10.15.7 (19H2) では、外部ストレージデバイスは `/Volumes` にマウントされます。したがって、oracle として必要な情報を含む USB デバイスを挿入できます。デバイスが接続されている場合、oracle はリーダーにシステムを前進させることを承認します。これは、他のインスタンスが失敗したことも意味します。このシミュレーションを再現するには **6** つの手順があります。
- まず、`Oracle` という名前の USB デバイスを挿入します。すると、`/Volumes/Oracle` にアクセスできるようになります。
次に、`/Volumes/Oracle` に `mastership` という名前で `1` を含むファイルを作成します。これで `/Volumes/Oracle/mastership` にアクセスできるようになり、zookeeper インスタンスもシステムを前進させる権利があるかどうかを確認できます。ファイルは、次のコマンドで簡単に生成できます。
-
`$ echo 1 > mastership`
3 番目に、以下の例のような `zoo.cfg` が必要です。
`dataDir=/data
- _(注) このシミュレーションでは **1 つ** の USB デバイスしかないため、スプリットブレインの問題は発生しません。_
- 4 番目に、クラスタを起動します。正常にクォーラムが形成されることが予想されます。
- 5 番目に、USB デバイスを接続せずに、または `mastership` が 0 を含むインスタンスを終了します。2 つのシナリオが考えられます。
- リーダー障害が発生し、残りのインスタンスは oracle により、独自のリーダー選出を完了します。
- oracle により、クォーラムがまだ維持されています。
最後に、USB デバイスを取り外すと、`/Volumes/Oracle/mastership` が利用できなくなります。したがって、現在の実装では、リーダーが oracle にクエリを実行するたびに、oracle は例外をスローし、`FALSE` を返します。5 番目の手順を繰り返すと、システムがリーダー障害から回復できないか、リーダーがクォーラムを失うことが予想されます。いずれの場合も、サービスは中断されます。
これらの手順により、2 インスタンスシステムで oracle がどのように機能するかを簡単に示し、実践できます。
参考文献