分散コンセンサスアルゴリズムの実装 - Raft アルゴリズム

分散コンセンサスアルゴリズムの実装 - Raft アルゴリズム

[[385285]]

著者は、Raftアルゴリズムフレームワークraft-coreの独自のJavaバージョンをオープンソース化しました。

プロジェクトリンク: https://github.com/wujiuye/delay-scheduler/tree/main/raft/raft-core

このプロジェクトコードは、delay-scheduler (分散遅延スケジューリングミドルウェア) のサブモジュールです。レベルが制限されているため、学習して使用することのみをお勧めします。

CAP原則について

C (一貫性)、A (可用性)、P (分断耐性) の原則は、分散システムでは避けられないテーマです。どの分散システムでも、可用性、一貫性、分断耐性は互いに矛盾しています。3 つすべてを同時に実現することはできず、最大でも 2 つしか実現できません。

AP: システムに高可用性 (A) とパーティション耐性 (P) が必要な場合は、一貫性 (C) を放棄する必要があります。

CP: 強力なデータ一貫性 (C) が必要な場合、ネットワーク パーティションによって同期時間が無限に延長されるため (P)、可用性を保証できず、可用性を放棄する必要があります (A)。

CA: ネットワーク パーティション (パーティションは異なるデータ センター/国/地域を指します) (P) がない場合、強力な一貫性 (C) と可用性 (A) を同時に満たすことができます。

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

Raft クラスターでは、各ノードはリーダーまたはフォロワーのいずれかの役割に対応します。リーダーが選出される前は、各ノードは候補になることができます。

Raft アルゴリズムでは、Raft クラスターにはリーダー ノードが 1 つだけ存在でき、リーダー ノードのみがクライアントの読み取りおよび書き込み要求を処理し、書き込み要求を操作ログに変換し、リーダー ノードが操作ログを他のフォロワー ノードにコピーできることが規定されています。リーダー ノードが操作ログを大多数のノード (リーダー ノード自身を含む) に正常に同期すると、操作ログをステート マシンに適用でき、ステート マシンが書き込み操作 (コマンドの実行) を実行して、データの最終的な一貫性を確保します。

Binlog は、MySQL データベースによって実行される書き込み操作コマンドと考えることができます。また、MyISAM ストレージ エンジンは、コマンドを実行するために使用される Binlog のステート マシンです。

Raft アルゴリズムを実装するには、次の 2 つの RPC インターフェースを実装する必要があります。

  • RequestVoteRpc: 選挙中、現在の候補ノードは他のノードからの投票要求を開始します。
  • AppendEmtriesRpc: リーダー ノードは、日記の複製要求、ハートビート要求、日記の送信要求を他のフォロワー ノードに送信します。

定期的なハートビートタイマー

リーダー ノードは、他のフォロワー ノードの選択タイムアウトを更新するために、他のフォロワー ノードに定期的にハートビート パケットを送信する必要があります。

ハートビート タイマーは、ノードがリーダーになると開始され、ノードがフォロワーになると停止します。ハートビート タイムアウト間隔は、選出タイムアウト間隔よりも長くする必要があります。つまり、ハートビート タイムアウト (ハートビート パケットのブロードキャスト時間) < 選出タイムアウト (選出タイムアウト) です。

タイムアウト選挙タイマー

タイミングがタイムアウト (選挙タイムアウト) しきい値に達すると、リーダー選挙がトリガーされます。現在のノードは、任期番号を 1 増やし、自分自身に投票しようとします (他の候補者にまだ投票していない場合)。自分自身に投票することに成功した場合、そのノードは候補者となり、他のノードに投票要求を開始します。

タイムアウト選択タイマーの現在のカウントは、AppendEntriesRPC (ハートビート要求を含む) 要求を受信するとリセットされ、再開されます。複数の選挙ラウンドの後にリーダーを選出できない状況が発生する可能性がある同時選挙要求を回避するために、各ノードのタイムアウトしきい値が異なる必要があります。

リーダー選出プロセス

リーダーは投票メカニズムによって選出されます。各ノードは、各ターム番号に対して 1 票しか持つことができません。各ノードは、自分自身への投票を優先します。過半数の票を獲得したノードがリーダー ノードになります。したがって、Raft クラスターには少なくとも 3 つのノードが必要であり、Raft クラスター内のノードの合計数は奇数であることが望ましいです。

