vlambda博客
学习文章列表

Raft算法之快照篇

一、什么是快照

快照(snapshot)是最简单的压缩方式。在快照中,全部的当前系统状态都被写入到快照中,存储到持久化的存储中,然后在那个时刻之前的全部日志都可以被丢弃。

打个比方,像Redis这样的KV系统,系统的当前状态就是当前所有key的值及过期时间,把这些信息全部写入到磁盘中就是快照。


二、Raft算法中为什么需要快照

Raft算法是通过日志来保证节点最终一致的,而日志是持续增加的,对于一个7*24小时运行的系统,日志会一直增加,这样导致几个问题:

1、磁盘占用空间过大;

2、新的节点加入进来后,需要同步的日志太多,进一步影响系统的可用性;


还有1点不是Raft算法中本身的功能,就是恢复数据,即一个误操作需要回滚,则需要回放从前到后所有日志,这个时间会非常长,这时如果有快照就可以快速恢复了。


mysql binlog、Redis的aof文件其实就相当于快照,只不过这些系统没有实现Raft算法。


三、与快照相关的RPC

1、安装快照 RPC(InstallSnapshot RPC)


参数
说明
term  Leader的任期 
leaderId Leader的id
lastIncludedIndex  快照中包含的最后日志条目的索引值 
lastIncludedTerm  快照中包含的最后日志条目的任期号 
offset  分块在快照中的偏移量 
data[] 快照块的原始数据 
done  如果是最后一块数据则为真 


返回值  描述 
term  Follower的当前任期号


对于接收方规则如下

  1. 如果term < currentTerm立刻回复

  2. 如果是第一个分块(offset 为 0)则创建新的快照

  3. 在指定的偏移量写入数据

  4. 如果 done为 false,则回复并继续等待之后的数据

  5. 保存快照文件,丢弃所有存在的或者部分有着更小索引号的快照

  6. 如果现存的日志拥有相同的最后任期号和索引值,则后面的数据继续保留并且回

  7. 丢弃全部日志

  8. 能够使用快照来恢复状态机(并且装载快照中的集群配置)

这些规则大部分应该好理解,部分规则解释下:

5、保存快照文件,丢弃所有存在的或者部分有着更小索引号的快照

假如说Follower已经有快照了,并且快照最后索引为1000,而新的快照的索引为2000,则将前面的快照丢弃


6、如果现存的日志拥有相同的最后任期号和索引值,则后面的数据继续保留并且回复

意思说接收节点如果有相应的日志了,则后面的日志保留,此消息可以直接回复。

打个比方,如果Follower B的索引已经到2002,此索引对应的term为102,其中2000索引的term为101,如果这时收到一个安装快照的消息,最后1条的term为101,最后1条的索引为2000,通过对比发现此日志已经存在节点上,并且Term也对的上,因此2001之后的日志保留。


7、丢弃全部日志

上面条件满足后,将快照保存到本地,本地所有日志全部丢弃。

当然前提是前面的条件都不满足,具体不细述。


8、能够使用快照来恢复状态机(并且装载快照中的集群配置)

恢复状态机就不用说了,直接拿快照恢复状态机的数据,举例来说KV系统,发送的快照如果只有a=1, b=2这样的状态,即把所有数据清空,只保留上面2条数据。


并且装载快照中的集群配置,意思是说快照还包含集群配置信息,主是要为了支持集群成员更新;


所以快照必须以下信息:

最后一条日志的Index;

最后一条日志的Term;

生成快照时的集群配置信息;

状态机数据;


四、其它细节

1、何时生成快照

这个Raft算法并没有规定,看应用自己实现,像etcd是10000日志后产生1次快照,需要根据实际条件选择。


2、谁生成日志快照

Raft算法并没有规定谁可以生成,即谁都可以生成,即符合条件1就可以生成,主要是为了切换为Leader的时候可以快速应对新节点添加数据的情况。因为只有数据一致,谁生成都是一样的。