为什么 cat 命令查看文件不会修改 atime | Linux 中国
作者 | Lujun9972
今天在 QQ 群里有人问了一个问题:
“为什么用
cat
查看文件内容后不会修改它的 atime 呢?”
我试了一下,发现真的是这样的!例如下面这个例子
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: 2018-10-10 21:15:35.195471306 +0800
-------------------------------
Access: (0600/-rw-------) Uid: ( 1000/lujun9972) Gid: ( 1000/lujun9972)
Access: 2018-10-10 21:15:40.198804743 +0800
这跟我们所熟知的 atime(访问时间)的说法不一样啊。
经过一番探查,最终从 Criticism of atime[1] 中发现了原因。
根据 Criticism of atime[1] 的说法,读取文件要修改 atime 本身是一件很不合理的事情,因为要修改文件的 atime 就意味着要对磁盘进行写操作。首先,在只读文件系统上你根本不可能修改文件的 atime,更重要的是这增加了磁盘 IO 数量。
为了提高磁盘性能,我们可以完全禁止 atime 的修改(参看 mount
的 --noatime
和 --nodiratime
选项),但这会破坏 POSIX 兼容性,而且某些备份软件需要通过对比 atime 和 mtime/ctime (修改时间/创建时间)的时间来判断是否需要进行备份。
针对这个问题,Linux 内核 2.6.20 开始为 mount
引入了一个 --relatime
选项,并从 2.6.30 开始这一选项默认是开启的。
当开启了 --relatime
选项后,只有当 atime < mtime 或 atime < ctime 时,才会去更新 atime。通过这种方式,一方面可以大幅度减少 atime 引起的磁盘写操作,另一方面又保证了备份软件不受到影响,可谓非常精妙了。
下面这段关于 --relatime
的说明取自 man mount
:
relatime
相对于 inode 的修改或更改时间来更新它的访问时间。仅当先前的访问时间早于当前修改或更改时间时,才会更新访问时间。 (与 noatime 类似,但它不会破坏 mutt 或其他需要知道文件自上次修改后是否已被读取的应用程序)
从 Linux 2.6.30 开始,内核默认使用此选项提供的行为(除非指定了 noatime),并且需要 strictatime 选项才能获得传统语义。 此外,自 Linux 2.6.30 起,如果文件的上次访问时间超过 1 天,则该文件的最后访问时间将始终更新。
另外,Linux 内核 4.0 开始引入了一个新选项 --lazytime
。它可以让更新 atime 的操作缓存在内存中,然后当该文件有非时间相关的 IO 要写入时以其更新到磁盘中。同时它也能设置超过多长时间后强制更新 atime。通过这种方式,--lazytime
能做到在不影响性能的情况下保持 POSIX 兼容性。