RequestVoteRpc 要求データ パケット (投票集計データ パケット):

  1. パブリッククラスRequestVote {
  2. プライベート長期;
  3. プライベートint候補ID;
  4. プライベート長いlastLogIndex;
  5. プライベート長いlastLogTerm;
  6. }
  • 任期: 選挙運動当事者(候補者ノード)の現在の任期番号。
  • candidateId: 選挙運動を行う政党のノード ID。
  • lastLogIndex: 調査員の最新のログエントリのインデックス値。
  • lastLogTerm: 選挙運動員の最新の日記エントリに対応する学期番号。

RequestVoteRpc 応答データ パケット (投票データ パケット):

  1. パブリッククラスRequestVoteResp {
  2. プライベート長期;
  3. プライベートブール値 voteGranted;
  4. }
  • 任期: 投票者の現在の任期番号。任期値を更新するよう選挙運動者に通知するために使用されます。
  • voteGranted: 投票政党が選挙運動政党に投票した場合、voteGranted は true になります。それ以外の場合は false になります。

選挙タイマーがタイムアウトしたときに選挙運動要求を開始するプロセスは次のとおりです。

1) ローカルに保持されている現在の用語番号 (term) を 1 増やします。

2) 自分自身に投票します。投票が成功した場合、ステータスが候補ノード (候補者) に切り替わります。したがって、各候補ノードの最初の投票は、自分自身から行われます。

3) クラスター内の他のノードに RequestVoteRPC リクエスト (投票リクエスト) を送信し、自分自身に投票するよう依頼します。

各ノードが他の候補ノードから投票要請要求を受信すると、ノードの現在の任期番号、ログ同期ステータス、および他のノード (自分自身を含む) に現在の任期の投票をすでに投じているかどうかに基づいて、次のように応答する必要があります。

1) 選挙運動員の任期が現在の任期よりも短い場合は、false を返して選挙運動員に任期が期限切れであることを思い出させ、選挙運動員にこの投票は行われないことを明確に伝えます。

2) 選挙運動員の任期が現在の任期よりも長く、かつ選挙運動員がこれまで誰にも投票したことがない場合(自分自身を含む)、選挙運動員はノードに投票し、選挙運動員の任期と true を返します。

3) それ以外の場合、選挙運動員の任期が現在の任期と同じで、選挙運動員に投票が行われており (繰り返し要求のシナリオ)、要求者の日記が自身の日記と同じくらい新しい場合は、選挙運動員の任期と true を返します。

4) そうでない場合、以前に他の誰かに投票が行われていた場合、この投票は請求側のためには行われず、請求側に対してはこの投票は行われないことが明確に伝えられます。

候補者ノードが選挙運動要求をブロードキャストした後、最終投票結果に基づいて次のように応答する必要があります。

1) 大多数のノードが異常に接続している場合は、現在の期間に引き続き調査を再開します。つまり、大多数のノードがダウンしており、選挙が異常です。

2) リーダーになるために、自分自身への 1 票を含め、ほとんどのノードの票を獲得します。ただし、各ノードは 1 票しか持ちません。自分自身に投票した場合、他のノードに投票することはできません。

3) 他のノードが選挙に勝ったことが判明した場合(選挙要求応答の期間が現在の候補ノードの期間よりも長い場合、他のノードが選挙に勝ったとみなされます)、積極的にフォロワーに戻ります。

4) タイムアウト選出タイマーが再度タイムアウト選出をトリガーした場合、リーダーのハートビート パケットが受信されておらず、前回の選出でリーダーになるための選出に勝利したノードがなかったことを意味し、引き続き選出を開始します。

別のノードが現在の期間のリーダーになった場合、リーダーはハートビート パケットを送信して自分自身に通知します。リーダーがハートビート パケットを自分自身に送信するのに十分な時間を与える必要があります。したがって、選出タイムアウトはハートビート タイムアウトよりも大きくする必要があります。つまり、ハートビート タイムアウト (ハートビート パケットのブロードキャスト時間) < 選出タイムアウト (選出タイムアウト) です。

