您的位置:  首页 > 技术 > 数据库 > 正文

分布式云原生数据库中的共识流程

2022-06-15 16:00 https://my.oschina.net/u/5148943/blog/5540165 浪潮云溪数据库 次阅读 条评论

Raft Scheduler概述

Raft Scheduler在节点初始化时会一起启动,同时还会一同启动raftTickLoop进程用于定时产生tick请求。

Raft Scheduler主要的功能是处理raftGroup内部的消息请求与外部的写入读取请求,Raft Scheduler的工作方式是通过对外提供一个rangeID队列,当有请求来时,会修改该请求设计的range状态,并将其放入这个队列中,同时当Raft Scheduler跟随云溪数据库启动而初始化时,会初始化一定数量的processor,这些processor的作用是监听消息队列,当消息队列中有rangeID入队时,processor会将该rangeID取出,并根据该rangeID入队时的状态(stateTick、stateReady、stateRequest)进行不同处理。

我们在后续优化云溪数据库版本的过程中将RaftScheduler额外划分了一部分资源用于处理tick请求从而降低心跳延迟,这并不影响我们理解整体的逻辑处理流程。

 

Request入队流程

在副本层中需要处理的数据来自于分发层通过gRPC发送来的RaftMessageBatch,以及内部产生的消息请求。

当接收到分发层的RaftMessageBatch后,消息处理会通过store获取RaftMessageRequest对应rangeID的raftRequestQueue,并将RaftMessageRequest转换成raftRequestInfo追加至raftRequestQueue中。与此同时,更新rangeID对应的raftScheduleState并将rangeID添加到raftScheduler的queue中等待raft processor调度处理。

 

StateRaftTick处理流程

如果processor从rangeIDQueue中取出的rangeID对应状态为stateRaftTick,则processor会调用ProcessTick()方法进行处理。

首先,processor会在store中获取该rangeID的本地replica和对应livenessMap, 然后调用replica_raft.go下tick()。获取replica的unreachable remotes,构造MsgUnreachable, 通过replica所在的raft group处理该msg。结束这一步后,会验证replica是否为静默状态,如果replica是静默状态,则无需tick。Tick的条件为:

  1. raft group已初始化。

  2. replica是非静默的。

  3. 再次检查replica是否静默,静默的判断条件为满足以下所有条件:

1. cluster启用静默配置。

2. replica不存在尚未应用的raft command。

3. replica不存在进行中的merge。

4. replica没有被destroyed。

5. replica所在raft group状态非空。

6. replica是raft leader。

7. replica当前不存在raft leader切换。

8. replica是leaseholder。

9. raft的applied/commit/lastindex相等。

10. 获取所有remote replica,除了不在livenessMap中的node,remote replica在leader生成的progress列表中,同时remote replica的progress match值必须跟当前raft的applied相等。

11. replica本身必须在progress列表中。

12. raft当前状态不是ready。

如果判断当前replica所在raft group是静默状态,只发送心跳数据: 

首先,获取range中其他remote replica的ReplicaDescriptor,为每个remote replica构造raftpb.MsgHeartbeat,构造StoreIdent和RaftHeartbeat,生成KV并写入store的heartbeats map<目标store标识,心跳数据>中,在store.go->coalescedHeartbeatsLoop()处理store的心跳数据,对每个KV构造RaftMessageRequest并写入对应节点的channel中,在raft_transport.go->startProcessNewQueue()->processQueue()中维护该channel,负责将request转发到指定replica。

如果判断当前replica所在raft group是非静默状态,除进行上述操作外,在这之后会检查当前replica是否同时为raft leader和leaseholder(DisableLeaderFollowsLeaseholder为false时的要求),如果不满足,会构造leader切换的message,发起一轮选举。

 

- StateRaftReady -

如果rangeID对应的状态是stateRaftReady。

1. store.go->processReady()首先从store中获取该rangeID对应的本地replica,通过relica的internalRaftGroup构造raft Ready数据(raft Ready包含了需要持久化的entries和需要提交或发送到其他节点的message),然后将Ready中包含的msg分为MsgApp和其他类型两部分,首先将MsgApp类型消息构造成RaftMessageRequest写入到对应node的channel中,然后通过raft_transport.go->startProcessNewQueue()->processQueue()转发到指定replica。

