为什么cat命令查看文件不会修改atime
今天在QQ群里有人问了一个问题:“为什么用cat查看文件内容后不会修改它的atime呢?”
我试了一下,发现真的是这样的!例如下面这个例子,在CentOS7上执行
export LANG=C cd /tmp tmpfile=$(mktemp) echo "-------------------------------" >${tmpfile} stat ${tmpfile} |grep Access sleep 5 cat ${tmpfile} stat ${tmpfile} |grep Access
Access: (0600/-rw-------) Uid: ( 1000/lujun9972) Gid: ( 1000/lujun9972) Access: 2019-01-15 13:08:34.519887362 +0800 ------------------------------- Access: (0600/-rw-------) Uid: ( 1000/lujun9972) Gid: ( 1000/lujun9972) Access: 2019-01-15 13:08:34.519887362 +0800
这跟我们所熟知的atime的说法不一样啊。
经过一番探查,最终从 Criticism of atime 中发现了原因。
根据 Criticism of atime 的说法,读取文件要修改atime本身是一件很不合理的事情,因为要修改文件的atime就意味着要对磁盘进行写操作。 首先,在只读文件系统上你根本不可能修改文件的atime,更重要的是这增加了磁盘IO数量.
为了提高磁盘性能,我们可以完全禁止atime的修改(参看mount的noatime和nodiratime选项),但这会破坏POSIX兼容性,而且某些备份软件需要通过对比atime和mtime/ctime的时间来判断是否需要进行备份。
针对这个问题,Linux kernel2.6.20开始为mount引入了一个 relatime
选项,并从 2.6.30 开始这一选项默认是开启的。
当开启了 relatime
选项后,只有当 atime<mtime
或 atime<ctime
时,才会去更新 atime
.
通过这种方式,一方面可以大幅度减少atime引起的磁盘写操作,另一方面又保证了备份软件不受到影响,可谓非常精妙了。
下面这段关于relatime的说明取自 man mount
relatime Update inode access times relative to modify or change time. Access time is only updated if the previous access time was earlier than the current modify or change time. (Similar to noatime, but it doesn't break mutt or other applications that need to know if a file has been read since the last time it was modified.) Since Linux 2.6.30, the kernel defaults to the behavior pro‐ vided by this option (unless noatime was specified), and the strictatime option is required to obtain traditional seman‐ tics. In addition, since Linux 2.6.30, the file's last access time is always updated if it is more than 1 day old.
另外,Linux kernel4.0开始引入了一个新选项 lazytime
. 它可以让更新atime的操作缓存在内存中,然后当该文件有非时间相关的IO要写入时以其更新到磁盘中。
同时它也能设置超过多长时间后强制更新atime. 通过这种方式, lazytime
能做到在不影响性能的情况下保持POSIX兼容性。