定足数を失うと遅くなるのではなく止まる
一言でいうと
etcdは、Raftをそのまま実装したストアで、前に手で作った任期とクォーラムが、同じ名前で 現れます。最もよく誤解される部分は、読み取りです。過半数を失うと、書き込みだけでなく、デフォルトの読み取りも止まります。
なぜ必要なのか
練習用の実装は、学ぶには良いものですが、信頼する根拠にはなりません。自分が作ったルールがおもちゃのルールなのか、 本物のルールなのかは、同じ数字と同じ言葉が、実際のシステムから出てくるのを見て初めて確認できます。 etcdは、その確認に最もふさわしい対象です。Kubernetesのすべてのオブジェクトがここに入っていて、 ドキュメントは自らを、「メタデータを一貫性があり、耐障害性のある形で保存する」 「大規模な分散システムのための汎用的な基盤」と紹介しています (etcd — なぜetcdなのか)。
どう動くのか
3つのメンバーを同じ--initial-clusterの文字列で起動すると、彼らが互いを1つのクラスターとして認識します。
ドキュメントの静的ブートストラップの例は、名前、ピアのアドレス、クライアントのアドレス、そしてクラスタートークンを
一緒に指定します。トークンを置く理由は、ドキュメントが述べるように、「各クラスターに一意のトークンを与えて」、異なる
クラスターが混ざらないようにするためです
(etcdのクラスター構成)。
起動した後は、前のモジュールで作った値が、そのまま見えます。
ENDPOINT ID IS LEADER RAFT TERM RAFT INDEX
127.0.0.1:22379 99f0eb44090117f8 false 2 14
127.0.0.1:22479 e64076ee26a8ab0d false 2 14
127.0.0.1:22579 8e05ae0f7f2c67be true 2 14
RAFT TERMが任期で、RAFT INDEXがログの位置番号です。etcdctl move-leaderで
リーダーを移すと、任期が1つ上がります。前に、新しいリーダーが任期を上げて選ばれていたのと同じことです。
クォーラムの表は、ドキュメントにそのままあります。1台は過半数1で耐えられる故障0台、3台は2と1台、 5台は3と2台、7台は4と3台です。ドキュメントは、クラスターを7台以下にするよう勧め、 「奇数サイズのクラスターは、偶数サイズと同じ数の故障に耐えながら、ノードはより少ない」と書いています (etcd FAQ)。
最も重要な部分は、読み取りです。etcdのデフォルトの読み取りは、線形化可能な読み取り(linearizable read)で、
ドキュメントは、線形化を「同時に実行されるプロセスが適用した各操作が、呼び出しとレスポンスの間の
ある一時点に、即座に起きたように見えること」と定義しています。そして続けて、線形化にはコストがかかり、その理由は、
線形化されたリクエストがRaftの合意の過程を経なければならないからだと書いています
(etcd APIの保証)。そのため、過半数を
失ったクラスターは、遅くなるのではなく、読み取りまで止まります。同じドキュメントは、リクエストの一貫性モードを
serializableにすると、「クォーラムの基準で古いデータにアクセスできる代わりに、線形化された
アクセスが生きている合意に依存することで生じる性能上の負担をなくす」と説明しています。古い値を
受け入れられるなら、その道があるという意味です。
ここまで来ると、前の3つのラボで使ったルールと、このドキュメントの文が、同じことを言っていることが
見えてきます。私たちがhas_majorityに書いた「半分超過」が、ドキュメントの(n/2)+1で、
commit_indexが数えていたものが、ここではRAFT INDEXで、任期を上げて選ばれていた新しいリーダーが、
move-leaderの後のRAFT TERMです。名前が違うだけです。
現場での姿
Kubernetesのクラスターが「何もできない」状態の相当な部分が、これです。コントロールプレーンのノード 3台のうち2台が同時に落ちると、kube-apiserverは生きていても、取得すらできません。 etcdが過半数を失って、読み取りを確定できないからです。このとき、残った1台をどれだけ調べても、 原因はその機械の中にありません。
etcdのドキュメントは、一時的なクォーラムの喪失は、ネットワークが戻れば自動的に安全に再開するが、 恒久的なクォーラムの喪失は致命的だと区別しています。その区別が運用で意味することは、 1つです。クォーラムを失った状態で、あわててメンバーを削除したり新しく入れたりせず、まず戻ってこれる メンバーがいるかどうかを確認することです。
もう1つ。このラボが使うポートが、標準の2379ではない理由は、同じPodの中で別の ラボ用のコントロールプレーンが、すでにそのポートを使っているからです。ポートを移すだけで クラスターがもう1つ生まれるという事実自体が、etcdがクラスターを「アドレスとトークンの組」だけで 区別するという意味でもあります。
次のラボですること
同じPodの中で、etcdの3つのメンバーを静的ブートストラップで起動します。リーダーを移して任期が上がるのを 確認し、1つを止めたまま書き込み、2つを止めたまま書き込みと読み取りの両方を試します。最後に、 前の3つのラボで手で作ったルールと、ここで見た数字を突き合わせます。