「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > etcd Raft ライブラリを使用して独自の分散 KV ストレージ システムを構築する方法

etcd Raft ライブラリを使用して独自の分散 KV ストレージ システムを構築する方法

2024 年 7 月 30 日に公開
ブラウズ:160

How to Build Your Own Distributed KV Storage System Using the etcd Raft Library

導入

raftexample は、etcd raft コンセンサス アルゴリズム ライブラリの使用法を示す etcd によって提供される例です。 raftexample は最終的に、REST API を提供する分散キー値ストレージ サービスを実装します。

この記事では、読者が etcd raft ライブラリの使用方法と raft ライブラリの実装ロジックをよりよく理解できるように、raftexample のコードを読んで分析します。

建築

raftexample のアーキテクチャは非常にシンプルで、主なファイルは次のとおりです:

  • main.go: raft モジュール、httpapi モジュール、kvstore モジュール間の対話を整理する責任を負います;
  • raft.go: 提案の送信、送信する必要がある RPC メッセージの受信、ネットワーク送信の実行など、Raft ライブラリとの対話を担当します。
  • httpapi.go: REST API の提供を担当し、ユーザー リクエストのエントリ ポイントとして機能します。
  • kvstore.go: コミットされたログ エントリを永続的に保存する責任を負い、raft プロトコルのステート マシンに相当します。

書き込みリクエストの処理フロー

書き込みリクエストは、HTTP PUT リクエストを介して httpapi モジュールの ServeHTTP メソッドに到着します。

curl -L http://127.0.0.1:12380/key -XPUT -d value

スイッチを介して HTTP リクエスト メソッドを照合した後、PUT メソッドの処理フローに入ります:

  • HTTP リクエストの本文 (値) からコンテンツを読み取ります。
  • kvstore モジュールの Propose メソッドを使用してプロポーザルを構築します (キーとしてキー、値として値を持つキーと値のペアを追加します);
  • 返すデータがないため、クライアントに 204 StatusNoContent;
  • で応答します。

提案は、raft アルゴリズム ライブラリによって提供される Propose メソッドを通じて raft アルゴリズム ライブラリに送信されます。

プロポーザルの内容には、新しい Key-Value ペアの追加、既存の Key-Value ペアの更新などが含まれます。

// httpapi.go
v, err := io.ReadAll(r.Body)
if err != nil {
    log.Printf("Failed to read on PUT (%v)\n", err)
    http.Error(w, "Failed on PUT", http.StatusBadRequest)
    return
}
h.store.Propose(key, string(v))
w.WriteHeader(http.StatusNoContent)

次に、kvstore モジュールの Propose メソッドを調べて、提案がどのように構築され、処理されるかを見てみましょう。

Propose メソッドでは、最初に gob を使用して書き込まれるキーと値のペアをエンコードし、次にエンコードされたコンテンツを、kvstore モジュールによって構築された提案を raft モジュールに送信する役割を担うチャネルである ProposalC に渡します。

