我希望能够监控Linux中打开文件的数量。目前我正在计算/proc/<pid>/fd
和中的文件数量fdinfo
。
我的负载均衡器有大约一百万个 FD。所以这最终需要大约 20 秒来执行。
然而,这会导致 CPU 使用率高:47.18% [kernel] [k] __d_lookup
有没有更有效的方法来获取这个数字?
答案1
对于专用的负载均衡器,我会跟踪系统中打开的文件总数,而不是浪费 I/O 和 CPU 资源按进程对它们进行计数。不需要的进程剩余的打开文件对于预期结果来说应该是无意义的值。
要了解Linux系统全局打开的文件数,无需统计; Linux 内核会跟踪它打开的文件数量。
要知道这一点,请运行:
cat /proc/sys/fs/file-nr | awk ' { print $1 } '
或者
sysctl fs.file-nr | awk ' { print $1 } '
这比计算使用 的输出打开的所有文件要高效得多lsof
,后者会遍历所有/proc/$PID/fd
目录,并对系统 I/O / CPU 资源产生负面影响。
答案2
简单的:
lsof | wc -l
将告诉您系统中打开的文件数量。
答案3
此 SystemTap 代码对于您的用例来说效率如何?这不是一个完美的视图,因为它只跟踪从开始时开始的变化(因此在开始之前打开的任何内容都会被错过),并且需要额外的工作以使输出更清晰或更合适。
global procfdcount
probe begin {
printf("begin trace...\n\n")
}
probe syscall.open {
procfdcount[pid()]++
}
probe syscall.close {
p = pid()
procfdcount[p]--
if (procfdcount[p] < 0) {
procfdcount[p] = 0
}
}
probe kprocess.exit {
p = pid()
if (p in procfdcount) {
delete procfdcount[p]
}
}
probe timer.s(60) {
foreach (p in procfdcount- limit 20) {
printf("%d %lu\n", p, procfdcount[p])
}
printf("\n")
}
通过类似的方式运行:
... (install systemtap here) ...
# stap-prep
... (fix any reported systemtap issues here) ...
# stap procfdcount.stp
这种方法的缺点是需要识别所有“打开的文件”(套接字等),然后通过适当的系统调用挂钩(如果可用)调整计数;以上仅跟踪文件文件。另一种选择是调用task_open_file_handles
进入 CPU 的任务,并定期显示最新的计数。
global taskopenfh
probe begin {
printf("begin trace...\n\n");
}
probe scheduler.cpu_on {
p = pid();
if (p == 0) next;
taskopenfh[p] = task_open_file_handles(pid2task(p));
}
probe timer.s(60) {
foreach (p in taskopenfh-) {
printf("%d %lu\n", p, taskopenfh[p]);
}
delete taskopenfh;
printf("\n");
}
但这会错过任何不在 CPU 上的东西;完整的列表需要完整的流程和任务,尽管如果您有数百万个 FD,这可能会太慢或太昂贵。
而且这些探针似乎不稳定,所以也许将来会使用 eBPF 或其他东西?例如 Centos 7 上的第二个在一段时间后爆炸了
ERROR: read fault [man error::fault] at 0x0000000000000008 (((&(fs->fdt))))
near identifier 'task_open_file_handles' at
/usr/share/systemtap/tapset/linux/task.stp:602:10