开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情
基于 fsimage 和 checkpoint 机制优化 Master 重启性能
我们都知道单纯的 editslog 机制是可能存在 Master 重启时间很久的问题的,那这个问题怎么解决呢?
今天我们就一起来讨论下~
fsimage 机制
本来的设计,系统中的元数据是由 editslog 日志来持久化的,这时候,引进了 Fsimage 快照。
editslog 是命令日志, FsImage 是快照。
说到这里就不得不提一提复制状态机理论了。
其实我们接触到的很多分布式系统其实都是由复制状态机的身影的,复制状态机理论是基于快照 + 操作日志
的。
我们熟悉的很多分布式系统都这样的:
Redis 集群,快照(RDB)+ 操作日志(AOF)
MySQL 集群,binlog + redo log
分布式存储, FsImage(快照) + editslog(操作日志)
FsImage 和 editslog 存储数据的区别:
FsImage:
public class FsImage {
......
/**
* 当前最大的txId
*/
private long maxTxId;
/**
* 内容
*/
private INode iNode;
......
}
可以看到 FsImage 中保存的是 iNode 的信息,也就是直接就是元数据信息;在 NameNode 重启的时候,只需要直接加载进内存即可。
editslog:
message EditLog {
int64 txId = 1;
// 操作类型
int32 opType = 2;
string path = 3;
map<string, string> attr = 4;
}
可以看到 editslog 中保存的数据是包含具体操作的(opType),也就是说在回放 editslog 中的数据的时候,其实就是将当初的命令重新执行一次。
checkpoint 机制
Checkpoint机制是一种实现数据恢复的优化策略。它主要是指将fsimage快照文件定期保存到磁盘上,并将新的变更操作以editslog日志形式保存,这样NameNode守护进程在重启之后只需要加载fsimage快照文件即可,而不需要对所有editslog日志进行恢复,从而提高数据恢复的速度。
Checkpoint机制的实现流程:
- 保存fsimage快照文件
- 将新的变更操作记录在editslog日志中
- 在Master重启之后,NameNode守护进程只需要加载fsimage快照文件即可。
checkpoint 任务实现:
/**
* checkpoint 任务
*/
@Override
public void run() {
log.info("BackupNode启动checkpoint后台线程.");
try {
// 如果是正在恢复元数据,则直接返回
if (nameSystem.isRecovering()) {
log.info("正在恢复元数据...");
return;
}
// 当前 maxid 和 之前记录的 maxid 相等
if (nameSystem.getMaxTxId() == lastCheckpointTxId) {
log.info("EditLog和上次没有变化,不进行checkpoint: [txId={}]", lastCheckpointTxId);
return;
}
// 以下讨论的情况是:当前 maxid 和 之前记录的 maxid 不相等(大于)
FsImage fsImage = nameSystem.getFsImage();
// 更新记录中的 maxid
lastCheckpointTxId = fsImage.getMaxTxId();
// 路径
String fsImageFile = backupNodeConfig.getFsImageFile(String.valueOf(System.currentTimeMillis()));
log.info("开始执行checkpoint操作: [maxTxId={}]", fsImage.getMaxTxId());
// 写入FsImage文件
doCheckpoint(fsImage, fsImageFile);
// 上传 FsImage 给 NameNode
uploadFsImage(fsImageFile);
// 删除旧的FSImage
namenodeClient.getDefaultScheduler().scheduleOnce("删除FSImage任务", fsImageClearTask, 0);
} catch (Exception e) {
log.error("FSImageCheckPointer error:", e);
}
}
通过上述代码,我们可以发现其实所谓的 checkpoint 机制就是定时生成新的 FsImage,并覆盖旧的 FsImage。