Rust で書かれた、非同期でスケーラブルな弱一貫性の感染スタイルのプロセス グループ メンバーシップ プロトコル (SWIM) 実装。
警告
免責事項:このプロジェクトは進行中の作業であり、まだ製品化の準備ができていません。コードベースにはバグや不完全な機能が含まれている可能性があります。慎重に使用してください。フィードバックと貢献は大歓迎です。ありがとうございます。
io_uring
ランタイムをサポート(SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
を実装し、Hashicorp Research による Lifeguard の機能を含めるように拡張します。 Gossipod は、 PING
、 PING-REQ
、およびBROADCAST
(サブタイプJOIN
、 LEAVE
、 SUSPECT
、 ALIVE
、およびCONFIRM
を含む) の 3 種類のメッセージを使用します。 PING
およびPING-REQ
メッセージは、システムの障害検出メカニズムのベースオフ SWIM の中心であり、このプロセスに便乗した情報配布によって定常状態の交換を促進します。自発的な要求または定期的な障害検出によって状態変化が発生すると、システムはBROADCAST
メッセージを使用してこの情報をランダムに配布します。ネットワーク内の各ノードは、ゼロから始まるインカネーション番号を維持します。この番号は、ノード自体によってのみ増加できます。この番号は、他のノードのローカル メンバーシップ リストでノードの状態を管理するために重要であり、他のノードからの疑惑(SWIM+Inf.+Susp.)
を反論する手段として機能します。この設計により、Gossipod は、分散ネットワークまたは分散ネットワークで効率的かつ回復力のある分散状態管理と障害検出を実現し、最新の情報、競合解決、システムの信頼性のニーズのバランスをとることができます。
拡張機能により、Lifeguard は、Hashicorp メンバーリストによって完全にサポートされている Gossipod の現在のバージョンにまだ組み込まれていない追加の実装機能を提供します。これらの機能を将来のリリースに統合する予定です。
シーケンス図
ノード 1 としての参加者 N1
ノード 2 としての参加者 N2
ノード 3 としての参加者 N3
ノード x としての参加者 Nx (ランダム)
N1、Nx に関するメモ: 便乗による探索と情報拡散
N1->>N2: PING (便乗情報あり)
N2->>N1: ACK (便乗情報あり)
N1->>N3: PING-REQ (N2 用)
N3->>N2: PING
N2->>N3: ACK
N3->>N1: ACK (間接)
N1、Nx に関する注意: 状態変更の配布
N1->>Nx: ブロードキャスト (離脱/参加/容疑者/確認)
Nx->>N2: PING (ピギーバックされた状態変更あり)
N2->>N3: PING (ピギーバックされた状態変化あり)
N1、Nx に関するメモ: 障害の検出と回復
N1->>N2: PING (応答なし)
N1->>N3: PING-REQ (N2 用)
N3->>N2: PING (応答なし)
N3->>N1: NACK
N1->>Nx: ブロードキャスト (容疑者 N2)
N2 に関するメモ: N2 は SUSPECT メッセージを受信します
N2->>N2: インカネーション番号をインクリメントします
N2->>Nx: ブロードキャスト (新しい化身番号で生きています)
alt N2 が反論に成功しました
Nx->>N1: PING (ピギーバックされた ALIVE N2 を使用)
N1 に関するメモ: N2 ステータスを生きた状態に更新します
そうでなければN2は時間内に反論しない
N1->>Nx: ブロードキャスト (N2 が失敗したことを確認)
終わり
Gossipod の動作を確認するには、 ./examples
examples ディレクトリをチェックしてください。このディレクトリには、多数のデモが含まれています。以下では、異なるポート アドレスとノード名を指定して gossipod の 2 つの異なるインスタンスを実行できます。
> cargo run -p ping_node -- --name=NODE_1 --port=7948
> cargo run -p pong_node -- --name=NODE_2 --port=7947 --join-addr=127.0.0.1:7948
let config = GossipodConfigBuilder :: new ( )
. with_name ( & args . name )
. with_port ( args . port )
. with_addr ( args . ip . parse :: < Ipv4Addr > ( ) . expect ( "Invalid IP address" ) )
. with_probing_interval ( Duration :: from_secs ( 1 ) )
. with_ack_timeout ( Duration :: from_millis ( 500 ) )
. with_indirect_ack_timeout ( Duration :: from_secs ( 1 ) )
. with_suspicious_timeout ( Duration :: from_secs ( 5 ) )
. with_network_type ( NetworkType :: LAN )
. build ( )
. await ? ;
let gossipod = Gossipod :: new ( config ) . await ? ;
# [ derive ( Clone , Debug , Serialize , Deserialize , PartialEq , Eq , Hash ) ]
struct Metadata {
region : String ,
datacenter : String ,
}
impl NodeMetadata for Metadata { }
let metadata = Metadata {
region : "aws-west-1" . to_string ( ) ,
datacenter : "dc1" . to_string ( ) ,
} ;
let gossipod = Gossipod :: with_metadata ( config , metadata ) . await ? ;
アプリケーションで Gossipod を使用する基本的な例を次に示します。
// Configuration
let config = GossipodConfigBuilder :: new ( )
. with_name ( & args . name )
. with_port ( args . port )
. with_addr ( args . ip . parse :: < Ipv4Addr > ( ) . expect ( "Invalid IP address" ) )
. with_probing_interval ( Duration :: from_secs ( 1 ) )
. with_ack_timeout ( Duration :: from_millis ( 500 ) )
. with_indirect_ack_timeout ( Duration :: from_secs ( 1 ) )
. with_suspicious_timeout ( Duration :: from_secs ( 5 ) )
. with_network_type ( NetworkType :: LAN )
. build ( )
. await ? ;
// New instance
let gossipod = Arc :: new ( Gossipod :: new ( config . clone ( ) ) . await ? ) ;
// Start Gossipod
tokio :: spawn ( gossipod . clone ( ) . start ( ) ) ;
// Wait for Gossipod to start
while !gossipod . is_running ( ) . await {
time :: sleep ( Duration :: from_millis ( 100 ) ) . await ;
}