選出後、各フォロワー ノードは現在のリーダー ノードがどれであるかを記録し、リーダー ノードは他のすべてのフォロワー ノードを記録する必要があります。リーダー ノードは、ハートビート パケットと日記同期要求を他のフォロワー ノードに送信する必要があり、他のフォロワー ノードは、クライアント要求を受信したときに、要求をリーダー ノードにリダイレクトするようにクライアントに通知する必要があります。

Raft ログ複製プロセス

Raft クラスターでは、リーダー ノードがクライアントからの読み取りおよび書き込み要求を受信する役割を担います。フォロワーが要求を受信した場合、その要求をリーダー ノードにリダイレクトする必要があります。

リーダーノードが読み取り要求を受信した場合、リーダーノードはデータを直接照会してクライアントに応答できます。リーダーノードが書き込み要求を受信した場合、リーダーノードは最初に書き込み要求を操作ログに変換し、操作ログをローカルノードに追加します。同時に、他のノードへの AppendEntriesRPC 呼び出しを開始して、操作ログを他のノードにコピーします。ほとんどのノードのコピーに成功した後、リーダーノードは操作ログを送信します。送信が成功した場合、状態マシンに適用され、次に他のノードへの AppendEntriesRPC 呼び出しを非同期的に開始して、ログが送信されたことを他のフォロワーノードに通知します。送信要求を受信した後、フォロワーノードは最初にログを送信された状態に変更し、次にログを状態マシンに適用します。

AppendEntriesRPC 要求データ パケット (リーダー ノードは他のフォロワー ノードに対して RPC 要求を開始し、他のフォロワー ノードにこの日記エントリをコピーするよう要求します):

  1. パブリッククラスAppendEntriesはCloneableを実装します{
  2. プライベート長期;
  3. プライベートintリーダー ID;
  4. プライベート長いprevLogIndex;
  5. プライベート長いprevLogTerm;
  6. プライベートな長いリーダーコミット;
  7. プライベートCommandLog[]エントリ;
  8. }
  • term: リーダーノードが日記エントリを作成した時点のターム番号。
  • leadersId: リーダー ノードの ID。これにより、他のフォロワー ノードはクライアント要求をリーダー ノードにリダイレクトできます。
  • prevLogIndex: リーダーノードによって送信されたログ内の最新のログエントリのインデックス。
  • prevLogTerm: リーダーノードによって送信されたログ内の最新のログエントリの用語番号。
  • leaderCommit: リーダー ノードは、フォロワーごとに leaderCommit を保持します。これは、リーダー ノードがフォロワーが送信したと信じている日記エントリのインデックス値を示します。
  • エントリ: フォロワーに追加される日記エントリ。ハートビート パケットの場合、エントリは空になります。

AppendEntriesRPC 応答パケット (AppendEntries RPC 応答):

  1. パブリッククラスAppendEntriesResp {
  2. プライベート長期;
  3. プライベートブール値の成功;
  4. }

term: 現在のターム番号。これは Max (AppendEntries リクエストで運ばれるタームとフォロワーによってローカルに維持されるターム) です。これは、リーダー ノードが自身のターム番号を更新するために使用されます。リーダー ノードは、ターム番号が自身のものより大きいことを検出すると、古いリーダーであることを示し、ハートビート パケットの送信を停止してフォロワーに積極的に切り替える必要があります。

success: 受信者 (フォロワー) が prevLogIndex と prevLogTerm を一致できるかどうか。一致した場合、リクエストは成功です。

リーダー ノードがクライアントの書き込み要求を処理し、書き込み要求ログをフォロワーにコピーするプロセス:

0) クライアントはリーダーに書き込み要求を送信します。

1) リーダーは書き込み要求を操作指示ログに解析し、それをローカル ログ ファイルに追加します。

2) リーダーは他のフォロワーノードに AppendEntriesRPC リクエストを非同期的に送信します。

3) ブロックして、大多数のノードが正常に応答するまで待機します。大多数のノードとは、少なくともノードの総数を 2 で割った数に 1 を加えた数です。リーダー ノード自体も 1 としてカウントされるため、正常に応答するには、ノードの総数を 2 で割った数だけが必要です。

