Asynchrone, skalierbare, schwach konsistente Process Group Membership Protocol (SWIM)-Implementierung im Infektionsstil, geschrieben in Rust.
Warnung
Haftungsausschluss: Dieses Projekt ist in Arbeit und noch nicht produktionsreif. Die Codebasis kann Fehler oder unvollständige Funktionen enthalten. Mit Vorsicht verwenden. Feedback und Beiträge willkommen, Danke!.
io_uring
Laufzeit über Tokio (SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
und erweitern Sie es um Funktionen von Lifeguard von Hashicorp Research Gossipod verwendet drei Arten von Nachrichten: PING
, PING-REQ
und BROADCAST
(einschließlich der Untertypen JOIN
, LEAVE
, SUSPECT
, ALIVE
und CONFIRM
). Die PING
und PING-REQ
Nachrichten sind von zentraler Bedeutung für den auf SWIM basierenden Fehlererkennungsmechanismus des Systems und erleichtern den ständigen Zustandsaustausch durch Huckepack-Informationsverbreitung über diesen Prozess. Wenn eine Zustandsänderung auftritt, sei es durch freiwillige Anfragen oder durch regelmäßige Fehlererkennung, verwendet das System BROADCAST
Nachrichten zur zufälligen Verbreitung dieser Informationen. Jeder Knoten im Netzwerk verwaltet eine Inkarnationsnummer, die bei Null beginnt und nur vom Knoten selbst erhöht werden kann. Diese Nummer ist entscheidend für die Verwaltung des Knotenstatus in den lokalen Mitgliederlisten anderer Knoten und dient als Mittel zur Widerlegung von Verdachtsmomenten (SWIM+Inf.+Susp.)
von anderen Knoten. Dieses Design ermöglicht es Gossipod, eine effiziente und belastbare verteilte Zustandsverwaltung und Fehlererkennung in einem verteilten oder dezentralen Netzwerk zu erreichen und so den Bedarf an aktuellen Informationen, Konfliktlösung und Systemzuverlässigkeit in Einklang zu bringen.
Durch die Erweiterung bietet Lifeguard zusätzliche Implementierungsfunktionen, die noch nicht in der aktuellen Version von Gossipod enthalten sind und von der Hashicorp-Mitgliederliste vollständig unterstützt werden. Ich plane, diese Funktionen in einer zukünftigen Version zu integrieren.
Sequenzdiagramm
Teilnehmer N1 als Knoten 1
Teilnehmer N2 als Knoten 2
Teilnehmer N3 als Knoten 3
Teilnehmer Nx als Knoten x (zufällig)
Hinweis zu N1, Nx: Sondierung und Informationsverbreitung per Huckepack
N1->>N2: PING (mit Huckepack-Info)
N2->>N1: ACK (mit Huckepack-Info)
N1->>N3: PING-REQ (für N2)
N3->>N2: PING
N2->>N3: ACK
N3->>N1: ACK (indirekt)
Hinweis zu N1,Nx: Verbreitung von Zustandsänderungen
N1->>Nx: BROADCAST (VERLASSEN/VERBINDEN/VERDÄCHTIGEN/BESTÄTIGEN)
Nx->>N2: PING (mit Huckepack-Zustandsänderungen)
N2->>N3: PING (mit Huckepack-Zustandsänderungen)
Hinweis zu N1, Nx: Fehlererkennung und -wiederherstellung
N1->>N2: PING (keine Antwort)
N1->>N3: PING-REQ (für N2)
N3->>N2: PING (keine Antwort)
N3->>N1: NACK
N1->>Nx: BROADCAST (VERDÄCHTIGER N2)
Hinweis zu N2: N2 empfängt die Meldung SUSPECT
N2->>N2: Inkarnationsnummer erhöhen
N2->>Nx: BROADCAST (LEBEND mit neuer Inkarnationsnummer)
alt N2 widerlegt erfolgreich
Nx->>N1: PING (mit huckepack genommenem ALIVE N2)
Hinweis zu N1: N2-Status auf „Aktiv“ aktualisieren
sonst widerlegt N2 nicht rechtzeitig
N1->>Nx: BROADCAST (N2 als fehlgeschlagen bestätigen)
Ende
Um Gossipod in Aktion zu sehen, schauen Sie sich das Verzeichnis ./examples
an, das eine Reihe von Demos enthält. Unten können Sie zwei verschiedene Instanzen von Gossipod ausführen, die unterschiedliche Portadressen und Knotennamen angeben
> 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 ? ;
Hier ist ein einfaches Beispiel für die Verwendung von Gossipod in Ihrer Anwendung:
// 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 ;
}