etcd 源码分析之raft&config

博客围绕 etcd 相关内容,介绍了 raft 结构体和 config 结构体,config 是创建 raft 实例的参数。还阐述了 Candidate 和 Follower 的定时推进及选举流程,超时会成为 pre,获半数节点响应成选举者,获半数以上则成为 leader。
raft 结构体
type raft struct {
	id uint64	//集群中的标识

	Term uint64 	//当前任期
	Vote uint64		//当前任期投票给了谁

	readStates []ReadState
	// the log
	raftLog *raftLog  //本地log

	maxMsgSize         uint64 //单条消息最大字节
	maxUncommittedSize uint64   //最大为commit数量
	// TODO(tbg): rename to trk.
	prs tracker.ProgressTracker //其他节点的相关信息

	state StateType //当前节点在集群中的角色

	// isLearner is true if the local raft node is a learner.
	isLearner bool

	msgs []pb.Message //当前节点等待发送的消息

	// the leader id
	lead uint64 //leader节点的id
	// leadTransferee is id of the leader transfer target when its value is not zero.
	// Follow the procedure defined in raft thesis 3.10.
	leadTransferee uint64   //leader转移的目标

	pendingConfIndex uint64 //用于判断可否修改配置

	uncommittedSize uint64  //当前uncommit个数

	readOnly *readOnly

	// number of ticks since it reached last electionTimeout when it is leader
	// or candidate.
	// number of ticks since it reached last electionTimeout or received a
	// valid message from current leader when it is a follower.
	electionElapsed int //选举计时器的时间

	// number of ticks since it reached last heartbeatTimeout.  
	// only leader keeps heartbeatElapsed.
	heartbeatElapsed int //心跳计时器 

	checkQuorum bool
	preVote     bool

	heartbeatTimeout int //心跳超时时间
	electionTimeout  int //选举计时器超时时间
	// randomizedElectionTimeout is a random number between
	// [electiontimeout, 2 * electiontimeout - 1]. It gets reset
	// when raft changes its state to follower or candidate.
	randomizedElectionTimeout int //选举计时器的上限
	disableProposalForwarding bool
    //当前节点推进逻辑时钟的函数,leader和follower、candidate不同
	tick func() 
	step stepFunc
	//当前节点收到消息的处理函数leader、follower、candidate都不同

	logger Logger
}
config

config结构体,创建raft实例需要用到的参数

// Config contains the parameters to start a raft.
type Config struct {
	// 本地节点的id,不能为0
	ID uint64
	//集群中其他各节点的id
	peers []uint64
	// learners 节点不参与投票,直到追赶上leader节点
	learners []uint64
	// 用于初始化raft的electionTimeout,逻辑时钟推送多少次后触发选举
	ElectionTick int
	// 初始化,raft的heartbeatTimeout,leader节点触发心跳的时长
	HeartbeatTick int
	//日志存储
	Storage Storage
	// 当前已经应用的记录位置
	Applied uint64
	// 初始化maxMsgSize,每条消息的最大字节数
	MaxSizePerMsg uint64
	// 可以应用的已提交的条目大小
	MaxCommittedSizePerReady uint64
	// leader未提交的总字节大小
	MaxUncommittedEntriesSize uint64
	// 初始化maxInflight已经发出去且未收到应答的最大消息个数
	MaxInflightMsgs int

	// 是否开启checkQuorum机制
	CheckQuorum bool

	//是否开启preVote机制
	PreVote bool
	// 指定如何处理只读请求
	ReadOnlyOption ReadOnlyOption

	Logger Logger

	DisableProposalForwarding bool
}

reset

func (r *raft) reset(term uint64) {
    //重置
	if r.Term != term {
		r.Term = term
		r.Vote = None
	}
	//lead置空
	r.lead = None
    //重置选举和心跳计时器
	r.electionElapsed = 0
	r.heartbeatElapsed = 0
	//过期时间随机值
	r.resetRandomizedElectionTimeout()
    //清空
	r.abortLeaderTransfer()
    //重置
	r.prs.ResetVotes()
	r.prs.Visit(func(id uint64, pr *tracker.Progress) {
		*pr = tracker.Progress{
			Match:     0,
			Next:      r.raftLog.lastIndex() + 1,
			Inflights: tracker.NewInflights(r.prs.MaxInflight),
			IsLearner: pr.IsLearner,
		}
		if id == r.id {
			pr.Match = r.raftLog.lastIndex()
		}
	})

	r.pendingConfIndex = 0
	r.uncommittedSize = 0
	r.readOnly = newReadOnly(r.readOnly.option)
}

Candidate和Follower的定时推进electionElapsed并判断超时了没

// tickElection is run by followers and candidates after r.electionTimeout.
func (r *raft) tickElection() {
	r.electionElapsed++

	if r.promotable() && r.pastElectionTimeout() {
		r.electionElapsed = 0
		r.Step(pb.Message{From: r.id, Type: pb.MsgHup})
	}
}

如果超时调用becomePreCandidate()成为pre
获得半数节点响应调用Candidate()成为选举者
获得半数以上becomeLeader()成为leader了啊

