Асинхронная масштабируемая слабосогласованная реализация протокола членства в группах процессов в стиле заражения (SWIM), написанная на Rust.
Предупреждение
Отказ от ответственности: этот проект находится в стадии разработки и еще не готов к производству. Кодовая база может содержать ошибки или неполные функции. Используйте с осторожностью. Обратная связь и вклад приветствуются, спасибо!.
io_uring
через Tokio (SWIM:Basic)
+ (SWIM+Inf.)
+ (SWIM+Inf.+Susp.)
и расширить, включив в него функции Lifeguard от Hashicorp Research. 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: ПОДТВЕРЖДЕНИЕ
N3->>N1: подтверждение (косвенное)
Примечание по 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: НЕТ
N1->>Nx: ВЕЩАНИЕ (ПОДОЗРЕВАЕМЫЙ N2)
Примечание по N2: N2 получает сообщение ПОДОЗРЕВАНИЕ.
N2->>N2: Увеличение номера воплощения
N2->>Nx: ВЕЩАНИЕ (ЖИВОЕ с новым номером воплощения)
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 ;
}