这是我的第106篇原创文章
一、安全模式简介
在hdfs中,namenode为保证数据一致性、可靠性,而进入的一种状态,称之为安全模式(SafeMode)。在安全模式下,客户端只能进行数据的读取操作,而不能进行创建、删除、重命名文件目录等操作,即在安全模式下,不能对hdfs文件系统做任何修改。
通常情况下,namenode在启动通过fsimage与editlog完成文件系统的加载之后,就会自动进入安全模式。此后等待各个datanode的注册,以及通过心跳进行的全量块汇报。
当在线(完成注册)的Datanode达到一定的个数,同时汇报的块个数达到一定的比例后,namenode自动离开安全模式。
二、运行过程中的安全模式检测
从namenode启动进入安全模式,到满足条件离开安全模式。在这之后,如果有Datanode下线,或者Datanode的磁盘损坏,导致在线的Datanode没有满足指定个数,或者汇报的block数量无法达到指定的比例时,是否还会重新再进入安全模式呢?
答案是否定的,Datanode在线数与block汇报率这两个指标仅在namenode启动时进行强检验,在离开安全模式之后,即便条件不满足也不会再次进入安全模式。
但是,namenode在启动后,内部会启动一个资源监测线程,定时检测资源是否满足指定条件。这些资源指的就是配置的用于存储editlog、fsiamge的存储卷目录;指定条件则是存储卷目录的剩余可用空间大于配置项指定的值(默认100MB),当有资源不满足条件时,即存储卷目录可用剩余空间小于指定大小时,则主动进入安全模式。
注意:资源检测线程发现存储空间不够时会触发进入安全模式,但代码中还存在BUG:即存储空间进行了释放达到可用的条件时,不会自动退出安全模式,这个问题在最新release版本中才修复。
资源检测与问题修复代码如下所示:
三、命令手动进入退出安全模式&特殊场景
除了这两种方式可以进入/退出安全模式之外, 我们还可以通过命令的方式主动设置进入安全模式或离开安全模式。
# 获取当前安全模式的状态
hdfs dfsadmin -safemode get
# 进入安全模式
hdfs dfsadmin -safemode enter
# 离开安全模式
hdfs dfsadmin -safemode leave
# 强制退出安全模式
hdfs dfsadmin -safemode forceExit
在上面提到的两种场景中,通过命令可以手动退出安全模式,那么在什么场景下,即便调用"-safemode leave"还不能退出安全模式,必须调用强制退出安全模式才能真正退出安全模式呢?
NN在处理DN首次全量块汇报时,如果DN汇报的块在NN中找不到对应的元数据记录信息,同时上报的这个块的时间戳比NN内部的时间戳还要大,在NN内部会认为这是一个"未来时间"写入的块,单独进行记录。
void processFirstBlockReport(
final DatanodeStorageInfo storageInfo,
final BlockListAsLongs report)
throws IOException {
...
for(BlockReportReplica iblk : report) {
...
BlockInfo storedBlock = getStoredBlock(iblk);
if(storedBlock == null) {
bmSafeMode.checkBlocksWithFutureGS(iblk);
continue;
}
...
}
}
void checkBlocksWithFutureGS(BlockReportReplica brr) {
assert namesystem.hasWriteLock();
if(status == BMSafeModeStatus.OFF) {
return;
}
if (!blockManager.getShouldPostponeBlocksFromFuture() &&
!inRollBack &&
blockManager.isGenStampInFuture(brr)) {
if(blockManager.getBlockIdManager().isStripedBlock(brr)) {
bytesInFutureECBlockGroups.add(brr.getBytesOnDisk());
} else {
bytesInFutureBlocks.add(brr.getBytesOnDisk());
}
}
}
之后,即便DN在线个数与块汇报率满足条件,也不会退出安全模式,此时,只能通过命令人为强制退出安全模式。相当于需要人工确认这些块是没有问题的,而不是可能的元数据丢失。
boolean leaveSafeMode(boolean force) {
final long bytesInFuture = getBytesInFuture();
if(bytesInFuture > 0) {
if(force) {
LOG.warn("Leaving safe mode due to forceExit. This will cause a data " + "loss of {} byte(s).", bytesInFuture);
bytesInFutureBlocks.reset();
bytesInFutureECBlockGroups.reset();
} else {
...
return false;
}
} else if(force) {
LOG.warn(...);
}
}
这种情况,多发生在升级回滚的场景。比如,先对NN的元数据进行了备份,然后进行升级,升级过程中写入了少量文件,再使用备份的元数据进行回滚,就会出现DN中新写入的块的时间戳要大于NN中记录的时间戳,同时由于是新写入的文件,在老的备份的元数据中不存在对应的信息,在DN注册进行全量块汇报时自然就出现了这种情况了。
四、相关配置
安全模式相关的配置包括:
配置项 | 默认值 | 说明 |
dfs.internal.nameservices | 5000(单位:毫秒) | ANN启动检测资源是否满足条件的时间间隔 |
dfs.namenode.safemode.min.datanodes | 0 | 启动后离开安全模式的最小存活datanode个数 |
dfs.namenode.safemode.threshold-pct | 0.999 | 启动后离开安全模式的block块的汇报百分比 |
dfs.namenode.resource.check.interval | 5000(单位:毫秒) | 资源检测的时间间隔 |
dfs.namenode.resource.du.reserved | 100MB | namenode存储卷目录预留大小 |
总结
本文介绍了hdfs安全模式的相关知识,包括启动进入安全模式、离开安全模式的条件、资源监测引起的安全模式进入与离开、以及运维操作命令手动进入安全模式与离开。
好了,这就是本文的全部内容,如果觉得本文对您有帮助,请点赞+转发,如果觉得有不正确的地方,欢迎留言交流~
参考:
[1] https://issues.apache.org/jira/browse/HDFS-17231