面试官:聊聊 etcd 中的 Raft 吧( 三 )
raftLog 由以下成员组成:
- storage Storage:前面提到的存放已经持久化数据的 Storage 接口 。
- unstable unstable:前面分析过的 unstable 结构体 , 用于保存应用层还没有持久化的数据 。
- committed uint64:保存当前提交的日志数据索引 。
- applied uint64:保存当前传入状态机的数据最高索引 。
raftLog 结构体中 , 几部分数据的排列如下图所示2[14]:
文章插图
RaftLog Layout
这个数据排布的情况 , 可以从 raftLog 的初始化函数中看出来:
// #L45// newLog returns log using the given storage. It recovers the log to the state// that it just commits and applies the latest snapshot.func newLog(storage Storage, logger Logger) *raftLog {if storage == nil {log.Panic("storage must not be nil")}log :=--tt-darkmode-color: #EF7060;">Storage管理的已经持久化的数据 , 而在此之后都是unstable管理的还没有持久化的数据 。
以上分析中还有一个疑问 , 为什么并没有初始化 unstable.snapshot 成员 , 也就是 unstable 结构体的快照数据?原因在于 , 上面这个是初始化函数 , 也就是节点刚启动的时候调用来初始化存储状态的函数 , 而 unstable.snapshot 数据 , 是在启动之后同步数据的过程中 , 如果需要同步快照数据时才会去进行赋值修改的数据 , 因此在这里并没有对它进行操作的地方 。
progress.goLeader 通过Progress这个数据结构来追踪一个 follower 的状态 , 并根据Progress里的信息来决定每次同步的日志项 。 这里介绍三个比较重要的属性:
// #L37// Progress represents a follower’s progress in the view of the leader. Leader maintains// progresses of all followers, and sends entries to the follower based on its progress.type Progress struct {Match, Next uint64State ProgressStateTypeins *inflights}
- 用来保存当前 follower 节点的日志状态的属性:在正常情况下 , Next = Match + 1 , 也就是下一个要同步的日志应当是对方已有日志的下一条 。
- Match:保存目前为止 , 已复制给该 follower 的日志的最高索引值 。 如果 leader 对该 follower 上的日志情况一无所知的话 , 这个值被设为 0 。
- Next:保存下一次 leader 发送 append 消息给该 follower 的日志索引 , 即下一次复制日志时 , leader 会从Next开始发送日志 。
- State属性用来保存该节点当前的同步状态 , 它会有一下几种取值3[15]:探测状态 , 当 follower 拒绝了最近的 append 消息时 , 那么就会进入探测状态 , 此时 leader 会试图继续往前追溯该 follower 的日志从哪里开始丢失的 。 在 probe 状态时 , leader 每次最多 append 一条日志 , 如果收到的回应中带有RejectHint信息 , 则回退Next索引 , 以便下次重试 。 在初始时 , leader 会把所有 follower 的状态设为 probe , 因为它并不知道各个 follower 的同步状态 , 所以需要慢慢试探 。 当 leader 确认某个 follower 的同步状态后 , 它就会把这个 follower 的 state 切换到这个状态 , 并且用pipeline的方式快速复制日志 。 leader 在发送复制消息之后 , 就修改该节点的Next索引为发送消息的最大索引+1 。 接收快照状态 。 当 leader 向某个 follower 发送 append 消息 , 试图让该 follower 状态跟上 leader 时 , 发现此时 leader 上保存的索引数据已经对不上了 , 比如 leader 在 index 为 10 之前的数据都已经写入快照中了 , 但是该 follower 需要的是 10 之前的数据 , 此时就会切换到该状态下 , 发送快照给该 follower 。 当快照数据同步追上之后 , 并不是直接切换到 Replicate 状态 , 而是首先切换到 Probe 状态 。
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 聊聊网易云音乐:“心动模式”
- 华为突然宣布!腾讯也没有想到,一切来得如此快
- 全球最受欢迎的4部5G手机:靠量取胜的小米竟榜上无名?
- Java学习:Java学习到什么程度可以进行面试
- 程序员面试金典17.05_go_字母与数字
- 安卓春招面经:二本渣院面试网易被拒,最终获腾讯阿里offer
- 中国最赚钱的公司诞生!不是移动,也不是阿里巴巴,那第一是?
- 「6」进大厂必须掌握的面试题-Hibernate
- 高通骁龙888提前来了!华为“慌”了?但一切还没有定论
- 震惊!京东T4大佬面试整整三个月,才写了两份java面试笔记