Implementación del Protocolo de membresía de grupo de procesos (SWIM) de estilo de infección asíncrono, escalable y débilmente consistente escrita en Rust.
Advertencia
Descargo de responsabilidad: este proyecto es un trabajo en progreso y aún no está listo para producción. El código base puede contener errores o funciones incompletas. Úselo con precaución. Se aceptan comentarios y contribuciones, ¡gracias!.
io_uring
a través de Tokio (SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
y ampliar para incluir funciones de Lifeguard de Hashicorp Research Gossipod emplea 3 tipos de mensajes: PING
, PING-REQ
y BROADCAST
(que incluye los subtipos JOIN
, LEAVE
, SUSPECT
, ALIVE
y CONFIRM
). Los mensajes PING
y PING-REQ
son fundamentales para el mecanismo de detección de fallas del sistema basado en SWIM, lo que facilita el intercambio de estado constante al aprovechar la difusión de información sobre este proceso. Cuando se produce un cambio de estado, ya sea a través de solicitudes voluntarias o de detección periódica de fallas, el sistema utiliza mensajes BROADCAST
para la difusión aleatoria de esta información. Cada nodo de la red mantiene un número de encarnación, comenzando en cero, que solo puede ser incrementado por el propio nodo. Este número es crucial para gestionar el estado del nodo en las listas de miembros locales de otros nodos y sirve como medio para refutar sospechas (SWIM+Inf.+Susp.)
de otros nodos. Este diseño permite a Gossipod lograr una gestión de estado distribuida y detección de fallas eficiente y resistente en una red distribuida o descentralizada, equilibrando las necesidades de información actualizada, resolución de conflictos y confiabilidad del sistema.
Por extensión, Lifeguard ofrece funciones de implementación adicionales que aún no están incorporadas en la versión actual de Gossipod y que son totalmente compatibles con la lista de miembros de Hashicorp. Planeo integrar estas funciones en una versión futura.
diagrama de secuencia
participante N1 como Nodo 1
participante N2 como Nodo 2
participante N3 como Nodo 3
participante Nx como Nodo x (Aleatorio)
Nota sobre N1, Nx: Sondeo y difusión de información a través de la colaboración
N1->>N2: PING (con información superpuesta)
N2->>N1: ACK (con información combinada)
N1->>N3: PING-REQ (para N2)
N3->>N2: PING
N2->>N3: CONFIGURACIÓN
N3->>N1: ACK (indirecto)
Nota sobre N1,Nx: Difusión del cambio de estado
N1->>Nx: TRANSMISIÓN (ABANDONAR/UNIRSE/SOSPECHO/CONFIRMAR)
Nx->>N2: PING (con cambios de estado combinados)
N2->>N3: PING (con cambios de estado combinados)
Nota sobre N1, Nx: Detección y recuperación de fallas
N1->>N2: PING (sin respuesta)
N1->>N3: PING-REQ (para N2)
N3->>N2: PING (sin respuesta)
N3->>N1: NACK
N1->>Nx: TRANSMISIÓN (SOSPECHOSO N2)
Nota sobre N2: N2 recibe un mensaje SOSPECHOSO
N2->>N2: Incrementar el número de encarnación
N2->>Nx: TRANSMISIÓN (VIVO con nuevo número de encarnación)
alt N2 refuta exitosamente
Nx->>N1: PING (con ALIVE N2 a cuestas)
Nota sobre N1: actualice el estado de N2 a vivo
De lo contrario, N2 no refuta a tiempo.
N1->>Nx: TRANSMISIÓN (CONFIRME N2 como fallido)
fin
Para ver Gossipod en acción, consulte el directorio ./examples
, que incluye varias demostraciones. A continuación puede ejecutar dos instancias diferentes de gossipod especificando diferentes direcciones de puerto y nombres de nodo.
> 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 ? ;
Aquí hay un ejemplo básico de cómo usar Gossipod en su aplicación:
// 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 ;
}