解析云溪数据库中Raft算法的消息类型
浪潮云溪数据库作为新一代分布式数据库,使用Raft共识算法实现多副本之间数据的一致性和外部读取的一致性。在云溪数据库的底层实现中,通过以下几种消息类型实现Raft机制的运行。其中,本地消息指节点创建完消息后,由自身处理该消息。节点间消息指节点在创建完消息后,将消息发送到其他节点并由这些节点处理。
- 本地消息 -
MsgHup
Follower节点持有一个选举计时器,当节点所持有的选举计时器超过预设的选举时间阈值时,便会创建MsgHup消息。具体操作包括:
Follower节点调用选举计时器,将选举计数加1;
检查当前Follower节点是否存在于Raft集群内,若不存在,则拒绝创建MsgHup消息。若存在于Raft集群内,则检查选举计数是否大于等于设定的选举时间阈值。若小于设定的选举时间阈值,则拒绝创建MsgHup消息,否则创建MsgHup消息。
在创建出MsgHup消息后,当前Follower节点会切换成PreCandidate状态,等待下一步操作。
MsgCheckQuorum
MsgCheckQuorum消息的作用是检测当前Leader节点是否能与Raft集群中的大部分节点通信。Leader节点持有一个心跳计时器,当心跳计时器出现超时现象时,Leader节点便会创建并发送一个MsgCheckQuorum消息。具体操作包括:
Leader节点调用心跳计时器,将选举计数加1;
检查选举计数是否大于等于设定的选举时间阈值,若满足条件,则将选举计数置为0,然后创建MsgCheckQuorum消息。
由于MsgCheckQuorum消息属于本地消息,所以当前Leader节点会收到MsgCheckQuorum消息。然后,Leader节点会根据自身记录的其他各个节点的活跃信息,判断该Leader节点与其余节点是否连通。如果不连通,则节点从Leader状态切换成Follower状态。
MsgBeat
MsgBeat消息的主要作用是探活,由Leader节点创建。在Leader节点所持有的心跳计时器超时后,便会发送MsgBeat消息。具体操作包括:
Leader节点调用心跳计时器,将心跳计数加1;
检查心跳计数是否大于等于设定的心跳时间阈值,若满足条件,则将心跳计数置为0,然后创建MsgBeat消息。
由于MsgBeat消息属于本地消息,所以当前Leader节点会收到MsgBeat消息。然后Leader节点向其他节点发送MsgHeartbeat心跳消息。若Follower节点收到MsgHeartbeat消息,则会重置自身持有的选举计时器,目的是防止Follower节点发起新一轮的选举。
MsgTransferLeader和MsgTimeoutNow
将节点的Leader状态转移到其他Follower节点,该过程会其中涉及MsgTransferLeader消息和MsgTimeoutNow消息的处理。Leader状态转移,即指定一个Follower节点作为下一个任期的Leader节点,当前Leader节点会选择一个合适的节点,然后发送MsgTransferLeader消息。
当Follower节点接收到MsgTimeoutNow消息后,会切换成Candidate状态并发起选举。
- 节点间消息 -
MsgPreVote
当Follower节点接收到MsgHup本地消息时,自身会切换成PreCandidate状态,然后创建MsgPreVote消息,并向其他节点广播该消息,MsgPreVote消息中携带的Term值为节点自身记录的Term值。
集群中其他节点收到MsgPreVote消息后,对MsgPreVote消息的处理包括:
若消息中携带的Term值大于当前节点记录的Term值,则检测该MsgPreVote消息是否为Leader节点迁移时发出的消息和自身记录的Leader节点是否存在,判断当前节点是否参与此次选举。若确定参与此次选举,则当前节点会根据自身的状态,决定是否将同意选票投给MsgPreVote消息的发送节点。
若消息中携带的Term值小于当前节点记录的Term值,则直接向发送MsgPreVote消息的节点投拒绝选票。
MsgPreVoteResp
处于PreCandidate状态的节点会收到集群中其他节点返回的MsgPreVoteResp消息,当PreCandidate节点收到半数以上的同意选票时,便会切换成Candidate状态,发起正式选举。但是,若收到了拒绝选票,且MsgPreVoteResp消息中携带的Term值大于当前节点记录的Term值,则当前节点切换为Follower状态,同时自身记录的Term值置为MsgPreVoteResp消息中携带的Term值,停止接下来的选举流程。
MsgVote
在处于PreCandidate状态的节点收到半数以上的同意选票之后,会发起新一轮的选举,自身会切换成Candidate状态,然后向集群中的其他节点发送MsgVote消息。
MsgVoteResp
在处于Candidate状态的节点接收到MsgVoteResp消息后,对MsgVoteResp消息的处理包括:
若MsgVoteResp消息中携带的Term值大于当前节点记录的Term值,则当前节点切换为Follower状态,同时自身记录的Term值置为MsgPreVoteResp消息中携带的Term值,停止接下来的选举流程。
检测当前节点是否收到了半数以上的同意选票。如果是,则将当前节点切换成Leader状态,然后向集群中其他节点发送消息MsgApp消息。如果不是,则将当前节点切换成Follower状态。
MsgApp
MsgApp消息的作用是Leader节点向集群中其他节点复制Entry记录。在对MsgVote消息的处理过程中,集群中的其他节点已经切换成了Follower状态,并且它们自身记录的Term值与当前Leader节点维护的Term值相同。当它们收到Leader节点发来的MsgApp消息时,会将MsgApp消息中携带的Entry记录追加到raftLog中,最后创建相应的MsgAppResp消息返回给Leader节点。
在处于Follower状态的节点接收到MsgApp消息后,对MsgApp消息的处理包括:
重置选举计时器,防止当前Follower节点发起选举;
设置当前节点记录的Leader信息;
追加Entry记录;
MsgAppResp
不论Follower节点追加Entry成功或失败,均会向Leader节点回复MsgAppResp消息。Leader节点接收到集群中其他Follower节点发送的MsgAppResp响应消息后,会根据自身记录的Follower节点的状态信息,选择不同的追加方式向其追加Entry记录,如单条追加、连续追加。若Leader节点在自身保存的Entery记录中无法找到对应Follower节点需要追加的Entry记录时,便会选择发送快照的方式,向其追加Entry。
MsgHeartbeat
在处于Follower状态的节点接收到MsgHeartbeat消息后,对MsgHeartbeat消息的处理包括:
重置选举计时器,防止当前Follower节点发起选举;
设置当前节点记录的Leader信息;
尝试修改当前Follower节点记录的已提交Entry的Index值,检查当前节点是否与Leader节点在Entry记录上存在冲突。若冲突,则将自身的Index信息放到MsgHeartbeatResp消息,等待发送;
发送MsgHeartbeatResp消息,响应此次心跳。
MsgHeartbeatResp
在处于Leader状态的节点接收到MsgHeartbeatResp消息后,对MsgHeartbeatResp消息的处理包括:
更新相应节点的活跃信息,表明Follower节点与自己是否能连通;
重置相应节点单条追加Entry记录的方式,可以向Follower节点进行连续追加Entry记录;
根据响应消息检测到Follower节点与Leader的Entry记录存在冲突,则调整自身记录的Follower节点状态信息,并向该节点开始追加Entry记录。
检查在Leader节点中存在未向该Follower节点追加的Entry记录,则向节点发送MsgApp消息完成Entry记录的追加。
MsgProp
客户端通过MsgProp消息向集群发送写请求,而Raft集群中只有Leader节点能够响应客户端的写请求。当集群中的Candidate节点收到客户端发来的MsgProp消息时,会直接忽略该消息。当Follower节点收到MsgProp消息时,会将该MsgProp消息转发给当前集群的Leader节点。
在处于Leader状态的节点接收到MsgProp消息后,对MsgProp消息的处理包括:
检测MsgProp消息是否携带Entry记录,如果未携带,则输出异常日志并终止程序;
检测当前节点是否被移出集群,如果当前节点以Leader状态被移出集群,则不再处理MsgProp消息;
检测当前Raft集群是否正在进行Leader节点的转移,如果是,则不再处理MsgProp消息;
若上述策略均通过,则将Entry记录保存到当前节点,并通过MsgApp消息向集群中其他节点追加Entry记录。
MsgSnap
在Leader节点尝试向集群中的Follower节点发送MsgApp消息时,如果查找不到待发送的Entry记录,就会通过MsgSnap消息将快照数据发送到Follower节点。Follower节点通过快照数据恢复其自身状态,从而可以与Leader节点进行正常的Entry记录追加。
在处于Follower状态的节点接收到MsgSnap消息后,对MsgSnap消息的处理包括:
重置选举计时器,防止当前Follower节点发起选举;
设置当前节点记录的Leader信息;
Follower节点根据快照进行恢复,之后向Leader节点回复MsgAppResp消息。
- 小结 -
本文主要介绍了Raft共识算法在云溪数据库中定义的消息类型,通过上述介绍的消息类型,实现和保证了副本数据的同步。可以看出,云溪数据库中的Raft算法将共识分解成了几个关键模块,例如预选举模块、正式选举模块、探活模块、日志复制模块等。基于此,实现将分布式一致性的复杂问题划分为一系列的模块化问题,大大降低了算法复杂性。