[配布] - ラフトペーパーの研究

序文

この記事は Raft 論文の研究です。元の記事の Paxos の評価と Raft の特性を実験的に評価する部分は省略します。記事中の黄色の部分や引用部分は、私の個人的な理解、または論文以外の記事で読んだ該当内容を補足として記載しています。

まとめ

Raft は一連のログ コピーを管理するために使用されるコンセンサス アルゴリズムであり、その効果は Paxos と同じであり、そのパフォーマンスは Paxos に匹敵します。ただし、そのアーキテクチャは Paxos とは異なり、理解しやすいため、実用的なシステムを構築するためのより良い基盤となります。

アルゴリズムの理解しやすさを向上させるために、Raft はリーダーの選択ログの複製メンバーの変更セキュリティなどの一貫性の主要な要素を分割しています。また、より強力な一貫性が強制され、システム内で考慮する必要がある状態の数が減ります。

Raft は、クラスター内のメンバーを変更するための新しいメカニズム (重複多数メカニズム) を提供し、メンバー変更時のセキュリティを確保します。

導入

コンセンサスアルゴリズムは、一連のコンピュータを一貫した全体として動作させることができ、一部のコンピュータのエラーを許容し、一部のコンピュータにエラーが発生しても全体としては正常に動作することができます。したがって、コンセンサス アルゴリズムは、信頼性の高い大規模ソフトウェア システムを構築する上で非常に重要な役割を果たします。

過去の長い間、Paxos はコンセンサス アルゴリズムに関するすべての議論を独占していました。しかし、それを理解するのが非常に難しかったため、システムを構築するためのより良い基盤を提供するために、新しくて理解しやすいコンセンサス アルゴリズムを見つけることにしました。私たちの最初の目的は比較的ユニークです -理解可能性: 実際のシステムで使用でき、Paxos よりもはるかに理解しやすいコンセンサス アルゴリズムを定義できるかどうか。さらに重要なことは、このアルゴリズムが、システム構築に携わる人々のアルゴリズム全体の理解を促進し、アルゴリズムが機能するだけでなく、なぜアルゴリズムが機能するのかを理解できるようになることを願っています。

こうして、コンセンサス アルゴリズムRaft が誕生しました。理解しやすさを向上させるために、分解(つまり、アルゴリズム全体をリーダーの選択、ログの複製などのさまざまな部分に分割する) と状態空間の削減(つまり、サーバー間で矛盾する状態の数、またはサーバー間の矛盾の数を減らす) を使用しました。これら 2 つの非常に重要な考え方です。

Raft は多くの点で既存のコンセンサス アルゴリズムに似ていますが、いくつかの独自の機能があります。

  • リーダーはクラスター内でより強力なリーダーシップを持ちます。たとえば、ログ エントリはリーダーから他のサーバーにのみ渡されるため、ログ コピーの管理が簡素化されます。
  • リーダー選出メカニズム: Raft はランダム タイマーを使用してリーダーを選出し、各フォロワーは自身のタイマーが期限切れになると選出を開始します。
  • メンバーの変更: Raft は、クラスター内のサーバーを変更するメカニズムに新しいジョイント コンセンサス方式を使用しており、この方式により、移行期間中に変更前後の 2 つの構成のサーバー グループが重複するため、クラスター全体の変更が可能になります構成変更中も通常どおり動作し続けます。

Raft は他のコンセンサス アルゴリズムよりもシンプルで理解しやすく、実用的なシステムのニーズを満たすのに十分です。

コピーステートマシン

レプリケートされたステート マシン レプリケートされた\ ステート\ マシンこの方法では、クラスター内のステートマシンが同じ状態の複数の同一コピー  を計算するためクラスターの一部のサーバーがダウン継続できます複製されたステート マシンは、分散システムにおけるフォールト トレランス問題を

複製されたステート マシンは、通常、複製されたログを使用して実装されます。各サーバーは、一連のコマンドを含むログを保存します。ステート マシンは、これらのコマンドを順番に実行します。各ステート マシンが正常である限り、同じステート マシンに進化します。ステータス、同じ出力シーケンスを取得します。

次に、レプリカ ログの一貫性を確保するのはコンセンサス アルゴリズムの仕事です。1 つのサーバー上のコンセンサス モジュールはクライアントからコマンドを受信し、それをログに追加し、同時に他のサーバーのコンセンサス モジュールと通信します。一部のサーバーに障害が発生した場合でも、最終的に各ログには同じコマンドが同じ順序で含まれるようになります。

すべてのコマンドが正常に複製される限り、各サーバーのステート マシンはコマンドを順番に実行し、クライアントに出力で応答します。その結果、外部からはクラスター全体が独立した信頼性の高いステート マシンのように見えます。

コンセンサス アルゴリズムを実際のシステムに適用するには、次のプロパティが必要です。

  • 安全性を確保します。ネットワーク遅延、ネットワーク分割、パケット損失などが発生した場合でも、誤った結果が返されることはありません。
  • 可用性は、クラスター内のサーバーの大部分が動作しており、サーバー同士やクライアントと通信できる限り利用できます。たとえば、5 台のサーバーを備えたクラスターでは、任意の 2 台のサーバーのダウンタイムに耐えることができ、その後の回復後、これらの障害が発生したサーバーは保存されたデータに基づいて状態データを復元し、クラスターに戻ることができます。
  • ログの一貫性を保証するのに時間には依存しません。また、不正確なクロックや極端なメッセージの遅延が実現可能性の問題を引き起こす可能性があるため、一定の時間内に一貫性が達成されることも保証しません。
  • ほとんどの場合、クラスタ内のほとんどのサーバーが RPC 要求に応答する限り、コマンドは完了します。応答が遅いサーバーが少数であっても、システム全体のパフォーマンスに影響を与えることはありません。

分かりやすさを追求したデザイン

一方では、Paxos は理解するのが難しく、教育や実用的なシステムの構築に優れた基盤を提供できないと考えていますが、他方では、大規模なソフトウェア システムではコンセンサス アルゴリズムが非常に重要であるため、 Paxos よりも優れた特性を備えた、よりオプションのコンセンサス アルゴリズムを設計できます。その結果、Raft アルゴリズムが得られます。

