上一篇讲到了namenode的格式化,格式化方法中有
FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
try {
FSNamesystem fsn = new FSNamesystem(conf, fsImage);
今天主要讲讲FSImage ,FSNamesystem 分别在(1),(2)中
FSImage,FSImage处理checkpointing(检查点),并记录到文件命名空间编辑日志中。
fsimage在磁盘上对应上一篇文章提到的/home/hadoop/dfs/name路径。目录下有current,image,in_use.lock;在current目录下有edits日志,fsimage内存镜像,fstime镜像时间,VERSION版本信息。
FSImage常用操作有loadFSImage(加载文件系统镜像),saveFSImage(保存文件系统镜像)
在loadFSImage中,最终会调用FSImageFormat类中的load(File curFile)方法,代码如下:
public void load(File curFile) throws IOException {
checkNotLoaded(); // 保证是第一次加载时执行下面的语句
assert curFile != null : "curFile is null"; // 断言
StartupProgress prog = NameNode.getStartupProgress(); // 获取启动进度
Step step = new Step(StepType.INODES);
prog.beginStep(Phase.LOADING_FSIMAGE, step);
long startTime = now(); // 开始
//
// Load in bits
//
MessageDigest digester = MD5Hash.getDigester();
DigestInputStream fin = new DigestInputStream(
new FileInputStream(curFile), digester); // 获取输入流
DataInputStream in = new DataInputStream(fin); // 包装输入流
try {
// read image version: first appeared in version -1
int imgVersion = in.readInt(); // 读取镜像版本号
if (getLayoutVersion() != imgVersion) { // 判断版本是否一致,不一致抛异常
throw new InconsistentFSStateException(curFile,
"imgVersion " + imgVersion +
" expected to be " + getLayoutVersion());
}
boolean supportSnapshot = NameNodeLayoutVersion.supports( // 判断是否支持快照
LayoutVersion.Feature.SNAPSHOT, imgVersion);
if (NameNodeLayoutVersion.supports(
LayoutVersion.Feature.ADD_LAYOUT_FLAGS, imgVersion)) {
LayoutFlags.read(in);
}
// read namespaceID: first appeared in version -2
in.readInt(); // 读取命名空间编号
long numFiles = in.readLong(); // 文件数量
<span style="white-space:pre"> </span>......
在saveFSImage中,最终调用FSImageFormatProtobuf中save(File file, FSImageCompression compression)方法,代码如下
void save(File file, FSImageCompression compression) throws IOException {
FileOutputStream fout = new FileOutputStream(file); // 创建输出流
fileChannel = fout.getChannel(); // 获取网络套接字的通道,用过java nio的朋友应该清楚
try {
saveInternal(fout, compression, file.getAbsolutePath().toString()); // 在该方法中,underlyingOutputStream.write(FSImageUtil.MAGIC_HEADER)进行持久化操作
} finally {
fout.close();
}
}
(2)对于
hadoop集群,
master节点存储
3种类型元数据:文件和数据块的命名空间,文件和数据块的对应关系,每个数据块副本的存放地点。所有的元数据都保存在内存中,前两种类型也会以记录变更日志的方式记录在系统日志文件中。
文件系统的存储和管理都交给了FSNameSystem类,我们就看看他的注释:
/***************************************************
* FSNamesystem does the actual bookkeeping work for the // 此类为datanode做实际的簿记工作
* DataNode.
*
* It tracks several important tables.
*
* 1) valid fsname --> blocklist (kept on disk, logged) // 文件系统命名空间到数据块列表的映射,保存在磁盘上并记录日志
* 2) Set of all valid blocks (inverted #1) // 合法数据块集合,上面的逆关系
* 3) block --> machinelist (kept in memory, rebuilt dynamically from reports) // 数据块到datanode的映射,保存在内存中,由datanode上报动态重建
* 4) machine --> blocklist (inverted #2) // datanode上保存的数据块列表,上面的逆关系
* 5) LRU cache of updated-heartbeat machines 近期最少使用缓存队列,保存datanode的心跳信息
***************************************************/
FSNamesystem 有一个FSDirectory成员变量,它保存文件名到数据块列表的映射,类中有添加文命名空间,添加文件,添加数据块,创建目录等操作。
下面是数据块相关的方法
@Override // FSNamesystemMBean
@Metric
public long getPendingReplicationBlocks() { // 返回正在复制的数据块
return blockManager.getPendingReplicationBlocksCount();
}
@Override // FSNamesystemMBean
@Metric
public long getUnderReplicatedBlocks() { // 返回需要复制的数据块
return blockManager.getUnderReplicatedBlocksCount();
}
/** Returns number of blocks with corrupt replicas */
@Metric({"CorruptBlocks", "Number of blocks with corrupt replicas"})
public long getCorruptReplicaBlocks() { // 返回损坏的数据块
return blockManager.getCorruptReplicaBlocksCount();
}
@Override // FSNamesystemMBean
@Metric
public long getScheduledReplicationBlocks() { // 返回当前正在处理的数据块复制数目
return blockManager.getScheduledReplicationBlocksCount();
}
@Override
@Metric
public long getPendingDeletionBlocks() { // 返回正在删除的数据块数目
return blockManager.getPendingDeletionBlocksCount();
}
@Metric
public long getExcessBlocks() { // 返回超过配额的数据块数目
return blockManager.getExcessBlocksCount();
}
// HA-only metric
@Metric
public long getPostponedMisreplicatedBlocks() { // 返回延期或错过复制的数据块数目,仅在ha的情况下
return blockManager.getPostponedMisreplicatedBlocksCount();
}