// kvstore.go
func (s *kvstore) Propose(k string, v string) {
    var buf strings.Builder
    if err := gob.NewEncoder(&buf).Encode(kv{k, v}); err != nil {
        log.Fatal(err)
    }
    s.proposeC 



kvstore によって構築され、proposalC に渡されたプロポーザルは、raft モジュールのserveChannels メソッドによって受信され、処理されます。

proposalC が閉じられていないことを確認した後、raft モジュールは、raft アルゴリズム ライブラリによって提供される Propose メソッドを使用して処理するために、提案を raft アルゴリズム ライブラリに送信します。

// raft.go
select {
    case prop, ok := 



プロポーザルが送信されると、raft アルゴリズム プロセスに従います。プロポーザルは最終的にリーダー ノードに転送されます (現在のノードがリーダーではなく、DisableProposalForwarding 構成によって制御され、フォロワーにプロポーザルの転送を許可している場合)。リーダーは、提案をログ エントリとしてラフト ログに追加し、他のフォロワー ノードと同期します。コミットされたとみなされた後、ステート マシンに適用され、結果がユーザーに返されます。

ただし、etcd raft ライブラリ自体はノード間の通信、raft ログへの追加、ステート マシンへの適用などを処理しないため、raft ライブラリはこれらの操作に必要なデータを準備するだけです。実際の操作は弊社で行う必要があります。

したがって、このデータを raft ライブラリから受信し、そのタイプに基づいて適切に処理する必要があります。 Ready メソッドは、処理する必要のあるデータを受信できる読み取り専用チャネルを返します。

受信したデータには、適用されるスナップショット、raft ログに追加されるログ エントリ、ネットワーク経由で送信されるメッセージなど、複数のフィールドが含まれることに注意してください。

書き込みリクエストの例 (リーダー ノード) を続けると、対応するデータを受信した後、サーバー クラッシュによって引き起こされる問題 (例: 複数の候補者に投票するフォロワー) に対処するために、スナップショット、HardState、およびエントリを永続的に保存する必要があります。この論文で説明されているように、HardState と Entries は、すべてのサーバー上で Persistent 状態を構成します。それらを永続的に保存した後、スナップショットを適用して raft ログに追加できます。

現在リーダー ノードであるため、raft ライブラリは MsgApp タイプのメッセージを返します (論文の AppendEntries RPC に対応)。これらのメッセージをフォロワー ノードに送信する必要があります。ここでは、ノード通信に etcd によって提供される rafthttp を使用し、Send メソッドを使用してメッセージをフォロワー ノードに送信します。

// raft.go
case rd := 



次に、publishEntries メソッドを使用して、コミットされた raft ログ エントリをステート マシンに適用します。前述したように、raftexample では、kvstore モジュールがステート マシンとして機能します。 publishEntries メソッドでは、ステート マシンに適用する必要があるログ エントリを commitC に渡します。以前のproposalCと同様に、commitCは、raftモジュールがアプリケーションのためにkvstoreモジュールにコミットしたとみなしたログエントリをステートマシンに送信する責任を負います。

// raft.go
rc.commitC 



kvstore モジュールの readCommits メソッドでは、commitC から読み取られたメッセージが gob デコードされて、元のキーと値のペアが取得され、kvstore モジュール内のマップ構造に格納されます。

// kvstore.go
for commit := range commitC {
    ...
    for _, data := range commit.data {
        var dataKv kv
        dec := gob.NewDecoder(bytes.NewBufferString(data))
        if err := dec.Decode(&dataKv); err != nil {
            log.Fatalf("raftexample: could not decode message (%v)", err)
        }
        s.mu.Lock()
        s.kvStore[dataKv.Key] = dataKv.Val
        s.mu.Unlock()
    }
    close(commit.applyDoneC)
}

raft モジュールに戻り、Advance メソッドを使用して、Ready チャネルから読み取ったデータの処理が完了し、次のデータ バッチを処理する準備ができていることを raft ライブラリに通知します。

先ほど、リーダー ノードで、Send メソッドを使用して MsgApp タイプのメッセージをフォロワー ノードに送信しました。フォロワー ノードの rafthttp は、対応するポートをリッスンしてリクエストを受信し、応答を返します。フォロワー ノードが受信したリクエストであっても、リーダー ノードが受信したレスポンスであっても、Step メソッドを通じて処理するために raft ライブラリに送信されます。

raftNode は rafthttp に Raft インターフェイスを実装し、Raft インターフェイスの Process メソッドを呼び出して、受信したリクエストの内容 (MsgApp メッセージなど) を処理します。

// raft.go
func (rc *raftNode) Process(ctx context.Context, m raftpb.Message) error {
    return rc.node.Step(ctx, m)
}

上記は、raftexample での書き込みリクエストの完全な処理フローを説明しています。

まとめ

この記事の内容は以上です。 raftexample の構造の概要を説明し、書き込みリクエストの処理フローを詳しく説明することで、etcd raft ライブラリを使用して独自の分散 KV ストレージ サービスを構築する方法をより深く理解できるようにしたいと考えています。

間違いや問題がある場合は、お気軽にコメントまたは直接メッセージを送ってください。ありがとう。

参考文献

  • https://github.com/etcd-io/etcd/tree/main/contrib/raftexample

  • https://github.com/etcd-io/raft

  • https://raft.github.io/raft.pdf

リリースステートメント この記事は次の場所に転載されています: https://dev.to/justlorain/how-to-build-your-own-distributed-kv-storage-system-using-the-etcd-raft-library-2j69?1侵害がある場合は、削除するには[email protected]までご連絡ください。
最新のチュートリアル もっと>
  • 項目 他の型の方が適している場合は文字列を避ける
    項目 他の型の方が適している場合は文字列を避ける
    1.他のデータ型の代わりに文字列を使用することは避けてください: 文字列はテキストを表すように設計されていますが、数値、列挙型、または集合構造を表すために誤用されることがよくあります。 データが本質的に数値である場合は、String. ではなく、int、float、BigInteger などの型を...
    プログラミング 2024 年 11 月 2 日に公開
  • sync.WaitGroup を使用して Go 同時実行でデッドロックを防ぐ方法
    sync.WaitGroup を使用して Go 同時実行でデッドロックを防ぐ方法
    ゴルーチンのデッドロックの解決このシナリオでは、Go 同時実行コードでデッドロック エラーが発生しました。問題を詳しく調べて、効率的な解決策を提供しましょう。このエラーは、プロデューサとコンシューマの動作の不一致が原因で発生します。プロデューサー関数に実装されたプロデューサーは、限られた期間、チャネ...
    プログラミング 2024 年 11 月 2 日に公開
  • テキスト ファイル内の Unicode テキストを処理する方法: エラーのない書き込みのための完全ガイド
    テキスト ファイル内の Unicode テキストを処理する方法: エラーのない書き込みのための完全ガイド
    テキスト ファイル内の Unicode テキスト: エラーのない記述のための包括的なガイドGoogle ドキュメントから抽出されたデータのコーディングは、特に困難な場合があります。 HTML で使用するために変換する必要がある非 ASCII シンボルが見つかった場合。このガイドでは、Unicode ...
    プログラミング 2024 年 11 月 2 日に公開
  • EchoAPI と不眠症: 実践例による包括的な比較
    EchoAPI と不眠症: 実践例による包括的な比較
    フルスタック開発者として、私は API のデバッグ、テスト、文書化のための一流のツールを用意することがいかに重要であるかを知っています。 EchoAPI と Insomnia は 2 つの傑出したオプションであり、それぞれに独自の特徴と機能があります。これらのツールについて説明し、その機能と利点を比...
    プログラミング 2024 年 11 月 2 日に公開
  • 移動時間と所要時間 |プログラミングチュートリアル
    移動時間と所要時間 |プログラミングチュートリアル
    導入 このラボは、Go の時間と期間のサポートについての理解をテストすることを目的としています。 時間 以下のコードには、Go で時間と期間を操作する方法の例が含まれています。ただし、コードの一部が欠落しています。あなたの仕事は、コードを完成させて期待通りに動作させ...
    プログラミング 2024 年 11 月 2 日に公開
  • ホイスティングにおける面接の質問と回答
    ホイスティングにおける面接の質問と回答
    1. JavaScript におけるホイスティングとは何ですか? 答え: ホイスティングは、変数や関数にメモリが割り当てられる実行コンテキストの作成フェーズ中のプロセスです。このプロセス中に、変数用のメモリが割り当てられ、変数には未定義の値が割り当てられます。関数の場合、関数定義全...
    プログラミング 2024 年 11 月 2 日に公開
  • JavaScript のドキュメント オブジェクト モデル (DOM) を理解する
    JavaScript のドキュメント オブジェクト モデル (DOM) を理解する
    こんにちは、素晴らしい JavaScript 開発者の皆さん? ブラウザは、スクリプト (特に JavaScript) が Web ページのレイアウトと対話できるようにするドキュメント オブジェクト モデル (DOM) と呼ばれるプログラミング インターフェイスを提供します。 We...
    プログラミング 2024 年 11 月 2 日に公開
  • SPRING BATCH でプログラミングを始める
    SPRING BATCH でプログラミングを始める
    Introduction Dans vos projets personnels ou professionnels, Il vous arrive de faire des traitements sur de gros volumes de données. Le traite...
    プログラミング 2024 年 11 月 2 日に公開
  • CSS で Github プロフィールを目立たせる
    CSS で Github プロフィールを目立たせる
    これまで、Github プロフィールをカスタマイズできる唯一の方法は、写真を更新するか名前を変更することでした。これは、すべての Github プロファイルが同じに見え、カスタマイズしたり目立たせるためのオプションが最小限であることを意味しました。 それ以来、Markdown を使用してカスタム セ...
    プログラミング 2024 年 11 月 2 日に公開
  • TypeScript ユーティリティの種類: コードの再利用性の向上
    TypeScript ユーティリティの種類: コードの再利用性の向上
    TypeScript は、開発者が型を効果的に変換および再利用できるようにする組み込みのユーティリティ型を提供し、コードをより柔軟で ​​DRY にします。この記事では、TypeScript スキルを次のレベルに引き上げるのに役立つ、Partial、Pick、Omit、Record などの主要なユー...
    プログラミング 2024 年 11 月 2 日に公開
  • 電報 window.open(url, &#_blank&#); iOSでは動作がおかしい
    電報 window.open(url, &#_blank&#); iOSでは動作がおかしい
    電報ボットを作成していて、ミニアプリからチャットに情報を転送するオプションを追加したいと考えています。 window.open(url, '_blank'); を使用することにしました。 iPhone で試してみるまでは問題なく動作していました。転送の代わりに、Share を取得しま...
    プログラミング 2024 年 11 月 2 日に公開
  • フロントエンド開発者とは誰ですか?
    フロントエンド開発者とは誰ですか?
    今日のインターネット上のすべての Web サイトやプラットフォームのユーザー インターフェイス部分は、フロントエンド開発者の仕事の成果です。彼らはユーザーフレンドリーなインターフェイスの作成に携わり、サイトの外観と機能を保証します。しかし、フロントエンド開発者とはいったい誰なのでしょうか?簡単に説明...
    プログラミング 2024 年 11 月 2 日に公開
  • CSS スタイルを保持したまま HTML コンテンツを PDF として保存するにはどうすればよいですか?
    CSS スタイルを保持したまま HTML コンテンツを PDF として保存するにはどうすればよいですか?
    CSS を含む HTML コンテンツを PDF として保存するWeb 開発では、コンテンツを別の形式にエクスポートする場合でも、見た目の美しさを維持することが非常に重要です。変換プロセス中に CSS スタイルが失われる可能性があるため、HTML 要素を PDF として保存しようとするときに問題が発生...
    プログラミング 2024 年 11 月 2 日に公開
  • Print_r() の使用時にファントム プロパティが DateTime オブジェクトに追加されるのはなぜですか?
    Print_r() の使用時にファントム プロパティが DateTime オブジェクトに追加されるのはなぜですか?
    Print_r() DateTime オブジェクトを変更しますPrint_r() は、DateTime オブジェクトにプロパティを追加し、デバッグ中のイントロスペクションを有効にします。この動作は、PHP 5.3 で導入された内部機能の副作用であり、テキストにダンプされたインスタンスにファントム パ...
    プログラミング 2024 年 11 月 2 日に公開
  • C のデータ構造とアルゴリズム: 初心者に優しいアプローチ
    C のデータ構造とアルゴリズム: 初心者に優しいアプローチ
    C では、データ構造とアルゴリズムを使用してデータを整理、保存、操作します。データ構造: 配列: 順序付けされたコレクション、インデックスを使用して要素にアクセスする リンク リスト: ポインターを介して要素をリンク、動的長さをサポート スタック: 先入れ後出し (FILO) 原則キュー: 先入れ先...
    プログラミング 2024 年 11 月 2 日に公開

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3