Linux不默认记录文件访问频次,因atime通常被禁用;inotifywait可监听IN_ACCESS事件实现轻量监控,但有漏计风险;bpftrace能精准跟踪read系统调用并关联进程,是唯一无侵入低开销方案;lsof+stat适合事后推断热点文件。

Linux本身不默认记录文件被谁、何时、读了多少次——atime(访问时间)字段虽存在,但多数系统已禁用或挂载为relatime,仅在修改或mtime更新时才更新,无法用于真实访问频次统计。
用 inotifywait 实时捕获文件读取事件
这是最轻量、最可控的用户态方案,适合短期盯梢单个或少量关键文件(如配置、证书、日志模板)。
-
inotifywait不捕获read()系统调用本身,而是监听IN_ACCESS事件——但注意:该事件仅在文件被打开且带O_RDONLY且后续有实际读操作时触发,且依赖内核是否启用CONFIG_INOTIFY_USER(现代发行版基本都开) - 命令示例:
inotifywait -m -e access /etc/hosts,每次读取会输出一行/etc/hosts ACCESS - 要统计频次,可管道进
awk:inotifywait -m -e access /var/log/nginx/access.log 2>/dev/null | awk '{c++} END{print c}'(需 Ctrl+C 中断后才输出) - 陷阱:它不区分进程、不记录偏移、不捕获 mmap 读取;若文件被多个进程高频轮询(如监控脚本),容易漏计或误计
用 bpftrace 跟踪 sys_enter_read 和 sys_enter_pread64
真正能抓到“谁在读哪个文件”的方法,必须下到系统调用层。eBPF 是目前唯一无侵入、低开销的可行路径。
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
- 核心逻辑是:在
sys_enter_read触发时,通过pid_tgid获取进程名,再用curtask->files->fdt->fd[fd]反查文件路径——但注意:内核 5.10+ 已移除直接访问fdt的能力,需改用bpf_probe_read_kernel+ 偏移计算,或依赖struct file的f_path.dentry和f_path.mnt - 更稳妥的简化做法:只统计按文件描述符号(
fd)读取次数,并关联comm(进程名):sudo bpftrace -e 'tracepoint:syscalls:sys_enter_read { @reads[comm, args->fd] = count(); } interval:s:10 { print(@reads); clear(@reads); }' - 若需路径,可用
cat /proc/PID/fd/FD_NUM手动查,但无法在 eBPF 中实时完成;建议先用此脚本抓出高频fd和comm组合,再人工验证 - 性能影响:每秒几万次 read 调用下,bpftrace 默认聚合开销极低;但开启
printf或大量字符串拷贝会显著拖慢
用 lsof + stat 辅助推断“热文件”
这不是实时统计,但对排查长期热点非常有效——尤其当文件被持续打开并反复读取(如数据库索引、共享内存段、长连接日志)。
-
lsof +D /path列出指定目录下所有被打开的文件及其 PID,再配合ps看进程行为;高频读取的文件往往长期处于 “open but not closed” 状态 - 结合
stat -c "%x %y %z %n" *查看最近访问(%x)、修改(%y)、变更(%z)时间,若%x频繁更新而%y几乎不变,大概率是只读热点 - 注意:
atime在noatime或relatime挂载选项下不会更新,此时该法失效;检查用mount | grep " $(df . | tail -1 | awk '{print $1}') " - 一个实用组合:
lsof -nP -w +D /var/log | awk '$5 ~ /REG/ && $9 ~ /\.log$/ {print $2, $9}' | sort | uniq -c | sort -nr | head -10—— 抓出被最多进程打开的 log 文件
真正的文件访问频次统计没有银弹:inotifywait 简单但粗糙,bpftrace 精准但需内核支持和调试耐心,lsof + 时间戳是事后推理利器。最容易被忽略的是挂载选项对 atime 的静默屏蔽——别一上来就怀疑工具不准,先 mount 看一眼。

















