ETCD 源码学习--Raft 协议实现的文件说明及 Raft 数据结构解析(三)
在 ETCD 源码学习过程,不会讲解太多的源码知识,只讲解相关的实现机制,需要关注源码细节的朋友可以自行根据文章中的提示,找到相关源码进行学习。
主要文件说明
在ETCD中,Raft协议实现的源码主要在 etcd/raft 目录下
1.raft.go 实现Raft协议的主要逻辑。
2.log.go 用于维护日志记录,其中包括两部分 log,持久化 log 和 未持久化 log
3.log_unstable.go 用于维护未持久化 log
4.stable.go 定义存储接口协议,同时实现 MemoryStorage 存储实例
5.node.go & rawnode.go 共同实现 Raf t节点,一个 node 相当于一个 raft 节点。主要做消息转发功能,当有请求时,会调用底层 raft 协议处理,当底层 raft 处理完之后,会将消息封装,然后传递给上层模块处理。
6.tracker/inflights.go 用于维护已发送,但未得到对应节点响应的消息日志记录。
7.tracker/processs.go 用于维护单个节点状态,比如节点活跃状态、已提交的 Index、已匹配的 Index 等。
8. tracker/tracker.go 用于管理所有节点的状态。
9. quorum 目录下的文件,主要用于实现 quorum 机制(过半机制)
10. confchange 目录下的文件,是用于实现在接收的状态机配置变更时,如何实现当前节点的配置变更。
11.raftpb 目录下的文件是消息协议文件(protobuf)
Raft 协议的数据结构
type raft struct {
id uint64
Term uint64
Vote uint64
readStates []ReadState
raftLog *raftLog
maxMsgSize uint64
maxUncommittedSize uint64
prs tracker.ProgressTracker
state StateType
isLearner bool
msgs []pb.Message
lead uint64
leadTransferee uint64
pendingConfIndex uint64
uncommittedSize uint64
readOnly *readOnly
electionElapsed int
heartbeatElapsed int
checkQuorum bool
preVote bool
heartbeatTimeout int
electionTimeout int
randomizedElectionTimeout int
disableProposalForwarding bool
tick func()
step stepFunc
logger Logger
}
1.节点状态参数
id:当前节点 ID
Term:当前节点任期
Vote:当前节点的选票(投给了谁做我 Leader )
state:节点状态 (Leader/Follower/Candidate/...)
lead:Leader ID
2.计时器参数
electionTimeout:选举超时时间。
randomizedElectionTimeout:随机选举超时时间,每个节点的选举超时时间不同, randomizedElectionTimeout = electionElapsed+随机数。具体计算参考 resetRandomizedElectionTimeout() 函数。
electionElapsed:选举计数器 ,在 Follower/Candidate 中,如果在 electionElapsed >= randomizedElectionTimeout, 会发起一轮选举。如果在 Leader 状态,那么当 electionElapsed > electionTimeout,Leader 会发起一次自我检查,主要目的是判断自身是否能继续维持 Leader 状态,如果不能,切换成 Follower,并发起一轮选举。
heartbeatElapsed:心跳计数器,在 Leader 节点运行,Leader 节点会定时向 Follower 发生心跳包,Follower 收到 心跳包会重置 electionElapsed,避免 Follower 发起选举。
heartbeatTimeout:心跳超时时间 当 heartbeatElapsed > heartbeatTimeout,向所有 Follower 发送心跳包
tick:逻辑计数器推进函数, 当 Leader状态时 为 tickHeartbeat。其他状态为 tickElection。
3.网络分区处理
CheckQuorum:当为 true 时, electionElapsed > electionTimeout,Leader 会进行自我检查,判断是否能继续维持 Leader 状态,如果发现连接到的节点数没有超过半数,则主动切换成 Follower,这样在网络分区中,旧的 Leader 节点可以很快指定自己过期,减少 client 连接 Leader 节点的等待时间
preVote:当为true时,选举过程会多一个预选举过程,同时会多一个 preCandidate 状态。主要作用是在正式发起选举之前,判断是否有超过半数的节点能参与选举。如果没有,放弃发起选举,这样在网络分区的情况下,可以避免脑裂问题。
4.raft协议 消息处理函数 step,主要用于处理raft的各种消息,其中包括三种模式
stepLeader: 当节点状态为 Leader 时,step 设置为该函数 (becomeLeader)
stepFollower:当节点状态为 Follower 时,step 设置为该函数 (becomeFollower)
stepCandidate:当节点状态为 Candidate 时,step 设置为该函数 (becomeCandidate)
5.集群节点状态维护
prs:该参数会维护集群中所有节点的信息,主要包括节点的活跃状态,日志复制情况等。
6.消息日志
raftLog:维护本地节点的消息日志,其中包括两个部分,一是已持久化(stable)的日志,二是未持久化(unstable)的数据
msgs:缓冲待发送给其他节点的消息日志。
在Leader节点中,会将日志消息先保存到 raftLog 中(unstable),然后 raft 会将 raftLog 中的日志,根据 prs 记录的日志同步情况,将未同步的数据,同步到对应的节点(发送到 msgs 中缓存)。
PS:欢迎纠正