Raft にはいくつかの目標があります。

  1. システム構築のための完全かつ実用的な基盤を提供し、開発者の追加の設計作業を軽減できなければなりません。
  2. あらゆる状況下で安全であり、特定の典型的な動作条件下で実行可能でなければなりません
  3. さまざまな一般的な操作動作を効率的に完了する必要がある
  4. 最も重要かつ難しいのは、理解できることです。理解するには、ほとんどの人がアルゴリズム全体を理解する必要があるだけでなく、システム ビルダーが問題を回避できるように、人々がアルゴリズムについて十分な知識を持っている必要もあります。実際の実装では必然的に必要になります

コンセンサスアルゴリズム Raft

Raft はまず、ログ コピーの管理、クライアントからのログ エントリの受信、およびこれらのエントリの他のサーバーへの複製を担当するリーダーを選出します。リーダー メカニズムにより、ログ コピーの管理が簡素化されます。たとえば、リーダーは他のサーバーに問い合わせることなく、ログのどの部分に新しいエントリを保存するかを決定でき、データ フローはシンプルで、リーダーから他のサーバーにのみ流れるだけです。リーダーが失敗するか接続が失われると、新しいリーダーが選出されます。

Raft はリーダー メカニズムを通じて、一貫性の問題を 3 つの比較的独立したサブ問題に分解します。

  1. リーダー選挙: 既存のリーダーが失敗した場合、新しいリーダーを選出する必要があります
  2. ログ レプリケーション: リーダーはクライアントからログ エントリを受信し、それをクラスタ全体にレプリケートして、他のサーバーのログを自分のログと強制的に一致させる必要があります。
  3. セキュリティ: Raft で最も重要なセキュリティはステート マシンのセキュリティです ステートマシンの安全性プロパティ State\ Machine\ Safety\ Propertyステートマシン安全プロパティでサーバーがそのステート マシンにログ エントリ   適用している場合、他のサーバーを同じログ インデックスに含めることはできませコマンド格納ます

ラフトの基本

Raft クラスターには一連のサーバー (通常は 5 台のサーバー) が含まれており、システムは 2 台のサーバーの障害を許容できます。どの時点においても、各サーバーは 3 つの状態 (リーダーフォロワー、または候補者 )のいずれかのみになります通常の状況では、システム内にリーダーは 1 人だけで、残りはフォロワーになります。

フォロワーは受動的であり、自分から要求をすることはなく、リーダーや候補者からの要求にのみ応答します。

リーダーはすべてのクライアント要求を処理します。クライアントがフォロワーとの通信を開始すると、フォロワーは通信をリダイレクトしてリーダーに転送します。

Raft は時間を複数の期間に分割します各期間の長さは任意です。期間は連続した番号に従って番号付けされます。各期間は選挙で始まりますリーダーの誕生というよりも、, 選挙段階では、1 人以上の候補者がリーダーになろうとし、選挙に勝った候補者が残りの任期にわたってリーダーを務めます。

場合によっては選挙結果が分かれる場合もあり、現時点ではリーダー不在の場合はそのまま任期終了となります。そしてすぐに新しい選挙と新しい任期が始まります。

Raft は、特定の任期内にリーダーが最大 1 人存在することを保証します。

異なるサーバーは異なる時点で用語間の移行を観察する可能性があり、場合によってはサーバーが選挙、または用語全体を観察しない場合もあります。

用語はRaft の論理クロックとみなすことができ、システム内のサーバーが古いリーダーなどの期限切れの情報を検出できるようになります。各サーバーには現在の用語の数値が保存され、時間の経過とともに単調かつ厳密に増加します。

現在の任期の番号はサーバー間で交換されます。サーバーの番号が他のサーバーの番号より小さい場合は、その番号をこの大きい値に更新します。候補者またはリーダーがその番号が古いことに気付いた場合は、その番号が更新されます。フォロワー状態に戻ります。サーバーが期限切れの期間番号を持つリクエストを受信した場合、リクエストは拒否されます。

Raft のサーバー間の通信にはRPCが使用されます。基本的なコンセンサス アルゴリズムでは、選挙中に候補者によって開始されるRequestVote RPCと、ログ エントリをコピーしてサービスを提供するためにリーダーによって開始される
AppendEntries RPC の 2 つの RPC のみが必要です。心拍メカニズムとして

さらに、3 番目のタイプの RPC については後で説明します。これは、サーバー間でスナップショットを転送するために使用されます。

開始された RPC がタイムリーな応答を受信しない場合、サーバーは RPC を再試行し、パフォーマンスを向上させるために並行して RPC を開始します。

リーダー選挙

Raft はハートビート メカニズムを使用してリーダー選出をトリガーします

サーバーが実行を開始すると、それらはすべてフォロワーになります。サーバーは、リーダーまたは候補者のいずれかから有効な RPC を受信する限り、フォロワーのままです。リーダーは、アイデンティティを維持するためにすべてのフォロワーに定期的にハートビートを送信します。送信されるハートビートは、ログ エントリのない AppendEntries RPCです。

フォロワーが選挙タイムアウトと呼ばれる時間を超えて通信を受信しない場合、フォロワーは生き残っているリーダーがいないと見なし、新しいリーダーを選出するための選挙を開始します。

選挙を開始するには、フォロワーは現在の期間値をインクリメントして候補状態に移行する必要があり、その後、自分自身に投票し、クラスター内の他のサーバーに対して RequestVote RPC を開始します。

候補者は、次の 3 つの状況が発生するまで、候補者としてのアイデンティティを維持します。

  1. それは選挙に勝った。その後、リーダー状態に移行します
  2. 別のサーバーがリーダーとしての地位を確立します。するとフォロワー状態に遷移します
  3. しばらく勝者が出なかった。その後、フォロワー状態にも遷移します

候補者は、同じ期間にクラスタ全体の過半数のサーバーから投票を獲得すると、選挙に勝利します。指定された期間において、各サーバーは先着順の原則に従って、最大 1 人の候補者にのみ投票します

過半数原理により、任期中に最大 1 人の候補者のみが選挙に勝利できることが保証されます。これが選挙の安全です。選挙の安全性プロパティ Election\ Safety\ Property選挙安全   _ _ _ _ _ _ _ _ _ _ _ _ _ _

候補者が選挙に勝つと、リーダーとなり、他のサーバーにハートビート メッセージを送信して、アイデンティティを確立し、新たな選挙を阻止します。