<think>好的,我现在需要回答用户关于如何阅读etcd源码以及推荐相关资料的问题。首先,我得回忆一下自己了解的etcd相关知识,确保信息准确。 用户的问题分为两部分:如何进行etcd源码阅读,以及推荐的资料或网站。我需要先理清回答的结构,确保逻辑清晰。先从etcd的基本概念开始,说明其重要性,这样用户能明白为什么需要深入源码。 接下来是源码阅读的步骤。应该分阶段进行,比如先了解基础架构,再深入核心模块。需要提到Raft协议,因为etcd依赖它实现一致性,这部分是关键。然后是存储模块、网络通信和客户端交互等,这些都是etcd的核心组成部分。每个模块需要简要说明重点,帮助用户有的放矢。 在推荐资料方面,官方文档是首要推荐的,因为最权威。GitHub仓库的文档和代码示例很重要。书籍方面,可以推荐《云原生分布式存储基石:etcd深入解析》,这本书可能对理解内部机制有帮助。另外,博客和社区资源也是很好的补充,比如CNCF的案例研究和官方博客。论文方面,Raft的原始论文是必读的,用户可能需要了解理论基础。 还需要考虑用户可能的实践需求,比如调试和测试方法。建议使用Go的调试工具,运行测试案例,甚至参与开源项目,这样能加深理解。同时,注意事项部分要提醒用户先掌握Go语言和分布式系统基础,避免直接陷入代码细节而无法理解整体结构。 现在要检查是否有遗漏点。比如,是否提到了工具推荐?比如Delve调试器,或者如何运行测试。可能还需要强调从入口开始,比如main函数,或者关键接口,这样用户有切入点。 另外,资料推荐部分是否有合适的链接?虽然不能提供超链接,但可以给出名称,用户自行搜索。比如CNCF网站、GitHub地址等。确保推荐的资源是当前有效且被广泛认可的。 最后,整个回答需要保持口语化,避免使用过于技术化的术语,但又要准确。结构分点说明,使用标题和分段,让用户容易阅读。同时,注意使用用户要求的格式,比如数学公式的正确表示,但这个问题中可能涉及较少,主要是在算法部分,如果有提到的话需要注意。 总结一下,回答的结构应该是:简介etcd源码阅读步骤(分阶段),推荐资料(分类型),注意事项和实践建议。确保每个部分都简明扼要,信息准确,帮助用户系统地进行源码学习。</think>etcd 是一款高可用的分布式键值存储系统,广泛用于 Kubernetes 等服务协调场景。阅读其源码是理解其分布式一致性、存储引擎和网络通信机制的重要途径。以下是源码阅读的分步指南和推荐资源: --- ### **一、源码阅读步骤** #### 1. **前置知识储备** - **掌握 Go 语言**:etcd 使用 Go 实现,需熟悉 Goroutine、Channel 等并发模型。 - **理解分布式系统基础**:如 CAP 定理、一致性协议(Raft)、分布式锁等。 - **熟悉 etcd 核心功能**:通过官方文档了解其 API、租约(Lease)、Watch 机制等。 #### 2. **从核心模块切入** - **Raft 协议实现**(`etcd/raft` 目录) 核心代码在 `raft/raft.go`,重点关注 Leader 选举、日志复制和状态机应用逻辑。 ```go // 示例:Raft 状态机处理日志条目 func (r *raft) Step(m pb.Message) error { switch m.Type { case pb.MsgProp: // 处理提案 case pb.MsgApp: // 处理日志追加 } } ``` - **存储引擎**(`etcd/server/storage` 目录) - 内存索引(BoltDB 的键值存储)。 - 数据持久化(WAL 日志和快照机制)。 - **网络通信**(`etcd/clientv3` 和 `etcd/etcdserver/api`) 分析 gRPC 接口定义(如 `rpc.proto`)和客户端-服务端交互流程。 #### 3. **调试与验证** - **运行单节点集群**:通过 `etcd --config-file=etcd.conf.yml` 启动本地调试。 - **单元测试**:执行 `go test -v ./raft/...` 验证 Raft 模块逻辑。 - **使用 Delve 调试**:断点跟踪关键流程(如 Leader 选举)。 --- ### **二、推荐资料与工具** #### 1. **官方资源** - [etcd 官方文档](https://etcd.io/docs/):功能详解、API 定义和配置指南。 - [GitHub 仓库](https://github.com/etcd-io/etcd):直接阅读源码和代码注释。 - [Raft 论文](https://raft.github.io/raft.pdf):理解 etcd 依赖的一致性协议。 #### 2. **书籍与博客** - 《**云原生分布式存储基石:etcd 深入解析**》:详细分析 etcd 架构与源码。 - [etcd 官方博客](https://etcd.io/blog/):版本更新解读和性能优化案例。 - [CNCF 案例研究](https://www.cncf.io/case-studies/):了解 etcd 在生产环境的应用场景。 #### 3. **辅助工具** - **etcdctl**:通过命令行操作 etcd,观察数据变化(如 `etcdctl watch /key`)。 - **WAL 日志分析工具**:直接解析二进制日志,验证数据持久化流程。 --- ### **三、注意事项** 1. **避免过早深入细节**:先梳理模块交互关系(如 Raft 模块如何驱动存储引擎)。 2. **关注 Issue 和 PR**:GitHub 的 Issue 列表和合并的 PR 可揭示设计决策。 3. **动手实践**:修改源码添加日志输出,或实现一个简单的 Raft 状态机。 --- ### **四、学习路径示例** 1. 从 `main.go` 入口分析服务启动流程。 2. 追踪一个写请求(如 `Put`)的完整生命周期:经 gRPC 接口 → Raft 提案 → 存储落地。 3. 研究故障恢复机制:节点重启后如何通过 WAL 日志恢复状态。 通过以上方法,可逐步掌握 etcd 的设计精髓,并应用于分布式系统开发或性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值