Implementação do Protocolo de associação de grupo de processo (SWIM) assíncrono, escalonável e fracamente consistente no estilo de infecção, escrito em Rust.
Aviso
Isenção de responsabilidade: este projeto é um trabalho em andamento e ainda não está pronto para produção. A base de código pode conter bugs ou recursos incompletos. Use com cuidado. Comentários e contribuições são bem-vindos, obrigado!
io_uring
via Tokio (SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
e estender para incluir recursos do Lifeguard da Hashicorp Research Gossipod emprega 3 tipos de mensagens: PING
, PING-REQ
e BROADCAST
(que inclui os subtipos JOIN
, LEAVE
, SUSPECT
, ALIVE
e CONFIRM
). As mensagens PING
e PING-REQ
são centrais para o mecanismo de detecção de falhas do sistema baseado no SWIM, facilitando a troca constante de estados ao aproveitar a disseminação de informações neste processo. Quando ocorre uma mudança de estado, seja por meio de solicitações voluntárias ou detecção regular de falhas, o sistema utiliza mensagens BROADCAST
para disseminação aleatória dessas informações. Cada nó da rede mantém um número de encarnação, começando em zero, que só pode ser incrementado pelo próprio nó. Este número é crucial para gerenciar o estado do nó nas listas de membros locais de outros nós e serve como um meio de refutar suspeitas (SWIM+Inf.+Susp.)
de outros nós. Este design permite que o Gossipod obtenha gerenciamento de estado distribuído eficiente e resiliente e detecção de falhas em uma rede distribuída ou descentralizada, equilibrando as necessidades de informações atualizadas, resolução de conflitos e confiabilidade do sistema.
Por extensão, o Lifeguard oferece recursos de implementação adicionais que ainda não foram incorporados à versão atual do Gossipod, que são totalmente suportados pela lista de membros da Hashicorp. Pretendo integrar esses recursos em uma versão futura.
diagrama de sequência
participante N1 como Nó 1
participante N2 como Nó 2
participante N3 como Nó 3
participante Nx como Nó x (Aleatório)
Nota sobre N1, Nx: Sondagem e Disseminação de Informações via piggybacking
N1->>N2: PING (com informações adicionadas)
N2->>N1: ACK (com informações adicionadas)
N1->>N3: PING-REQ (para N2)
N3->>N2: PING
N2->>N3: ACK
N3->>N1: ACK (indireto)
Nota sobre N1, Nx: Disseminação de Mudança de Estado
N1->>Nx: TRANSMISSÃO (SAIR/ENTRAR/SUSPEITAR/CONFIRMAR)
Nx->>N2: PING (com mudanças de estado associadas)
N2->>N3: PING (com mudanças de estado associadas)
Nota sobre N1, Nx: Detecção e recuperação de falhas
N1->>N2: PING (sem resposta)
N1->>N3: PING-REQ (para N2)
N3->>N2: PING (sem resposta)
N3->>N1: NACK
N1->>Nx: TRANSMISSÃO (SUSPEITO N2)
Nota sobre N2: N2 recebe mensagem SUSPEITA
N2->>N2: Aumentar o número de encarnação
N2->>Nx: BROADCAST (ALIVE com novo número de encarnação)
alt N2 refuta com sucesso
Nx->>N1: PING (com ALIVE N2 nas costas)
Nota sobre N1: atualize o status N2 para ativo
senão N2 não refuta a tempo
N1->>Nx: BROADCAST (CONFIRME N2 como falhou)
fim
Para ver o Gossipod em ação, verifique o diretório ./examples
, que inclui várias demos. Abaixo você pode executar duas instâncias diferentes do gossipod especificando diferentes endereços de porta e nomes de nó
> 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 ? ;
Aqui está um exemplo básico de como usar o Gossipod em sua aplicação:
// 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 ;
}