投票が到着するのを待っている間に、候補者は、サーバーがリーダーになったことを示す AppendEntries RPC を別のサーバーから受信する場合があります。RPC リクエストに含まれるリーダーの任期番号が候補者の現在の任期以上である場合、候補者はリーダーを正当なリーダーとみなし、フォロワー状態に戻ります逆に、リーダーの任期数が候補者の現在の任期よりも小さい場合、候補者は RPC を拒否し、候補者の状態を維持し続けます。

3 番目に考えられる状況は、各候補者が選挙に勝ったり負けたりしないことです。複数の支持者が同時に候補者になった場合、票は分散され、どの候補者も過半数の票を獲得できなくなりますこれが発生すると、各候補者はタイムアウトになり、任期番号をインクリメントし、新しい選挙を開始して、RequestVote RPC の新しいラウンドを開始します。しかし、追加の対策が講じられなければ、票の分裂が起こる可能性は後を絶たない

Raft はランダム化された選挙タイムアウトを使用して、投票の分割がほとんど発生せず、迅速に処理できるようにします。

まず、サーバーは、選挙タイムアウトの長さとして、150 ~ 300 ミリ秒などの固定範囲の数値をランダムに取得しますこれにより、各サーバーの選出時間を区別できるようになり、ほとんどの場合、1 つのサーバーだけがタイムアウトになり、他のサーバーがタイムアウトする前に選出を開始して選出に勝ち、それらのサーバーにハートビートを送信できる可能性があります。

各候補者は、選挙の開始時にランダム選挙タイムアウトを再開し、タイムアウトが期限切れになるのを待ってから新しい選挙を開始します。これにより、次の選挙で再び票が分裂する可能性が低くなります

ログのコピー

リーダーが選出されると、クライアントのリクエストの受信と処理が開始されます。各クライアント要求には、複製されたステート マシンによって実行されるコマンドが含まれていますリーダーはコマンドをログの新しいエントリとしてログに追加し、他の各サーバーに AppendEntries RPC を発行してエントリをコピーできるようにします。

エントリが安全にレプリケートされると、リーダーはエントリをステート マシンに適用し、結果をクライアントに返します。フォロワーがダウンしているか動作が遅い場合、またはパケット損失が発生した場合、リーダーは無期限に継続します。次の時点まで AppendEntries RPC を再試行します。すべてのフォロワーはすべてのログ エントリを保存していますが、すでにクライアントに応答している可能性もあるため、適用されるエントリはすべてのフォロワーがエントリを保存している必要はありません。

各ログ エントリがリーダーによって受信されると、そのエントリにはステート マシン コマンドとターム番号が含まれており、これらのターム番号はサーバー間のログの不一致を検出するのに役立ちます。

各ログ エントリには数値インデックスIndex が含まれ、ログ全体におけるその位置をマークします。各エントリのインデックスは異なりますが、用語番号は異なるエントリ間で同じである場合があります

リーダーは、ログ エントリをステート マシンに適用するのに十分安全である時期を判断する必要があります。ステート マシンに適用されるエントリは、コミットされたエントリと呼ばれます。Raft は、コミットされたすべてのエントリが永続的であり、最終的には利用可能なすべてのステート マシンによって実行されることを保証します。

エントリを作成したリーダーがほとんどのサーバーでエントリを正常に複製すると、エントリが送信され、リーダーのログ内の以前のエントリもすべてコミットされます。

リーダーは、送信した最高のインデックスを維持し続け、他のサーバーも最高のインデックスを知ることができるように、AppendEntries RPC でこのインデックスを保持します。比較して、特定のログ エントリが送信されたことが判明する限り、リーダーはエントリは独自のステート マシンに適用されます

Raft は、次の 2 つのプロパティを確保することによってログ マッチング プロパティを構成します。ログ マッチング プロパティ Log\ Matching\ プロパティログ一致プロパティ: 2 つのエントリが異なる  ログに存在するが、同じインデックスと同じ用語番号を持つ場合、それらは同じコマンド コマンドを保存する必要があり、これらのログすべてエントリ保存ますこのインデックスの前も同じである必要があります

前者の属性は、リーダーが特定の用語内で特定のインデックスを持つエントリを 1 つだけ作成し、ログ内のエントリの位置が決して変更されないという事実から来ています。

後者のプロパティは、AppendEntries RPC によってもたらされる整合性チェック単純な AppendEntries RPC が正常に返される限り、リーダーはフォロワーのログが自分のものとまったく同じであることを知ることができます。

通常の動作条件では、リーダーとフォロワー間のログの一貫性が保たれるため、AppendEntries RPC は常に正常に返されます。ただし、リーダーのクラッシュによってログの不整合が発生する可能性があり、クラッシュする前にログ内のすべてのエントリがフォロワーに完全にコピーされない可能性があります。これらの不一致は、一連のリーダーまたはフォロワーのクラッシュによって悪化します。フォロワーには、一部のリーダーが持つエントリを持たない場合や、一部のリーダーが持たないエントリがある場合、またはその両方が発生する場合があります。欠落しているエントリまたは余分なエントリは複数の用語にまたがる場合があります。

Raft では、リーダーは不一致を処理するためにフォロワーのログにそのログを強制的に複製させます。これは、フォロワー内の競合するエントリがリーダーのログ内のエントリによって上書きされることを意味します。

フォロワーのログと自分自身のログの一貫性を保つために、リーダーは 2 つのログで一貫性のある最新のインデックスを見つける必要があります。つまり、インデックス上の 2 つのログと、その前のすべてのインデックスを満たす最新のインデックスを見つける必要があります。インデックス。ログに保存されるエントリはすべて同じです次に、フォロワー内のインデックス以降のすべてのエントリを削除し、自分のログ内のインデックス以降のすべてのエントリをフォロワーに送信します。

これらのアクションは、前述の整合性チェックに応じて発生します。リーダーは、各フォロワーのnextIndexパラメータを保存します。これは、リーダーがフォロワーに送信する次のエントリのインデックス値を表します。サーバーがリーダーになると、すべての nextIndex 値がログ内の最後のインデックスの次のインデックス値に初期化されます。

