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
메시지를 사용합니다. 네트워크의 각 노드는 0부터 시작하는 구현 번호를 유지하며, 이는 노드 자체에 의해서만 증가될 수 있습니다. 이 숫자는 다른 노드의 로컬 멤버십 목록에서 해당 노드의 상태를 관리하는 데 중요하며 다른 노드의 의심 (SWIM+Inf.+Susp.)
을 반박하는 수단으로 사용됩니다. 이 설계를 통해 Gossipod는 분산 또는 분산 네트워크에서 효율적이고 탄력적인 분산 상태 관리 및 오류 감지를 달성하여 최신 정보, 충돌 해결 및 시스템 신뢰성에 대한 요구 사항의 균형을 맞출 수 있습니다.
확장을 통해 Lifeguard는 Hashicorp 회원 목록에서 완벽하게 지원되는 Gossipod의 현재 버전에 아직 통합되지 않은 추가 구현 기능을 제공합니다. 향후 릴리스에 이러한 기능을 통합할 계획입니다.
시퀀스 다이어그램
참가자 N1을 노드 1로 사용
참가자 N2를 노드 2로 사용
참가자 N3을 노드 3으로 사용
참가자 Nx를 노드 x로(임의)
N1,Nx에 대한 참고사항: 피기백을 통한 조사 및 정보 전파
N1->>N2: PING(피기백 정보 포함)
N2->>N1: ACK(피기백 정보 포함)
N1->>N3: PING-REQ(N2의 경우)
N3->>N2: 핑
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: BROADCAST (새로운 화신번호로 ALIVE)
alt N2가 성공적으로 반박했습니다.
Nx->>N1: PING(피기백된 ALIVE N2 사용)
N1에 대한 참고사항: N2 상태를 활성으로 업데이트
그렇지 않으면 N2가 제때에 반박하지 않습니다.
N1->>Nx: BROADCAST (N2를 실패로 확인)
끝
Gossipod의 실제 작동 모습을 보려면 다양한 데모가 포함된 ./examples
디렉터리를 확인하세요. 아래에서는 서로 다른 포트 주소와 노드 이름을 지정하는 두 개의 서로 다른 gossipod 인스턴스를 실행할 수 있습니다.
> 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 ;
}