การใช้งานโพรเซสกลุ่มสมาชิกโปรโตคอล (SWIM) แบบอะซิงโครนัสที่ปรับขนาดได้ไม่สอดคล้องกันเล็กน้อยซึ่งเขียนด้วยภาษา Rust
คำเตือน
ข้อสงวนสิทธิ์: โครงการนี้อยู่ในระหว่างดำเนินการและยังไม่พร้อมสำหรับการผลิต Codebase อาจมีจุดบกพร่องหรือคุณสมบัติที่ไม่สมบูรณ์ ใช้ด้วยความระมัดระวัง ข้อเสนอแนะและการมีส่วนร่วมยินดีต้อนรับขอบคุณ!.
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 ซึ่งอำนวยความสะดวกในการแลกเปลี่ยนสถานะอย่างต่อเนื่องโดยการเผยแพร่ข้อมูลแบบ piggybacking ในกระบวนการนี้ เมื่อมีการเปลี่ยนแปลงสถานะเกิดขึ้น ไม่ว่าจะผ่านการร้องขอโดยสมัครใจหรือการตรวจจับความล้มเหลวตามปกติ ระบบจะใช้ข้อความ BROADCAST
เพื่อเผยแพร่ข้อมูลนี้แบบสุ่ม แต่ละโหนดในเครือข่ายจะรักษาหมายเลขการเกิดใหม่ โดยเริ่มต้นที่ศูนย์ ซึ่งสามารถเพิ่มขึ้นได้โดยตัวโหนดเองเท่านั้น หมายเลขนี้มีความสำคัญอย่างยิ่งต่อการจัดการสถานะของโหนดในรายการสมาชิกท้องถิ่นของโหนดอื่น และทำหน้าที่เป็นวิธีการหักล้างข้อสงสัย (SWIM+Inf.+Susp.)
จากโหนดอื่น การออกแบบนี้ช่วยให้ Gossipod บรรลุการจัดการสถานะแบบกระจายที่มีประสิทธิภาพและยืดหยุ่นและการตรวจจับความล้มเหลวในเครือข่ายแบบกระจายหรือแบบกระจายอำนาจ โดยปรับสมดุลความต้องการข้อมูลที่ทันสมัย การแก้ไขข้อขัดแย้ง และความน่าเชื่อถือของระบบ
ตามส่วนขยาย Lifeguard นำเสนอคุณสมบัติการใช้งานเพิ่มเติมที่ยังไม่ได้รวมเข้ากับ Gossipod เวอร์ชันปัจจุบัน ซึ่งได้รับการสนับสนุนอย่างเต็มที่จากรายชื่อสมาชิกของ Hashicorp ฉันวางแผนที่จะรวมคุณสมบัติเหล่านี้ไว้ในรุ่นต่อๆ ไป
ลำดับไดอะแกรม
ผู้เข้าร่วม N1 เป็นโหนด 1
ผู้เข้าร่วม N2 เป็นโหนด 2
ผู้เข้าร่วม N3 เป็นโหนด 3
ผู้เข้าร่วม Nx เป็น Node x (สุ่ม)
หมายเหตุสำหรับ N1,Nx: การซักถามและการเผยแพร่ข้อมูลผ่านการแบกหลัง
N1->>N2: PING (พร้อมข้อมูลแบบ piggybacked)
N2->>N1: ACK (พร้อมข้อมูลแบบ piggybacked)
N1->>N3: PING-REQ (สำหรับ N2)
N3->>N2: ปิง
N2->>N3: อ๊าก
N3->>N1: อ๊าก (ทางอ้อม)
หมายเหตุเกี่ยวกับ N1,Nx: การเผยแพร่การเปลี่ยนแปลงสถานะ
N1->>Nx: ออกอากาศ (ออก/เข้าร่วม/สงสัย/ยืนยัน)
Nx->>N2: PING (พร้อมการเปลี่ยนแปลงสถานะแบบ piggybacked)
N2->>N3: PING (พร้อมการเปลี่ยนแปลงสถานะแบบ piggybacked)
หมายเหตุเกี่ยวกับ N1,Nx: การตรวจจับและการกู้คืนความล้มเหลว
N1->>N2: PING (ไม่มีการตอบกลับ)
N1->>N3: PING-REQ (สำหรับ N2)
N3->>N2: PING (ไม่มีการตอบกลับ)
N3->>N1: ไม่มี
N1->>Nx: การออกอากาศ (ผู้ต้องสงสัย N2)
หมายเหตุเกี่ยวกับ N2: N2 ได้รับข้อความที่น่าสงสัย
N2->>N2: เพิ่มหมายเลขชาติ
N2->>Nx: BROADCAST (มีชีวิตอยู่พร้อมกับหมายเลขชาติใหม่)
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 ;
}