フォロワーのログがリーダーのログと矛盾している場合、一貫性チェック AppendEntries RPC は失敗します。失敗後、リーダーは nextIndex をデクリメントし、AppendEntries RPC を再試行します。最終的に、nextIndex はリーダーのログとフォロワーのログに一致するインデックス値に達します。このとき、AppendEntries RPC も正常に戻ります。 、そして同時に、リーダーと競合するフォロワーのログ内のすべてのエントリも削除され、リーダーからのログ エントリが追加されました。AppendEntries RPC が正常に返される限り、フォロワーのログはリーダーのログと一致し、期間の残りの間この状態が維持されます。

必要に応じて、失敗した AppendEntries RPC の数を減らすためにプロトコルを最適化できます。たとえば、AppendEntries RPC を拒否する場合、フォロワーは競合するエントリの用語番号とその用語に格納されている最初のインデックスを保持できます。この情報を使用すると、リーダーは nextIndex をデクリメントするときに、この用語の競合するエントリを直接スキップできます。このようにして、競合するエントリがある用語ごとに、競合があるかどうかを確認するために各エントリが AppendEntries RPC を必要とするのではなく、競合があるかどうかを確認するために必要な AppendEntries RPC が 1 つだけ必要になります。実際には、AppendEntries の RPC エラーは頻繁に発生するものではなく、多くの矛盾したエントリが存在する可能性は低いため、この最適化が必要かどうかはわかりません。したがって、この最適化は必要ない可能性があります

このメカニズムにより、新しく出現したリーダーは、ログの一貫性を復元するために特別なアクションを実行する必要がありません。正常に実行を開始するだけでよく、AppendEntries RPC の一貫性チェックがエラー後に最終的に成功するため、ログの一貫性が保たれます。

リーダーは自分のログのエントリを上書きしたり削除したりしません。これは、リーダーが属性のみを追加することを意味します。 リーダー A 追加 - プロパティのみ リーダー\ 追加のみ\ プロパティリーダー追加_ _ _ _ _ _ _ プロパティのみ_ _ _ _ _ _ _ _ 

このログ レプリケーション メカニズムは、理想的なコンセンサス プロパティも示しています: クラスター内のほとんどのサーバーが正常に実行されている限り、Raft は新しいログ エントリを受信、コピー、および適用でき、通常の状況では RPC は 1 ラウンドのみ必要です。クラスタ内のほとんどのサーバーにレプリケートされるため、単一の低速フォロワーが全体的なパフォーマンスに影響を与えることはありません。

安全性

前述のコンテンツでは、Raft がリーダーを選出し、ログ エントリを複製する方法について説明します。しかし、これまで説明したメカニズムは、各ステート マシンが同じコマンドを同じ順序で正しく実行することを保証するには十分ではありません。たとえば、リーダーがいくつかのログ エントリをコミットすると、フォロワーが使用できなくなる可能性があり、その後リーダーとして選出され、コミットされたエントリをいくつかのエントリでカバーする可能性があります。このようにして、異なるステート マシンが異なるコマンド シーケンスを実行する可能性があります。

このセクションでは、リーダーとして選出されるサーバーに制限を追加することで Raft を改善します。この制限により、特定の用語のリーダーには、過去の用語で送信されたすべてのエントリ、つまり、リーダー整合性プロパティ、リーダー完全性プロパティ、リーダー\完全性\プロパティが含まれることが保証されます。リーダーコンピュータープロパティこの制限により  コミット操作に関するルールより正確なります_

選挙制限

リーダー メカニズムを使用するコンセンサス アルゴリズムでは、リーダーは最終的に送信されたすべてのログ エントリを保存する必要があります。Raft は簡単な方法を使用して、各リーダーがリーダーになった瞬間から、特定のエントリを送信することなく、過去の期間に送信されたすべてのエントリがすでに存在することを確認します。これは、ログ エントリがリーダーからフォロワーへの一方向にのみ流れ、リーダーがログにすでに存在するエントリを決して上書きしないことも意味します。

Raft は、ログに提出されたすべてのエントリが含まれていない限り、投票プロセス中に候補者が選挙に勝つことを妨げます。候補者が選出されるためには、クラスター内の過半数のサーバーによってサポートされている必要があります。つまり、提出された各エントリがこれらのサーバーの少なくとも 1 つに表示される必要がありますエントリが送信されたということは、ほとんどのサーバーにエントリが存在する必要があることを意味します候補者のログが少なくともこのセクションのすべてのサーバーのログと同じくらい最新である場合送信されたすべてのエントリのサーバーと同じくらい最新であるため、送信されたすべてのエントリが含まれることになります。

RequestVote RPC はこの制限を実装します。投票者のログが候補者のログよりも最新である場合、この RPC には候補者のログに関する情報が含まれます。そうすれば有権者は候補者への投票を拒否するだろう

Raft は、2 つのログの最後のエントリの用語とインデックスを比較することで、どちらのログがより最新であるかを判断します。2 つのログの最後のエントリの用語番号が異なる場合は、より大きい用語のログが更新されます。2 つのログの最後のエントリの用語が同じ場合は、同じ間隔でどちらのログのエントリが多いかがわかります。誰がより最新情報を持っていますか

過去の学期のエントリーを提出する

前述したように、リーダーは、エントリがほとんどのサーバーに保存されると、そのエントリが送信されることを知っています。リーダーがエントリを送信する前に電話を切った場合、将来のリーダーはエントリの複製を続行しようとします。

しかし、リーダーは、前の用語のエントリがほとんどのサーバーに保存されているときにコミットされたかどうかをすぐに推測することはできません。古いエントリは、ほとんどのサーバーに保存されているにもかかわらず、後続のサーバーによってまだコミットされている可能性があります。このエントリはリーダーによって上書きされます。このような問題を解消するため、Raft ではレプリカをカウントして過去の期のエントリーを提出することはなく、リーダーの今期のエントリーのみをレプリカをカウントして提出します。現在の用語のエントリが送信されると、ログの一致により Log Matchingプロパティ Log\ Matching\ プロパティLogMatchingproperty存在する以前エントリもすべて間接的に送信  ます

