当前位置:网站首页>ETCD数据库源码分析——从raftNode的start函数说起

ETCD数据库源码分析——从raftNode的start函数说起

2022-07-07 01:39:00 肥叔菌

在这里插入图片描述

如上图所示,raftNode是真正操纵ETCD RAFT API的模块,充当etcd-raft模块与上层模块之间交互的桥梁,其定义了如下成员。其中msgSnapC通道用于接收和发送快照、applyc通道用于发送待应用的Entry记录、readStateC用于向上层模块发送ReadState、ticker用于向raft模块发送定时脉冲tick、td用于检测发往同一节点的两次心跳消息是否超时。raftNodeConfig后续再说,该篇主要说明ticker模块。

type raftNode struct {
    
	lg *zap.Logger
	tickMu *sync.Mutex
	raftNodeConfig	
	msgSnapC chan raftpb.Message // a chan to send/receive snapshot 
	applyc chan toApply // a chan to send out apply 
	readStateC chan raft.ReadState // a chan to send out readState 
	ticker *time.Ticker // utility 
	td *contention.TimeoutDetector // contention detectors for raft heartbeat message
	stopped chan struct{
    }
	done    chan struct{
    }
}

初始化raftNode结构体的函数是newRaftNode,raftNodeConfig包含了已经初始化的网络transport、预写日志Storage、raftStorage以及最重要的raft模块,这些模块提供相应的接口给raftnode使用以协助完成raft log发送、持久化、多数复制等功能。

func newRaftNode(cfg raftNodeConfig) *raftNode {
        
	raft.SetLogger(lg) // 初始化logger(略)
	r := &raftNode{
     lg: cfg.lg, tickMu: new(sync.Mutex),
		raftNodeConfig: cfg, td: contention.NewTimeoutDetector(2 * cfg.heartbeat), // set up contention detectors for raft heartbeat message. expect to send a heartbeat within 2 heartbeat intervals.
		readStateC: make(chan raft.ReadState, 1),
		msgSnapC:   make(chan raftpb.Message, maxInFlightMsgSnap),
		applyc:     make(chan toApply),
		stopped:    make(chan struct{
    }), done:       make(chan struct{
    }),
	}
	// 这里是重点
	if r.heartbeat == 0 {
     r.ticker = &time.Ticker{
    }  // 如果heartbeat为零,则使用默认&time.Ticker{}
	} else {
     r.ticker = time.NewTicker(r.heartbeat) } // 否则,需要设定时间间隔为r.heartbeat
	return r
}

start函数会启动一个协程运行主要的业务逻辑,这里我们会看到如果定时器超时时,select会检测到该通道,调用raftNode接口的tick函数。该tick函数会获取tickMu锁,然后调用Node接口提供的Tick函数,也就是图中的raft.Node提供的Tick函数。

func (r *raftNode) start(rh *raftReadyHandler) {
    
	internalTimeout := time.Second
	go func() {
    
		defer r.onStop()
		islead := false
		for {
    
			select {
    
			case <-r.ticker.C:
				r.tick()
				
// raft.Node does not have locks in Raft package
func (r *raftNode) tick() {
    
	r.tickMu.Lock()
	r.Tick()
	r.tickMu.Unlock()
}				

raft.Node提供的Tick函数会向n.tickc通道中写入struct{}{},而在raft.Node中会有协程执行run函数,如图中raft.Node的run协程所示,其会执行监听n.tickc通道的代码,然后执行n.rn.Tick()。而这里n.rn.Tick()执行的是rawnode所包含成员raft结构体的Tick成员函数,该函数会根据raft角色执行不同的tick函数:tickElection或tickHeartbeat。
在这里插入图片描述

// Tick advances the internal logical clock by a single tick.
func (rn *RawNode) Tick() {
    
	rn.raft.tick()
}
原网站

版权声明
本文为[肥叔菌]所创,转载请带上原文链接,感谢
https://feishujun.blog.csdn.net/article/details/125608972