4) 大多数のノードが正常に応答した場合: リーダーはログエントリを送信してローカルステートマシンに適用し、ログが送信されたことを他のフォロワーノードに非同期的に通知し、操作結果をすぐにクライアントに返します。

5) それ以外の場合: クライアントに失敗を応答します。

フォロワー ノードはログ複製要求プロセスを処理します。

0) 任意の AppendEntriesRPC 要求 (ハートビート パケット要求、日記送信要求、日記追加要求を含む) を受信すると、選出タイムアウト タイマーの現在の時刻がリセットされます。

1) 自身の任期がリクエストパラメータの任期より長く、ローカルに記録されたリーダーの任期番号が自身の任期より小さい場合、自身の任期が返され、成功は false になります (要求者に期限切れのリーダーであることを通知します)。

2) それ以外の場合、prevLogIndex ログ内の Follower 自体のターム番号がリクエストパラメータ prevLogTerm と一致しない場合は、自身のタームが返され、成功は false になります (現在の Follower ノードのログが遅れています)。

3) それ以外の場合、現在ハートビート パケットが 1 つしかない場合は、リーダーのハートビートが受信されたことを意味し、これはリーダーがすでにフォロワーであることを意味します。必要に応じて、リーダーは候補ノードからフォロワー ノードに切り替え、独自の用語を返し、成功は true になります。

4) それ以外の場合、Follower は日記の一貫性チェックを実行し、既存の不一致な日記を削除し、既存の日記に存在しないエントリを追加し、冗長なエントリを削除し、すでにコミットされたエントリをコピーする場合は、コピーが成功したら直接コミットします。

5) リクエストパラメータのleaderCommitが現在のcommitIndexより大きい場合、commitIndexはMax(leaderCommit, commitIndex)に更新され、ローカルコミットされたダイアリーのcommitIndexは、フォロワーが追跡するためにリーダーが記憶している値に楽観的に進められます。これは、フォロワーが障害から回復したばかりのシナリオで使用されます。

フォロワー ノードがリーダー ノードに、ログ追加が失敗し、フォロワー ノードの現在の期間番号がリーダーの現在の期間番号以下であると応答した場合、リーダー ノードはパラメーター prevLogIndex の減少を要求し、AppendEntriesRPC が成功を返すまで AppendEntriesRPC 要求を再開します。成功は、リーダーとフォロワーが prevLogIndex 位置のログ エントリで一貫していることを示します。このとき、フォロワー ノードの prevLogIndex 位置より前のすべてのログ エントリは保持され、prevLogIndex 位置より後のすべてのログ エントリ (リーダーと競合する) はフォロワーによって削除され、リーダーの prevLogIndex 位置より後のすべてのログ エントリはその位置から追加されます。したがって、AppendEntriesRPC が正常に返されると、リーダーとフォロワーのログの一貫性が保たれます。

一貫性

候補ノードがリーダーになるには、ノードの過半数から投票される必要があり、ノードは独自のログを持たない新しい候補ノードには投票しません。さらに、リーダーは、ログを過半数のノード(自分自身を含む)に正常に同期した後にのみ、ログを送信します(ログを送信された状態に変更し、それをステート マシンに適用します)。したがって、毎回選出されるリーダーは、送信されたすべてのログを含むノードです。

新しいリーダー ノードが新しい日記をフォロワー ノードに同期するときに、フォロワー ノードの日記が大幅に遅れている場合、フォロワー ノードはリーダーにない日記を積極的に削除し、リーダー ノードの日記をフォロワーに同期します。リーダー ノードが送信済みとしてマークした日記については、フォロワーはそれを受信したときにそれをステート マシンに直接適用して、データの最終的な一貫性を維持できます。

マルチラフト

3 台のマシンがあり、各マシンに Raft ノード サービスがデプロイされているとします。読み取りおよび書き込み要求はリーダー ノードによって処理されるため、動作できるのは 1 台のマシンだけですよね?

ノード サービスに対して複数の Raft サービス (複数のプロセスではないことに注意してください) を開始して、複数の Raft クラスター (つまり、Multi Raft) を構築できます。このようにして、各 Raft クラスターのリーダー ノードを複数のマシンに均等に分散できます。例えば:

機械 Raft Raft Raft
マシン1 RaftサービスAノード1Leader RaftサービスBノード1Follower RaftサービスCノード1Follower
マシン2 RaftサービスAノード2Follower RaftサービスBノード2Leader RaftサービスCノード2 ( Follower )
マシン3 RaftサービスAノード3Follower RaftサービスBノード3Follower RaftサービスCノード3Leader

分散データベース TiDB では、Multi Raft を使用してデータを分割し、各 Raft クラスターがデータの一部を担当するようにします。

参考文献

Huawei クラウド コンテナ サービス チーム。「クラウド ネイティブ分散ストレージの基礎: etcd の詳細な分析」(クラウド コンピューティング テクノロジー シリーズ)

ラフト紙の住所

Raft 論文の中国語版: https://github.com/maemual/raft-zh_cn

画像ソース

画像ソース: https://github.com/maemual/raft-zh_cn/tree/master/images

この記事はWeChatの公開アカウント「Java Art」から転載したものです。以下のQRコードからフォローできます。この記事を転載する場合はJava Art公式アカウントまでご連絡ください。

<<:  ファーウェイがGood Vision Cloud Serviceを正式に開始、包括的なマシンビジョンの時代を先導

>>:  これは陰謀論ですか? AIさん、どう思いますか?

ブログ    
ブログ    

推薦する

JD.com、ビリビリ、ピンドゥオドゥオなど中国企業88社が米国の上場廃止前リストに含まれ、中国コンセプト株がクリアされる可能性

半月も経たないうちに、第6波がまたやってきました!現地時間5月4日、米証券取引委員会は再び「上場廃止...

人工知能の今後5年間で世界が注目する10人

[[251996]]十分に大きな技術的放射効果により、人工知能は世界経済の発展において主導的な地位に...

フードデリバリーロボット市場は11.6億規模に到達。美団は「台頭」するか?

近年、ロボット産業は急速に発展しており、工業、農業、サービスなど多くの分野でロボットが見られるように...

テスラとモメンタの「自動運転アルゴリズム」の秘密を研究した

現在、自動運転技術は研究室を抜け出し、量産段階に入っており、大手自動車メーカーや部品サプライヤー、ハ...

研究者:AIは将来「感情」を持つことが期待されており、関連する医療ハードウェア産業の発展に役立つ可能性がある

著名なAI研究者のジェフリー・ヒントン氏は、Googleを退職後、人工知能関連産業の研究に専念してい...

...

生成 AI が流行する中、コンプライアンス計画にはどのような変化が見られるのでしょうか?

消費者のショッピング嗜好を予測したり、軍事上の意思決定を導いたり、金融犯罪に関する独自の洞察を提供し...

革新を続ける: 6月のロボット研究開発の概要

近年、人工知能への熱狂が多くの業界を席巻しており、ロボット工学の分野も例外ではありません。人工知能技...

強化学習は AGI を実現するのに十分でしょうか?サットン:報酬メカニズムはさまざまな目標を達成するのに十分です

[[405185]]人工知能の分野では、何十年もの間、コンピューター科学者が視覚、言語、推論、運動能...

ナレッジグラフの過去と現在: ナレッジグラフがなぜ人気なのか?

[51CTO.com からのオリジナル記事] 近年、ナレッジグラフは、その強力な表現力、優れたスケ...

...

うつ病で人生が押​​しつぶされたとき、AIを使ってうつ病を診断することで、どん底を味わう人々を救えるのでしょうか?

韓国のお笑いタレント、パク・チソンさんとその母親が自宅で死亡しているのが発見されたが、これはうつ病が...

敵対的 AI とは何ですか?なぜそれが重要なのでしょうか?

[[250514]] [51CTO.com クイック翻訳] 人工知能 (AI) は、政府、企業、国...

ChatGPT のパフォーマンスが最大 214% 向上し、7 つのグラフが更新されました。 IDEA、HKUST GuazhouなどがToG思考マップを提案

大きなモデルは良いですが、「深刻なナンセンス」の問題をどのように解決するのでしょうか?金融、法律、医...

脳とコンピューターのインターフェースのための新しい「接着剤」が発明され、人間と機械の融合「サイボーグ」における新たな進歩がもたらされる

マスク氏の脳コンピューターインターフェースは「人間でテスト」されようとしているが、侵襲的な脳コンピュ...