エントリはほとんどのサーバーに複製され、この時点で送信されるはずですが、リーダーがダウンしているため、正常に送信されません。ただし、後続のリーダーにはこのエントリが与えられます。選出ルールでは、リーダーになれるサーバーはほとんどのサーバーと同じ最新のログ ステータスを持っている必要があることがわかっているためです。このリーダーは、送信する必要があるのに送信されていないエントリを追加処理する必要はなく、通常どおりに実行するだけでよく、次のエントリを受信したときに、ログ マッチングに従って新しいエントリを他のサーバーにコピーするため、プロパティと一貫性のチェック。以前に古いエントリを受信して​​いない他のサーバーも古いエントリをコピーし、古いエントリの継続的な複製が完了します。新しいエントリが送信されると、このエントリまでに蓄積されたすべてのエントリも送信されます。したがって、コミットされていないエントリについては心配する必要はありません。この観点から、エントリが最終的に送信されるかどうかは、エントリがほとんどのサーバーにレプリケートされるかどうかによって決まります。

場合によっては、リーダーは、古いログ エントリがコミットされたことを安全に推測することもできます。たとえば、エントリが各サーバーに保存されています。しかし、Raft はより保守的なアプローチを採用しています

Raft のコミットメント ルールにより、リーダーが過去の用語からエントリをコピーすると、これらのエントリは元の用語番号を保持するため、この複雑さがさらに増します。このアプローチにより、ログ エントリはいつでもログ間で同じ用語番号が維持されるため、ログ エントリが理解しやすくなります。

安全デモンストレーション

ここで、リーダーの誠実さ、リーダー完全性特性が確立されていることをより明確に示したいと思います。リーダー完全性特性が成り立たないと仮定し、矛盾する事象を検証します。

用語 T のリーダーがその用語にエントリをコミットしたが、このエントリは後続のいくつかの用語のリーダーによって保存されないとします。項 U が、後続の対応するリーダーがそのエントリを保存していない項の中で最小の項であると仮定します。つまり、T と U の間のすべての項のリーダーがそのエントリを送信していると仮定します。

  1. leaderU がリーダーに選出されると、送信されたエントリがログに存在しません
  2. leaderT はクラスタ内のほとんどのサーバーにエントリを複製し、leaderU はクラスタ内のほとんどのサーバーから投票を受け取ります。したがって、これらの投票者のうち少なくとも 1 つのサーバーは、リーダー T のエントリを受け取り、リーダー U に投票しました。この投票者が紛争の鍵となる
  3. この投票者は、leaderU に投票する前に、leaderT から送信されたエントリを受け取っていなければなりません。そうしないと、leaderT の AppendEntries RPC が拒否されます。
  4. すべての中間リーダーにこのエントリが含まれているため、有権者はリーダー U に投票するときにもエントリを保存します。リーダーはエントリを削除せず、フォロワーはリーダーと意見が異なる場合にのみエントリを削除します。
  5. 投票者はリーダー U に投票したため、リーダー U のログは投票者のログと同じ最新のものである必要があります。これは2つの矛盾をもたらします
  6. まず、投票者のログの最後の用語がリーダー U の用語と同じである場合、リーダー U のログの内容は少なくとも投票者のものと同じである必要があり、リーダー U のログには投票者のログのすべてのエントリが含まれます。投票者には提出されたすべてのエントリが含まれるため、これは矛盾しています。この考えによれば、リーダー U にも提出されたすべてのエントリが含まれることになりますが、これは最初の仮想リーダー U には当てはまりません。
  7. さらに、リーダー U のログの最後の用語は投票者のログの最後の用語よりも明らかに大きく、投票者のログの最後の用語は少なくとも T であるため、リーダー T の用語よりも大きくなります。リーダー T の後、リーダー U より前にリーダー U のログに前のエントリを作成したリーダーは、(私たちの仮定によると) そのコミットされたエントリをログに持っている必要があります。次に、ログ マッチング プロパティを通じて、leaderU のログにも送信されたエントリが含まれている必要がありますが、これは私たちの想定と矛盾します。
  8. 議論は完了です。要約すると、T 以降のすべてのタームのリーダーは、ターム T に提出されたターム T のすべてのエントリを含める必要があります。
  9. ログ マッチング プロパティにより、将来のリーダーには間接的に送信されたエントリも確実に含まれるようになります。

リーダー完全性プロパティを通じて、ステート マシンの安全性を証明できます。 ステート マシンの安全性プロパティ State\ Machine\ Safety\ Propertyステートマシン安全プロパティつまり、サーバー特定のインデックスのエントリをそのステートマシン適用し場合、他のサーバーは別のエントリ   適用しません同じインデックスです。

サーバーがステート マシンにエントリを適用する場合、エントリまでのログの部分はリーダーとまったく同じである必要があり、エントリは送信されている必要があります。どのサーバーも、指定されたエントリの用語の中で最小の用語を適用すると考えてください。ログ完全性プロパティにより、すべての大きな用語のリーダーが同じエントリを保存することが保証されるため、インデックスは後続の用語に適用されます。同じ値であること。したがって、ステートマシンの安全性ステートマシンの安全性プロパティが確立されます。

最後に、Raft では、サーバーがログ内のインデックスの順序でエントリを適用する必要があります。ステート マシンの安全性プロパティと組み合わせると、すべてのサーバーが同じエントリのセットをまったく同じ順序でステート マシンに適用することになります。

フォロワーも候補者も減っている

これまでリーダーの失敗に焦点を当ててきました。フォロワーと候補者の失敗はリーダーの失敗よりも扱いやすく、どちらも同じ方法で処理されます。

フォロワーまたは候補者がダウンしている場合、それに送信される後続の Request Vote RPC または AppendEntries RPC は失敗します。Raft はこれらの障害を無限に再試行することで処理し、ダウンしたサーバーが再起動されると、RPC は正常に完了します。

RPC を完了した後まだ応答していないサーバーがダウンした場合、再起動時に同じ RPC を受信します。Raft の RPC は冪等であるため影響はありません。たとえば、フォロワーがログに既に存在するエントリを含む AppendEntries RPC を受信した場合、フォロワーは RPC 内のそれらのエントリを無視し、含まれていないエントリのみを受信します。

タイミングと可用性

Raft に対する私たちの要件の 1 つは、セキュリティが時間に依存すべきではないということです。つまり、一部のイベントの発生が予想よりも早すぎる、または遅すぎるという理由だけで、システムが誤った結果を生成してはなりません。

