一、什么是快照
快照(snapshot)是最简略的压缩形式。在快照中,全副的以后零碎状态都被写入到快照中,存储到长久化的存储中,而后在那个时刻之前的全副日志都能够被抛弃。
打个比方,像 Redis 这样的 KV 零碎,零碎的以后状态就是以后所有 key 的值及过期工夫,把这些信息全副写入到磁盘中就是快照。
二、Raft 算法中为什么须要快照
Raft 算法是通过日志来保障节点最终统一的,而日志是继续减少的,对于一个 7 *24 小时运行的零碎,日志会始终减少,这样导致几个问题:
1、磁盘占用空间过大;
2、新的节点退出进来后,须要同步的日志太多,进一步影响零碎的可用性;
还有 1 点不是 Raft 算法中自身的性能,就是复原数据,即一个误操作须要回滚,则须要回放从前到后所有日志,这个工夫会十分长,这时如果有快照就能够疾速复原了。
mysql binlog、Redis 的 aof 文件其实就相当于快照,只不过这些零碎没有实现 Raft 算法。
三、与快照相干的 RPC
1、装置快照 RPC(InstallSnapshot RPC)
对于接管方规定如下
- 如果 term < currentTerm 立即回复
- 如果是第一个分块(offset 为 0)则创立新的快照
- 在指定的偏移量写入数据
- 如果 done 为 false,则回复并持续期待之后的数据
- 保留快照文件,抛弃所有存在的或者局部有着更小索引号的快照
- 如果现存的日志领有雷同的最初任期号和索引值,则前面的数据持续保留并且回复
- 抛弃全副日志
- 可能应用快照来复原状态机(并且装载快照中的集群配置)
这些规定大部分应该好了解,局部规定解释下:
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 的时候能够疾速应答新节点增加数据的状况。因为只有数据统一,谁生成都是一样的。