前面三篇我们分别介绍了Raft的API、网络层、存储层,从这一篇开始我们来看Raft的Leader、Candidate、Follower
实现。
r.runLeader逻辑
事务提交的过程:接着我们一点点分析,
发送请求,Apply方法
1 | // Apply |
runLeader()
接着我们看下leader初始化的时候会干些啥,重点看下初始化的后台处理协程。
1 | func (r *Raft) runLeader() { |
Leader消费r.applyCh
将客户端的写凑成一批,
1 | case newLog := <-r.applyCh: |
接着看看dispatchLogs逻辑
加r.leaderState.inflight list, 表示需要处理的applyLogs
日志持久化 r.logs.StoreLogs(logs),类比mysql 持久化redo log
将自己的log index往前,并且通知commitCh
持久化lastIndex,r.setLastLog(lastIndex, term)
通知每个replication新Log – asyncNotifyCh(f.triggerCh)
接着就是上面的初始化的时候干的事情了,给每个channel发消息
想想哪些是异步的?为啥要异步处理呢?
搞清楚重点
下面的observe
是干啥的?
1 | r.observe(LeaderObservation{Leader: leader}) |
client 写请求 :api.go Apply方法,返回一个ApplyFuture对象,包含req、response、error
1 |
–> 发消息 append entity –> 多数派的回复 – > 客户端返回 –> 应用FSM(另一个流程)–> 通知其他节点可以应用 –
client返回的标准是啥?日志多数派 or Master apply成功(不可能)
认真琢磨其中的优化
问题记录
1、chan里面只有一个元素,并且不能并发调用。下面代码的理解,到底是怎么避免并发调用的?还有别的实现吗?这个实现是不是有点trick?
1 | func overrideNotifyBool(ch chan bool, v bool) { |
2、leaderLoop
这个里面全是异步的chan,代码规划的非常好,很值得学习