ただし、可用性 (クライアントにタイムリーに応答するシステムの能力) は、必然的に時間に依存します。たとえば、メッセージ通信に 2 つのサーバーのダウンタイムの間の時間よりも長い場合、つまり、サーバーが稼働している時間よりも長い場合、メッセージの通信時間が長くなるため、候補者は選挙に勝つのに十分な時間待つことができません。無失敗時間はまだ長いため、投票要求 RPC が戻る前に候補者が失敗している可能性があります。そのため、クラスターには安定したリーダーが存在せず、Raft は安定してサービスを提供できなくなります。

リーダー選挙 リーダー選挙は、時間要素が重要となる Raft の非常に重要な側面です。システムが次のタイミング要件を満たしている限り、Raft は通常、安定したリーダーを選出して維持できます。

ブロードキャスト タイム < < 選挙タイムアウト < < MTBF ブロードキャスト タイム << 選挙タイムアウト << MTBFブロードキャスト時間_ _ _ _ _ _ _ _<<選出時間_ _ _ _ _ _ _ _ _ _<<MTBF

この不等式において、broadcastTime は、サーバーがクラスター内の各サーバーに RPC を並行して送信し、その応答を受信するのにかかる平均時間を指します。

electionTimeout は、フォロワーが選挙を開始しようとする前にリーダーのハートビートを受信しない時間です。

MTBF は、サーバーの 2 つの障害間の平均時間、つまりサーバーの障害間の平均時間を指します。

ブロードキャスト時間は、リーダーが必要なハートビート メッセージを確実に送信してフォロワーによる選挙の開始を防ぐことができるように、選挙のタイムアウトよりも 1 桁短くする必要があります。選挙タイムアウトで使用されるランダム化方法を考慮すると、この不平等により、票の分割が発生する可能性も低くなります。

リーダーの頻繁な選出と交換を行わずにシステムが安定してサービスを提供できるように、選出タイムアウトは MTBF よりも 1 桁小さくする必要があります。

リーダーがダウンすると、システムは選挙タイムアウトの間ほぼ利用できなくなりますが、これが合計時間のほんの一部にすぎないことを願っています。

ブロードキャスト時間と MTBF は基盤となるシステムの特性であり、私たちが干渉することは困難です。しかし、選挙のタイムアウトは私たちが選択しなければならないものです。Raft の RPC では、受信機が関連情報を保持する必要があるため、ストレージ テクノロジに応じて、ブロードキャスト時間は 0.5 ミリ秒から 20 ミリ秒かかります。これにより、10 ミリ秒から 500 ミリ秒の範囲の選出タイムアウトが発生します。一般的なサーバーの MTBF は数か月以上で、時間要件を容易に満たします。

メンバー変更

これまで、クラスターの構成、つまり全体的なコンセンサス アルゴリズムに参加するサーバーのセットは固定されていると想定してきました。実際には、この構成を変更する必要がある場合があります。たとえば、サーバーに障害が発生した場合に交換したり、レプリカの数を変更したりします。

これは、クラスター全体をオフラインにし、構成ファイルを更新してからクラスターを再起動することで実現できますが、これにより、切り替え期間中はクラスター全体が使用できなくなります。また、手動で行う必要がある操作がある場合は、オペレーターエラーが発生するリスクがあります。

これらの問題を回避するために、設定変更のプロセスを自動化し、それらを Raft コンセンサス アルゴリズムにマージすることにしました。

構成変更メカニズムが安全であるためには、移行中に同じ任期内に 2 人の指導者が同時に選出される可能性のある時点があってはなりません。

残念ながら、サーバーを古い構成から新しい構成に直接変換する方法はどれも安全ではありません。すべてのサーバーを同時にアトミックに変更することは不可能であるため、移行期間中にクラスター全体が 2 つの独立した部分に分割される可能性があります。

安全性を確保するには、構成変更には 2 つのフレーズのアプローチを使用する必要があります。2 つのフェーズを達成するにはさまざまな方法があります

たとえば、一部のシステムでは、最初のフェーズで古い構成を無効にし、クライアントの要求を処理できないようにし、その後、2 番目のフェーズで新しい構成が機能できるようにします。

Raft では、クラスターは最初に、共同コンセンサスと呼ばれる移行構成に移行します。共同コンセンサスがコミットされると、システムは新しい構成に移行します。共同コンセンサスでは、古い構成と新しい構成が結合されます。

  • ログエントリは両方の構成のすべてのサーバーにコピーされます
  • どちらの構成のサーバーもリーダーになることができます
  • 選出とエントリーの送信に対する同意には、それぞれ古い構成と新しい構成のサーバーの大多数の同意が必要です。

共同コンセンサスにより、各サーバーはセキュリティを損なうことなく、異なる時点で別の構成に移行できます。さらに、共同コンセンサスにより、クラスタは構成変更中にクライアントのリクエストを処理し続けることができます。

クラスター構成情報は、保管と通信のためにレプリカ・ログ内の特別なエントリーを使用します。

リーダーは構成変更要求を受信すると、共同合意構成情報をエントリーの形式でログに保管し、そのエントリーをコピーします。特定のサーバーは、新しい構成のエントリをログに追加するとすぐに、この構成に対応するエントリがすでに送信されているかどうかに関係なく、サーバーはログ内の最新の構成を使用するため、今後の決定でこの構成を使用します。 。これは、リーダーが共同合意ルールを使用して、いつ共同合意エントリを提出するかを決定することを意味します。

リーダーが失脚した場合、選挙に勝った候補者が共同合意に対応するエントリーを受け取ったかどうかに応じて、古い構成または共同合意に基づいて新しいリーダーを選出する必要があります。ただし、新しい構成のサーバーは、この期間中に一方的な決定を行うことはできません。

共同合意がコミットされると、古い構成も新しい構成も、他の構成の同意なしには決定を下すことができなくなります。さらに、ログ完全性プロパティにより、共同合意に対応するエントリを持つサーバーのみがリーダーとして選出されることが保証されます。

この時点で、リーダーは新しい構成を説明するエントリを安全に生成し、クラスタに複製できます。繰り返しますが、この構成は確認されるとすぐにサーバー上で有効になります。

新しい構成がコミットされると、古い構成は無関係になり、新しい構成にないサーバーはシャットダウンできます。

古い構成と新しい構成の間で一方的に決定を下す時間はなく、セキュリティが確保されます。

再構成には 3 つの問題があります。

1 つ目は、新しいサーバーが最初はエントリを格納しない可能性があることです。この状態でクラスタに追加された場合、クラスタ内のエントリの格納の進行状況に追いつくまでに時間がかかります。この間、エントリを格納できない可能性があります。新しいエントリをコミットする

