0%

HDFS 中 atime 与 mtime 解析

HDFS 中 atime 和 mtime


转载来源

1
2
3
作者:混绅士
链接:http://bigdatadecode.club/HDFS%E4%B8%ADatime%E5%92%8Cmtime.html
来源:HDFS中atime与mtime解析

前言

如果不知道 atime、mtime 的建议先了解下 Linux 中 atime 和 mtime,这样有助于学习 HDFS 中 atime 与 mtime

查看

转载文章中未介绍如何查看 HDFS atime、mtime,因此说明下。

跟 Linux 一样,也是使用 stat 命令来查看

用法: hadoop fs -stat [format] <path> ...

以指定的格式打印有关 处的文件/目录的统计信息。格式接受八进制(%a)和符号(%A),字节(%b)文件大小,类型(%F),所有者组名称(%g),名称(%n),块大小(%o),复制(%r),
所有者用户名(%u),访问日期(%x,%X)和修改日期(%y,%Y)。%x和%y将UTC日期显示为“yyyy-MM-dd HH:mm:ss”,并且%X和%Y显示自1970年1月1日UTC以来的毫秒数。如果未指定格式,则默认使用%y。 —— https://www.jianshu.com/p/49d89c197310

如查看 HBase 根目录

1
2
$ hadoop fs -stat "type:%F perm:%a %u:%g size:%b mtime:%y atime:%x name:%n" /hbase
type:directory perm:755 hbase:hbase size:0 mtime:2020-01-14 12:54:42 atime:1970-01-01 00:00:00 name:hbase

分析

先来了解下 HDFS 中的这 atime 与 mtime 的变化规则

在看代码之前,先想下 atime 和 mtime 有可能在哪些地方会修改

hdfs底层api对文件都有哪些操作?

无非就是读写两种操作,读肯定修改的是atime,写修改的是mtime,是否修改atime还得确认。
这里我们还漏掉一种操作,那就是mv。

atime

去年写过一篇文章 HDFS read解析(一)之Open文件流介绍HDFS读操作流程,这里就不再累赘了,直接贴出关键代码。(有兴趣的同学可以自行查看)

这里还是简单说下读的流程:客户端向NN发起一个读请求,NN将相关的block信息返回给客户端,客户端再与对应的DN建立连接读取信息。
在这个过程中,先与NN交互然后再与DN交互,那么每个文件的atime相关元数据信息都存在NN中,那么atime相关的修改也肯定发生在与NN交互的这个过程中。

从之前的文章中可知入口函数是 FSNamesystem.getBlockLocations,关键代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
LocatedBlocks getBlockLocations(String clientMachine, String srcArg,
long offset, long length) throws IOException {
...
if (res.updateAccessTime()) {
String src = srcArg;
writeLock();
final long now = now();
try {
final INodesInPath iip = dir.resolvePath(pc, src);
src = iip.getPath();
INode inode = iip.getLastINode();
// 再次判断是否可以更新atime
boolean updateAccessTime = inode != null &&
now > inode.getAccessTime() + getAccessTimePrecision();
if (!isInSafeMode() && updateAccessTime) {
// 设置atime
boolean changed = FSDirAttrOp.setTimes(dir,
inode, -1, now, false, iip.getLatestSnapshotId());
if (changed) {
getEditLog().logTimes(src, -1, now);
}
}
} catch (Throwable e) {
LOG.warn("Failed to update the access time of " + src, e);
} finally {
writeUnlock(operationName);
}
}
...
}

res.updateAccessTime() 决定了是否更新atime,其值是在getBlockLocationsInt中赋值的,代码如下

1
2
3
boolean updateAccessTime = isAccessTimeSupported() && !isInSafeMode()
&& !iip.isSnapshot()
&& now > inode.getAccessTime() + getAccessTimePrecision();

其中关键的因素是isAccessTimeSupported()getAccessTimePrecision(),这个两个方法都与accessTimePrecision有关,
此值是由dfs.namenode.accesstime.precision设置的,默认是3600000。

当此值大于0,isAccessTimeSupported()返回true,getAccessTimePrecision()得到的值是dfs.namenode.accesstime.precision的值。

从上述代码中可以看出更新atime的一个条件是两次读取间隔相隔dfs.namenode.accesstime.precision秒,默认是1小时。

这里遗留两个问题:

  1. 新建文件时atime如何赋值
  2. 修改文件内容时atime如何赋值

关于这个两个问题我在下一节在写流程中解答。请继续向下看

mtime

同样去年也写过一篇关于写的文章HDFS write解析介绍HDFS读操作流程,这里就不再累赘了,直接贴出关键代码。(有兴趣的同学可以自行查看)

写相关的操作包括create、close和append
写文件有两种方式,一种是调用create(Path)方法,另一种是调用append(Path)方法

create

通过调用create(Path),最终会调用FSDirectory.addFile方法,
在此方法中会new一个INodeFile,此时会设置 mtime 和 atime 为同一个值,代码如下:

1
2
3
4
5
6
7
8
9
10
INodesInPath addFile(INodesInPath existing, String localName, PermissionStatus
permissions, short replication, long preferredBlockSize,
String clientName, String clientMachine)
throws FileAlreadyExistsException, QuotaExceededException,
UnresolvedLinkException, SnapshotAccessControlException, AclException {
long modTime = now();
INodeFile newNode = newINodeFile(allocateNewInodeId(), permissions, modTime,
modTime, replication, preferredBlockSize);
...
}

有打开一个文件就有关闭一个文件,接下来看下关闭文件时 atime 和 mtime 会有什么变化。

close

closeFile()finalizeINodeFileUnderConstruction中调用,在此方法中会设置mtime,看下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void finalizeINodeFileUnderConstruction(String src,
INodeFile pendingFile, int latestSnapshot) throws IOException {
...
pendingFile.toCompleteFile(now());
...
closeFile(src, pendingFile);
...
}

// INodeFile.java
public INodeFile toCompleteFile(long mtime) {
Preconditions.checkState(isUnderConstruction(),
"file is no longer under construction");
FileUnderConstructionFeature uc = getFileUnderConstructionFeature();
if (uc != null) {
assertAllBlocksComplete();
removeFeature(uc);
this.setModificationTime(mtime);
}
return this;
}

从代码中可以看出,close文件时只对mtime进行了修改。

append

append只是打开一个文件流,并不会修改mtime或者atime,只是在close的时候修改mtime

结论

atime

  1. 两次读间隔大于默认的1小时时,更新atime。默认间隔通过dfs.namenode.accesstime.precision控制。
  2. 新建一个文件时atime赋值为当前时间(注意,当关闭一个文件时atime不会修改)

mtime

  1. 新建一个文件时mtime赋值为当前时间(同时会修改atime)
  2. 关闭一个文件时mtime赋值为当前时间(此时并不会修改atime)