5.1 创建快照
流程详解
流程概览
快照有压缩日志和加速启动的作用,其创建流程如下:
当快照定时器超时或用户手动调用接口,会触发节点执行创建快照的任务
节点会将任务放进 ApplyTaskQueue,等待其被执行
当任务被执行时,会创建一个
temp目录用来保存临时快照,并返回一个SnapshotWriter以
SnapshotWriter和Closure做为参数调用用户状态机的on_snapshot_save用户需通过
SnapshotWriter将状态数据写入到临时快照中:5.1 调用
SnapshotWriter::get_path获得快照目录绝对路径,并将快照文件写入该目录5.2 调用
SnapshotWriter::add_file将快照文件相对路径添加至快照元数据中
待数据写入完成,用户需回调
Closure将其转换为正式快照:6.1 将快照元数据持久化到文件
6.2 通过
rename()将临时快照转换为正式快照6.3 删除上一个快照
6.4 删除上一个快照对应的日志
至此,快照创建完成
流程整体分为以下 3 个阶段:创建临时快照(1-3),用户写入数据(4-5),转为正式快照(6-7)

快照结构

正常情况下用户指定的快照存储目录下只会有一个快照目录。当创建快照时,会创建一个 temp 目录来保存临时快照,待创建完成后,通过 rename 将其转换为正式快照。
正式快照目录以当时创建快照时的 applyIndex 命名,如 snapshot_00000000000000002000。
快照目录下除了用户写入的快照文件集合外,还有一个框架写入的元数据文件 __raft_snapshot_meta,元数据主要保存以下 2 部分信息:
快照中每一个文件的相对路径
快照中包含的最后日志的
index和term,以及集群配置
参见以下元数据 proto:
相关接口
用户手动触发快照:
用户需要实现的快照函数:
SnapshotWriter 相关接口:
阶段一:创建临时快照
触发快照任务
节点有以下 2 种方式触发快照任务,其最终都是调用 NodeImpl::do_snapshot 执行快照任务。
快照定时器超时:
用户手动触发:
执行快照任务
NodeImpl::do_snapshot 会调用 SnapshotExecutor::do_snapshot 执行快照任务。在正式创建快照前会做一些判断,决定是否要创建快照;若确定要创建快照,则:
创建
temp目录用于保存临时快照将创建快照任务放入 ApplyTaskQueue 中等待被执行
创建临时目录
LocalSnapshotStorage::create 会创建 temp 目录,若事先已存在 temp 目录,则先将其删除后再创建,并返回 SnapshotWriter:
任务入队执行
创建好 temp 目录后,会调用 FSMCaller::on_snapshot_save 将快照任务放入 ApplyTaskQueue,等待其被执行:
队列消费函数会调用 FSMCaller::do_snapshot_save 执行快照任务:
在 FSMCaller::do_snapshot_save 函数中主要做以下 2 件事:
准备好元数据,将其保存在
Closure中将上述创建的
SnapshotWriter和Closure作为参数调用用户状态机的on_snapshot_save
阶段二:用户写入数据
on_snapshot_save
用户需要实现状态机的 on_snapshot_save 函数,在该函数中用户需要做以下 3 件事:
调用
writer->get_path获取临时快照的目录路径,并将快照文件写入到该目录下调用
write->add将快照中每一个文件的相对路径加入到快照元数据中待以上全部完成后,调用
done->Run将临时快照转换为正式快照
get_path
get_path 接口会返回临时快照(temp)目录的绝对路径,用户需要在该目录中写入快照文件:
add_file
add_file 接口只是将文件路径添加到元数据中而已:
阶段三:转为正式快照
调用 Closure
用户完成快照的创建后,需调用 Closure,即 SaveSnapshotDone::Run(),而该函数会将临时快照 rename 成正式快照,并删除上一个快照,以及删除上一个快照对应的日志。
用户调用 SaveSnapshotDone::Run,该函数主要执行以下 2 件事:
on_snapshot_save_done 会完成以下几项工作:
save_meta 会将元数据保存到 LocalSnapshotMetaTable 中:
写入元数据
rename 成正式快照
在 close 函数中主要以下做四件事:
(1) 将元数据持久化到文件
(2) 通过
rename()将临时快照变为正式快照(3) 删除上一个快照
LocalSnapshotWriter::sync 会调用 save_to_file 将元数据填充到 proto(LocalSnapshotPbMeta)中,并将其序列化,最终持久化到文件:
删除上一个快照
调用 unref 删除上一个快照。需要注意的是,当前节点可能是 Leader,而该快照可能正用于下载给其他 Follower,所以需要判断其引用计数,若引用计数为 0,则删除其目录:
删除上一个快照对应日志
在 Closure 中最后会调用 set_snapshot 删除上一个快照的日志,之所以只删除上一个快照的日志,而不立即删除当前快照的日志,主要考虑到有些 Follower 还没有同步完日志,如果删除了当前的日志,哪怕只差几条日志也只能发送快照进行同步,见以下注释:
Last updated