2. 在异步发送msg过程中,会通过rocksDB/Pebble构造batch,同时处理Ready中包含的待持久化的entries,并构造repr,然后使用构造的batch将repr异步迭代写入到store对应的存储引擎中。

3. 将拆分出的其他消息类型构造RaftMessageRequest发送到node的channel中。

4. 从Ready中包含的CommittedEntries每一行中获取command id和raft command并生成WriteBatch,构造WriteBatch, 并生成Repr,将Repr中数据异步落盘。

 

- StateRaftRequest -

如果rangeID对应的状态是stateRaftRequest,从store中获取该rangeID对应的raftRequestQueue,然后获取队列中的每个raftRequestInfo, 每个raftRequestInfo中的RaftMessageRequest都带有一条message,根据每条message的type不同有不同的处理方法,可参考上述Msg类型篇。

1. MsgHub,当follower节点的选举计时器超时后,会发送msgHub.

2. MsgBeat,leader发送的心跳信息,心跳计时器超时时触发该消息,leader通过stepLeader()生成MsgHeartbeat发送给集群中其他节点。

3. MsgProp,客户端向集群发送的写请求通过msgProp表示。

4. MsgApp,当一个节点通过选举成为leader后,会获取目标节点Next-1对应的记录的term值和需要发送的Entries,然后发送MsgApp消息,该消息可以帮助follower节点与leader节点同步。

5. MsgAppResp,msgApp的响应消息类型,当follower节点收到msgApp后,无论是否进行日志追加,都将返回一条带有本节点最后一条记录索引值的消息。

6. MsgVote,当PreCandidate状态节点收到半数以上的投票之后,会发起新一轮的选举,即向集群中的其他节点发送MsgVote。

7. MsgVoteResp,msgVote的响应消息。

8. MsgSnap,当leader获取目标节点Next-1对应的记录的term值和需要发送的Entries出现异常时,就会生成msgSnap将快照数据发送到follower节点,follower节点通过快照数据恢复状态,从而可以与leader进行正常的entry记录复制。

9. MsgHeartbeat,leader发送的心跳消息,主要作用是探测节点是否存活,follower接收到msgHeartbeat会重置自身的选举计时器,防止follower发起新一轮的选举。同时尝试更新follower节点raftLog中已提交的位置。

10. MsgHeartbeatResp,follower处理心跳消息返回的消息类型。

11. MsgUnreachable,如果leader发送MsgSnap消息出现异常,将会调用ReportUnreachable()发送该类型消息,将follower节点的状态改为ProgressStateProbe。

12. MsgSnapStatus,校验节点对应的状态是否为ProgressStateSnapshot,如果之前发送的快照消息出现异常则将节点状态改为ProgressStateProbe,之后单条发送消息。

13. MsgCheckQuorum,leader发送该消息类型检测是否保持半数以上连接。当Leader 的心跳计时器超时,并且开启了checkQuorum模式(raft的checkQuorum字段为true)。该Leader节点就会发送MsgCheckQuorum消息检测与集群中其他节点是否保持半数以上的连接,如果没有则变成Follower节点。

14. MsgTransferLeader,发起leader节点转移的消息类型,本地消息。

15. MsgTimeoutNow,如果leader节点转移超时,会发送该类型的消息,使follower的选举计时器立即过期,并发起新一轮的选举。

16. MsgReadIndex,客户端发往集群的只读消息使用该类型。

17. MsgReadIndexResp,只读消息类型的响应消息。

18. MsgPreVote,当Follower的选举计时器超时时,会把当前状态切换成 StatePreCandidate(预选举),并向集群中其他节点发送MsgPreVote。当集群中其他节点收到预选举消息时,会先进行一些检验,符合相关条件会投同意,否则会投拒绝票,然后发送给该候选节点,发送的消息类型为MsgPreVoteResp。如果预选举阶段(StatePreCandidate)成功收到超过半数以上的同意票,那么该节点会认为选举成功,会发起新一轮的正式选举(节点状态切换成SateCandidate(候选人),发送的消息类型为MsgVote)。是否有预选举阶段是根据初始化配置的参数,该字段保存在raft结构体的preVote字段中

19. MsgPreVoteResp,其他节点响应预选举的投票消息。

展开阅读全文
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接