开源代码memberlist源码分析

本文微信公众号链接:https://mp.weixin.qq.com/s/abY24PhBgNDJgh5m9Taq4w

 

memberlist是go语言开发的,基于Gossip协议来传播消息,用来管理分布式集群内节点发现、 节点失效探测、节点列表的软件包。

 

对于Gossip协议之前写过一篇文章: Gossip协议简介---病毒感染模型的p2p算法

 

源码地址 https://github.com/hashicorp/memberlist

 

为了学习memberlist的原理设计,遵循个人从低版本代码研究的习惯。这里一提交号fe04265为分析。

 

再次备注:学习早期版本,只是为了学习开源代码的设计原理,底层工作原理。以及版本在进化过程中,源码的改进。

 

源码目录:

 

整体代码风格像面向对象c的风格。模块划分刚好以文件名为划分

1、broadcast.go :广播模块

2、net.go:传输与协议处理模块

3、state.go:节点状态管理模块

4、memberlist.go:主模块

 

 

github.com/hashicorp/memberlist/memberlist.go

Memberlist

在结构体Memberlist中,成员变量也是按照功能不同分隔

type Memberlist struct {
config *Config  //配置
shutdown bool  //本地服务关闭的标志位
leave bool  //本节点退出的标志位

udpListener *net.UDPConn
tcpListener *net.TCPListener
//udp和tcp的链接管理。对应的net.go,传输与协议管理

sequenceNum uint32 // Local sequence number
//本地seq num
incarnation uint32 // Local incarnation number
//本地inc num

nodeLock sync.RWMutex
nodes []*NodeState // Known nodes
nodeMap map[string]*NodeState // Maps Addr.String() -> NodeState
//node管理以及state管理对应state.go

tickerLock sync.Mutex
tickers []*time.Ticker
stopTick chan struct{}
probeIndex int

ackLock sync.Mutex
ackHandlers map[uint32]*ackHandler

broadcastLock sync.Mutex
bcQueue broadcasts
//broadcast管理,对应broadcast.go
}

 

 

Config

在config中,前面是一些基本的配置项,注释也都有解释。

type Config struct {
Name string // Node name (FQDN)
BindAddr string // Binding address
UDPPort int // UDP port to listen on
TCPPort int // TCP port to listen on
TCPTimeout time.Duration // TCP timeout
IndirectChecks int // Number of indirect checks to use
RetransmitMult int // Retransmits = RetransmitMult * log(N+1)
SuspicionMult int // Suspicion time = SuspcicionMult * log(N+1) * Interval
PushPullInterval time.Duration // How often we do a Push/Pull update
RTT time.Duration // 99% precentile of round-trip-time
ProbeInterval time.Duration // Failure probing interval length

GossipNodes int // Number of nodes to gossip to per GossipInterval
GossipInterval time.Duration // Gossip interval for non-piggyback messages (only if GossipNodes > 0)

JoinCh chan<- *Node
LeaveCh chan<- *Node
}

 

在最后两行

JoinCh:这个是对外提供的一个接口,用于做新增node的时候,作为外部注册通知处理

LeaveCh:这个是对外提供的一个接口,用于做对去除一个node的时候,做为外部注册通知处理

这两个chan,在更早的版本中是在结构体memberlist中。后来移到了config中。

 

开始进入流程

Create

// Create will start memberlist and create a new gossip pool, but
// will not connect to an existing node. This should only be used
// for the first node in the cluster.
func Create(conf *Config) (*Memberlist, error) {
  m, err := newMemberlist(conf)
//newMemberlist,中开启了tcplisten和udplisten
  if err != nil {
  return nil, err
  }
  if err := m.setAlive(); err != nil {
  m.Shutdown()
  return nil, err
  }
  m.schedule()
//schedule中开启了三个服务:probe、pushpull、gossip
  return m, nil
}
这里面有两个重要步骤
1、newMemberlist
2、m.schedule

 

newMemberlist
// newMemberlist creates the network listeners.
// Does not schedule exeuction of background maintenence.
func newMemberlist(conf *Config) (*Memberlist, error) {
  
    tcpAddr := fmt.Sprintf("%s:%d", conf.BindAddr, conf.TCPPort)
    tcpLn, err := net.Listen("tcp", tcpAddr)
    if err != nil {
        return nil, fmt.Errorf("Failed to start TCP listener. Err: %s", err)
    }
//上面是创建tcplisten

    udpAddr := fmt.Sprintf("%s:%d", conf.BindAddr, conf.UDPPort)
    udpLn, err := net.ListenPacket("udp", udpAddr)
    if err != nil {
        tcpLn.Close()
        return nil, fmt.Errorf("Failed to start UDP listener. Err: %s", err)
    }
//上面是创建udplisten


    m := &Memberlist{config: conf,
        udpListener: udpLn.(*net.UDPConn),
        tcpListener: tcpLn.(*net.TCPListener),
        nodeMap: make(map[string]*NodeState),
        stopTick: make(chan struct{}, 32),
        ackHandlers: make(map[uint32]*ackHandler),
      }//构建Memberlist实例

    go m.tcpListen() //开启tcp服务
    go m.udpListen() //开启udp服务
    return m, nil
}
在newMemberlist中,最主要的动作就是开启了tcp服务和udp服务
那么就看看net服务(tcp和udp)
github.com/hashicorp/memberlist/net.go
tcp
tcplisten
// tcpListen listens for and handles incoming connections
func (m *Memberlist) tcpListen() {
    for {
        //tcp accept
        conn, err := m.tcpListener.AcceptTCP()
        if err != nil {
            if m.shutdown {
                break
            }
            log.Printf("[ERR] Error accepting TCP connection: %s", err)
            continue
        }
        //每个链接都有一个处理
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值