可用性のギャップを避けるために、Raft は構成変更の前にステージを追加します。このステージでは、新しいサーバーは非投票メンバーとしてクラスターに参加します。リーダーはログ エントリをそれらにコピーしますが、一部とはみなされません。ほとんどのサーバーの。新しいサーバーがクラスター内の他のサーバーに追いつく限り、再構成は正常に進行します。

2 番目の問題は、クラスターのリーダーが新しい構成の一部ではない可能性があることです。この場合、リーダーは、新しく構成されたエントリをコミットした後、フォロワー状態に戻ります。これは、リーダーが一定期間存在することを意味します。つまり、リーダーが新しい設定をコミットします。エントリが設定されたとき、リーダーは存在しないクラスタを管理していました。エントリを複製しましたが、それ自体は多数派のサーバーにはカウントされませんでした。

リーダーの移行は、新しい構成がコミットされるときに発生します。これは、新しい構成が独立して実行できる最初の時点であるためです。新しい構成でリーダーを選出することはいつでも可能です。この時点より前は、古い構成に属する 1 つのサーバーのみがリーダーとして選出されます。

3 番目の問題は、削除されたサーバー、つまり新しい構成にないサーバーによってクラスター全体が中断される可能性があることです。これらのサーバーはハートビートを受信しないため、タイムアウトになり、新しい選択が開始されます。彼らは、新しい用語番号を含む Request Vote RPC を送信します。これにより、現在のリーダーがフォロワー状態に移行します。

最後に、新しい構成の新しいリーダーが選出されますが、削除されたサーバーは再びタイムアウトになり、プロセスが繰り返されるため、可用性が低下します。

この問題を防ぐために、サーバーは現在のリーダーが生きていると信じている場合、Request Vote RPC を無視します。具体的には、サーバーが現在のリーダーの最小選挙タイムアウト内に投票要求 RPC を受信した場合、サーバーは任期を更新したり投票したりしません。

これは通常の選挙には影響しません。通常の状況では、各サーバーは選挙を開始する前に少なくとも最小の選挙タイムアウトを待機するため、この時間内に受信した Request Vote RPC を無視しても問題ありません。ただし、これにより、削除されたサーバーからの干渉が回避されます。リーダーがクラスターにハートビートを取得できる場合、リーダーはより高いターム番号によって削除されません。

単一ノードの変更は、クラスターのメンバー構造を変更する方法でもあります。この方法では、クラスターは一度に 1 つのノードのみを変更します。具体的には、3 ノードのクラスターを 5 ノードのクラスターに変更する場合は、次の手順が必要です。変更操作により、クラスターが 4 ノード クラスターに 1 回変更され、次に 5 ノード クラスターに変更されます。この方法では、各変更の前後で 2 つの構成の大部分が交差する必要があり、投票中に 2 つのリーダーを生成することは不可能であるため、構成を安全に変更できます。この方法を使用すると、クラスター内に共同合意の過渡状態を導入する必要がありません。

ログ圧縮

Raft のログは、通常の操作中にマージされるクライアント要求が増えるにつれて増加しますが、実際のシステムでは上限がなければ増加することはありません。ログが長くなると、必要なスペースが増え、ロードに時間がかかります。ログに蓄積された古い情報を破棄する何らかのメカニズムがないと、最終的に可用性の問題が発生します。

スナップショットの取得は、最も簡単な圧縮方法です。スナップショット メカニズムでは、システム全体の現在の状態がスナップショットに書き込まれ永続ストレージに保存され、スナップショットが生成されるまでのすべてのログが破棄されます。スナップショット メカニズム スナップショットは Chubby と Zookeeper の両方で使用されます。このセクションの残りの部分では、Raft のスナップショット メカニズムについて説明します。

ログ クリーニングやログ構造化マージ ツリー (LSM ツリー) などの増分圧縮方法も利用できます。これらのメソッドは一度にデータの一部のみを操作するため、圧縮操作の負荷をタイムラインに沿って時間の経過とともにより均等に分散します。

まず、削除および上書きされたオブジェクトが大量に蓄積されているデータ内の領域を見つけ、次にこの領域に残っているオブジェクトをよりコンパクトに書き換えて、この領域を解放します。これには、スナップショット作成と比較して大幅な追加の機械と複雑さが必要ですが、常にデータセット全体を操作することで問題が簡素化されます。

Raft のスナップショット メカニズムでは、各サーバーが個別にスナップショットを取得し、独自のログ内のコミットされたエントリを上書きします。作業のほとんどは、ステート マシンが現在の状態をスナップショットに書き込むことで行われます。Raft にはスナップショットにメタデータも含まれています。
最後に含まれたインデックスは、スナップショットによって置き換えられたログ内の最後のエントリのインデックス、またはステート マシンが適用した最後のエントリのインデックスです。最後に含まれた用語
、このエントリ 。

このエントリの処理には以前のログ インデックスと用語の知識が必要であるため、このデータは、このスナップショットの後に最初のログ エントリを送信するときに AppendEntries RPC 整合性チェックをサポートするために保存されます。クラスターのメンバーシップの変更をサポートするために、スナップショットにはログ内の最新の構成情報も含まれています。サーバーがスナップショットを書き込むと、最後に含まれたインデックスまでのすべてのログ エントリと、以前のすべてのスナップショットが削除されます。

通常、サーバーは個別にスナップショットを取得しますが、リーダーは時折、遅れているフォロワーにスナップショットを送信する必要があります。これは通常、リーダーがフォロワーに送信する必要がある次のエントリをドロップしたときに発生します。幸いなことに、通常の状況ではこのような状況が発生する可能性は低く、リーダーの進歩に追いついたフォロワーがこのエントリを所有することになります。ただし、異常に遅いフォロワーや、クラスターに参加する新しいサーバーはこのようにはなりません。そのため、そのようなフォロワーを最新の状態にするには、リーダーにネットワーク経由でスナップショットを送信させる必要があります。

リーダーは、 InstallSnapshotと呼ばれる新しい RPC を使用して、はるかに遅れているフォロワーにスナップショットを送信します。

フォロワーがこの RPC とそのスナップショットを受信すると、現在のログ エントリをどう処理するかを決定する必要があります。

