memberlist 是一个 Go 库,它使用基于 gossip 的协议来管理集群成员和成员故障检测。 这种库的用例影响深远:所有分布式系统都需要成员资格,而 memberlist 是管理集群成员资格和节点故障检测的可重用解决方案。 memberlist 最终是一致的,但平均而言收敛速度很快。它的收敛速度可以通过协议上的各种旋钮进行大量调整。通过尝试通过多条路由与潜在的死节点进行通信,检测到节点故障并部分容忍网络分区。
Memberlist 使用起来非常简单。一个例子如下所示:
/* Create the initial memberlist from a safe configuration.
Please reference the godoc for other default config types.
http://godoc.org/github.com/hashicorp/memberlist#Config
*/
list, err := memberlist.Create(memberlist.DefaultLocalConfig())
if err != nil {
panic("Failed to create memberlist: " + err.Error())
}
// Join an existing cluster by specifying at least one known member.
n, err := list.Join([]string{"1.2.3.4"})
if err != nil {
panic("Failed to join cluster: " + err.Error())
}
// Ask for members of the cluster
for _, member := range list.Members() {
fmt.Printf("Member: %s %s\n", member.Name, member.Addr)
}
// Continue doing whatever you need, memberlist will maintain membership
// information in the background. Delegates can be used for receiving
// events when members join or leave.
memberlist 最困难的部分是配置它,因为它有许多可用的旋钮来调整状态传播延迟和收敛时间。 Memberlist 提供了一个默认配置,它提供了一个良好的起点,但在谨慎方面会犯错误,选择为更高的收敛性而优化的值,但会以更高的带宽使用为代价。 For complete documentation, see the associated Godoc.
UDP
收包、PING
TCP
PING、状态同步【push/pull】
----------
pull、push
ping
gossip UDP定时将Broadcast发送到不同的节点
Suspect Suspicion--->Broadcast SuspectMsg [一旦收到来通节点的质疑消息数大于上限后] ---> Broadcast DeadMsg
ProbeNode Ping--->IndrectPing--->TCPPing--->Suspect
会定时同步消息
类似,多条消息会合并
// a 1,2,3,4
// 1 --> b
// 2 --> c
// 3 --> d
Join是建立的TCP链接
以AliveMsg为例
当某节点Create以后,就调用了 AliveNode ,将alive消息放入到了Btree等待广播
加入集群
等待Gossip超时,将信息,随机发往某个节点
也就是某个节点的alive信息会一直在集群中传输,最早将这个信息放进来的是这个节点本身;另外当自己收到质疑消息,也会发送存活消息
c:
AliveNode |<-- Gossip() 定时广播到随机的机器
DeadNode ------> Btree ---| 在主动发包到某个节点的过程中,填充额外的信息
EncodeBroadcast |<-- encodeAndSendMsg <-- Ping 、Gossip、ProbeNode、Probe 、ProbeNodeByAddr
Refute
s:
<------
//_ = m.Transport.(*NetTransport).RecIngestPacket //往通道发消息
//_ = m.Transport.(*NetTransport).UdpListen // 往通道发消息
PacketListen <-----
HandleIngestPacket
HandleCommand
handlePing
handleIndirectPing
AliveMsg:
AliveNode
Refute 都是将自己还活着的消息存入到BTree中
等待handlePing、handleIndirectPing、ProbeNode调用; 将BTree中的数据发送到一台指定的机器
sendAndReceiveState()
--->
buf = PushPullMsg (1 byte) + PushPullHeader + localNodes + userData
sendBuf = CompressMsg (1 byte) + buf
sendBuf = EncryptMsg (1 byte) + messageLength (4 byte) + sendBuf + stream_Label (optional)
另外:如果有Label
HasLabelMsg (1 byte) + LabelSize (1 byte) + LabelData (LabelSize byte) + sendBuf
UDP
HasLabelMsg (1 byte) + LabelSize (1 byte) + LabelData (LabelSize byte) + sendBuf
-----> sendBuf 通过 私钥、label 解密
buf = HasCrcMsg (1 byte) + crcSum(4 byte) + msgType(1 byte) + msg
msg:
CompoundMsg + len(msgs) uint8 + 每个消息的长度uint16 + 每个消息
streamLabel 只有在 HasLabelMsg 类型下有
PingMsg
PushPullMsg
- join 时触发
UserMsg
周期性的向每个节点发送 pingMsg
a (ProbeNode)--->1、PingMsg---> b(handlePing) --->3、IndirectPingReq ---> c(handleIndirectPing)
↑ ↓ |->3、IndirectPingReq ---> d(handleIndirectPing)
↑ ↓ |->3、IndirectPingReq ---> d(handleIndirectPing)
↑<---- 2、AckRespMsg <---↓ |->3、IndirectPingReq ---> e(handleIndirectPing) --->3.1、PingMsg---> b(handlePing)
↓---->1、收到ack ↑<- AckRespMsg <-↓
a(handleNack) <----------------- ↓---->2、没有收到ack,向A返回NACK消息
--->SendPingAndWaitForAck---> true return \ false awarenessDelta+?
--->SuspectNode
UserMsg:
c:
SendUserMsg
SendToAddress
SendBestEffort
SendToUDP
以及配置了 m.Config.Delegate.GetBroadcasts 任何一个可以广播的行为
程序本身没有发送UserMsg
1、StateDead与StateLeft的区别
StateLeft: 将广播一个Leave消息,但不会关闭listeners,这意味着该节点将继续参与gossip和状态更新。
2、广播出去的包,server怎么处理
每个UDP链接都有一个listen函数 UdpListen ,用于处理接收到的包
3、BTree
```
tq.Max
tq.Len
tq.Delete
tq.AscendRange
tq.Ascend 按照升序遍历
tq.Descend 按照将序遍历
```