gossipod
1.0.0
用 Rust 编写的异步可扩展弱一致感染式进程组成员协议 (SWIM) 实现。
警告
免责声明:该项目正在进行中,尚未准备好投入生产。代码库可能包含错误或不完整的功能。谨慎使用。欢迎反馈和贡献,谢谢!
io_uring
运行时(SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
并扩展以包含 Hashicorp Research 的 Lifeguard 功能Gossipod 使用 3 种类型的消息: PING
、 PING-REQ
和BROADCAST
(其中包括JOIN
、 LEAVE
、 SUSPECT
、 ALIVE
和CONFIRM
子类型)。 PING
和PING-REQ
消息是系统基于 SWIM 的故障检测机制的核心,通过在此过程中附带信息传播来促进持续的状态交换。当状态发生变化时,无论是通过自愿请求还是定期故障检测,系统都会使用BROADCAST
消息随机传播此信息。网络中的每个节点都维护一个化身号,从零开始,只能由节点本身递增。该数字对于管理其他节点本地成员列表中的节点状态至关重要,并可作为反驳其他节点怀疑(SWIM+Inf.+Susp.)
的手段。这种设计使 Gossipod 能够在分布式或去中心化网络中实现高效且有弹性的分布式状态管理和故障检测,平衡对最新信息、冲突解决和系统可靠性的需求。
通过扩展,Lifeguard 提供了尚未合并到当前版本的 Gossipod 中的附加实现功能,这些功能得到 Hashicorp 成员列表的完全支持。我计划在未来的版本中集成这些功能。
序列图
参与者 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:广播(ALIVE,具有新的化身编号)
alt N2 成功反驳
Nx->>N1:PING(搭载 ALIVE N2)
关于 N1 的注释:将 N2 状态更新为存活
否则N2没有及时反驳
N1->>Nx:广播(确认 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 ;
}