通常、スナップショットには受信者のログには存在しない新しい情報が含まれます。この場合、フォロワーはログ全体を破棄し、スナップショットに完全に置き換えられます。また、スナップショットと競合するコミットされていないエントリが存在する可能性があります。逆に、フォロワーが受信したスナップショットが、そのスナップショットのプレフィックスの特定の部分を記述している場合は、独自のログを作成すると、スナップショットが上書きされます。エントリは削除されますが、スナップショット後のエントリはまだ有効で保持されます。

このスナップショット方法は、フォロワーがリーダーの知らないうちにスナップショットを撮ることができるため、Raft の強力なリーダーのルールから逸脱しています。しかし、私たちはこの離脱が合理的であると考えています。

リーダーがいると、一貫性を達成するプロセス中に矛盾する決定を回避するのに役立ちますが、スナップショットが取得されるときに一貫性が達成されるため、矛盾する決定はありません。データは依然としてリーダーからフォロワーへのみ流れ、フォロワーのみがデータを再編成します。

ここでは、リーダーのみがスナップショットを生成し、そのスナップショットを他のフォロワーに送信する、リーダーベースのアプローチを検討します。このアプローチには 2 つの欠点があります。

まず、各フォロワーにスナップショットを送信すると、ネットワーク帯域幅が消費され、スナップショット処理プロセス全体が遅くなります。各フォロワーは独自のスナップショットを生成するために必要な情報をすでに持っており、サーバーが独自のローカル状態のスナップショットを生成するほうが、ネットワーク経由でスナップショットを送信して受信するよりもコストがかかりません。スナップショット メカニズムのより重要な点は、データ圧縮にあります。一貫性よりも

次に、リーダーの実装はより複雑になります。たとえば、リーダーは、新しいクライアント要求をブロックしないように、スナップショットをフォロワーに並行して送信し、新しいログ エントリをフォロワーにコピーする必要があります。

スナップショット メカニズムのパフォーマンスに影響を与える問題が他に 2 つあります。まず、サーバーは、いつスナップショットを取得するかを決定する必要があります。サーバーがスナップショットを頻繁に取得すると、ディスク帯域幅とリソースが無駄になります。スナップショットの取得が少なすぎると、サーバー自体のストレージ容量が枯渇し、ログが再ロードされるリスクを負う必要があります。再起動すると時間がかかります。シンプルな戦略は、ログが固定バイト サイズに達したときにスナップショットを作成することです。このサイズがスナップショットの予想サイズよりも大幅に大きく設定されている場合、スナップショットのディスク帯域幅のオーバーヘッドは小さくなります。

2 番目のパフォーマンスの問題は、スナップショットの書き込みに時間がかかる可能性があり、これによって通常の操作が遅延することを望まないことです。解決策は、書き込み中のスナップショットに影響を与えない場合に新しい更新を受け入れることができるコピーオンライト技術を使用することです。たとえば、オペレーティング システムのコピーオンライト テクノロジー

クライアントとの対話

このセクションでは、クライアントがクラスタ リーダーを見つける方法や Raft が線形化可能なセマンティクスをサポートする方法など、クライアントが Raft と対話する方法について説明します。

線形化されたセマンティクスは、平たく言えば、線形一貫性、つまり強い一貫性です。これは、操作が実行された後、すべての個人に即座に表示され、一度だけ実行される必要があることを意味します。

これらの問題はすべてのコンセンサスベースのシステムに当てはまり、Raft のソリューションは他のシステムと同様です。

Raft のクライアントはすべてのリクエストをリーダーに送信します。クライアントが初めてオンラインになると、ランダムに選択されたサーバーに接続します。クライアントの最初の選択がリーダーではない場合、AppendEntries RPC にはリーダーのネットワーク アドレスが含まれるため、サーバーはクライアントの要求を拒否し、知っている最も近いリーダーに関する情報を提供します。リーダーがダウンすると、クライアントのリクエストはタイムアウトになり、クライアントはランダムに選択されたサーバーに対してリクエストを再試行します。

Raft の目標は、各操作が呼び出しと応答の間で 1 回だけ瞬時に実行される、線形化可能なセマンティクスを実現することです。しかし、これまでの説明によれば、Raft はコマンドを複数回実行する可能性があります: たとえば、エントリをコミットした後、クライアントに応答する前にリーダーがクラッシュした場合、クライアントは新しいリーダーでコマンドを再試行します。二度目に実行される

解決策は、クライアントが各コマンドに一意のシーケンス番号を割り当てられるようにすることです。その後、ステート マシンが、最後に処理されたシーケンス番号と各クライアントの対応する応答を追跡して記録します。すでに実行されている、対応するシーケンス番号を持つコマンドを受信した場合は、すぐに応答し、リクエストを再実行しません。

読み取り専用 読み取り専用リクエストは、ログに書き込むことなく処理できます。しかし、追加の対策を講じないと、リクエストに応答しているリーダーが知らない新しいリーダーに置き換えられている可能性があるため、古いデータが返されるリスクがあります。線形化可能な読み取りでは古いデータを返してはなりません。Raft では、ログを使用せずにこれを保証するために 2 つの追加の予防策が必要です。

まず、リーダーは、提出されたエントリに関する最新の情報を持っている必要があります。リーダーの完全性プロパティにより、リーダーはすべてのエントリを提出していることが保証されますが、任期の開始時には、これらのエントリが何であるかわからない可能性があります。答えを見つけるには、期間内にエントリーを提出する必要がある

Raft は、各リーダーが学期の初めに空白の no -opエントリをログに送信できるようにすることでこの問題に対処し、この no-op エントリを送信することで、リーダーは送信されたエントリに関する最新情報を得ることができます。

第 2 に、リーダーは、読み取り専用リクエストを処理する前に、リーダーが追放されているかどうかを確認する必要があります。これは、新しいリーダーが選出されている場合、その情報が古くなっている可能性があるためです。

Raft は、読み取り専用リクエストに応答する前に、各リーダーがクラスター内の大半のサーバーとハートビート メッセージを交換することで、この問題に対処します。あるいは、リーダーはハートビート メカニズムに依存してリース形式を提供することもできますが、これには安全のためにクロックへの依存が必要になります (クロック スキューが制限されていると仮定して)。

おすすめ

転載: blog.csdn.net/Pacifica_/article/details/127863287