简介
dledger是openmessaging的一个组件, raft算法实现,用于分布式日志,本系列分析dledger如何实现raft概念,以及dledger在rocketmq的应用
本系列使用dledger v0.40
本文分析dledger的心跳
关键词
Raft
Openmessaging
心跳/选主
参考资料
In Search of an Understandable Consensus Algorithm raft论文简版
心跳
选主是dledger的关键特性,主节点承担处理Client请求,复制日志到跟随者节点,dledger通过心跳发起选举。
关键属性
本节介绍关键属性,为下面分析准备
- term 任期/轮次
任期: 新的选举开始到下一个选举开始,左闭右开的时间区间,包括选举期和工作期两部分
轮次:任期内选举的轮次,任期内可多轮不提升term选举
- needIncreaseTermImmediately
需要立即增加term的设置,只提升任期,但不对其他节点发起投票请求,用于term落后的节点
- nextTimeToRequestVote
下次请求投票时间
System.currentTimeMillis() + minVoteIntervalMs + random.nextInt(maxVoteIntervalMs - minVoteIntervalMs)
dledger根据情况有不同的设定,下次发起选举时间的差异正是选举的关键
- currVotedFor
本节点投票给谁了,该值提升term时设置为null;该值设置地方只有一处,处理投票handlerVote,即,不提升term节点,投票给谁不会改变
- currTerm
节点当前所处任期
- ledgerEndTerm/ledgerEndIndex
已写入日志的term;已写入日志的索引
两个数据是节点成为leader的关键数据,作为leader已写入日志的term/已写入日志的索引越多越好
状态维护
上图节点状态维护模型
ShutdownAbleThread 线程提供定时执行工作;等待执行两个特性
StateMaintainer 继承ShutdownAbleThread, 获得定时执行能力,定时执行维护状态的工作,维护工作分领导者,追随者,候选者
心跳
领导者通过状态维护线程定时发送心跳到其他节点(不发给自己),检测健康度。领导者收到心跳返回,统计,设置下一步动作准备。
心跳是选举的源头,跟随者记录心跳时间,跟随者状态维护线程检查收到心跳时间间隔,若超时转为候选者发起选举。
发送心跳
领导者定时发送心跳
1 准备和初始化统计量
2 发送心跳
2.1 跳过自身,心跳请求不发给自己
处理心跳
其他非leader节点接收心跳请求,处理
1 leader不在集群成员名单
dledger目前没有集群成员管理,实际不会出现
2 leader收到自己发来的心跳请求
这个在后面问题一章分析
-----------------------------------------分割线------------------------------------------
3 term检查
3.1 leader的term落后于本节点
3.2 term一致,leader是心跳发送者,正常
-----------------------------------------分割线------------------------------------------
4 同样是term检查,需要改变状态,加上线程锁
4.1 leader的term落后于本节点,返回告诉发起阶段,你term落后了
4.2 term一致
4.2.1 leader空
可能是term落后的节点,提升了term,又或是刚启动,设置leader,便可正常工作
4.2.2 leader是发起心跳节点,正常
4.2.3 leader不是发起节点,不一致
出现脑裂,然后网络正常,处理方法参看部署下一步行动
4.3 本节点term落后了
提升term,不需要发起投票
统计心跳返回结果
领导者心跳返回统计,为下一步行动准备
2.2 异步统计
2.2.1 节点存活记录,目前没有使用,应该是预留给集群成员管理
2.2.2 提前结束,2个条件
1) 正常返回数过半
对leader来说,最关心的是正常返回节点数量过半,这样就可以维持任期有效,因此,只要过半可以“下班”,多一个两个无关紧要
2) 正常返回数+term落后节点数过半
心跳最重要任务就是探测集群是否有效,同时,节点term落后,给予机会调整,这样保证集群的稳定性,不要急于发起选举,说到底,集群最重要的是正常工作,此时落后的节点正提升term,只要这些节点正常,正常节点就过半
2.2.3 总数累计
总数达到allNum.get() == memberState.peerSize(),所有心跳请求返回(包括连接不上),退出
* memberState.peerSize() 实为 memberState.peerSize()+1-1,peerSize从0开始,数量需+1,排除自己,数量-1
部署下一步心跳行动
领导者统计完成,依据统计结果部署下一步行动
3 等待
这里等待有两处,一个是latch,一个是线程sleep
我不确定,但我理解, latch可以提前退出,线程sleep时间固定,固定的这段时间是为了notReady退出条件的情况,那时notReady节点正提升term,故而留点时间,提升term完成,接收心跳检测,便可成为正常节点
4 统计完毕,部署下一步的行动
4.1 本节点term落后了,自身是leader,需立即重新选举
4.2 集群有效性
心跳最重要任务就是探测集群是否有效,同时,有些节点term落后,给予机会调整,保证集群的稳定性,不要急于发起选举
4.2.1 正常节点过半,心跳检测完成
4.2.2 有效节点过半
notReady节点此时提升term,立刻心跳,term赶上可正常工作,参看处理心跳4.2,上面3
4.2.3 leader不一致
单单是一个节点的leader不一致,不用立刻发起选举,但到这里,
memberState.isQuorum(succNum.get() + notReadyNum.get())=false,意味着过半的节点没通讯上,很可能是脑裂,而且自己处于小数一边,需立刻选举
4.2.4 到这里,过半节点没通讯上,心跳检测失败
跟随者(follower)
跟随者检测心跳接收时间间隔,若超过最大心跳接收时间间隔,转为候选者角色发起选举,这里有个小心思,体现细节,
问题
选举未分析出来的点