
Я хочу иметь возможность отслеживать количество открытых файлов в Linux. В настоящее время я подсчитываю количество файлов в /proc/<pid>/fd
и fdinfo
.
У моего балансировщика нагрузки около миллиона FD. Так что на выполнение уходит около 20 секунд.
Однако это приводит к высокой загрузке процессора:47.18% [kernel] [k] __d_lookup
Есть ли более эффективный способ получить это число?
решение1
Для выделенного балансировщика нагрузки я бы отслеживал общее количество файлов, открытых в системе, вместо того, чтобы тратить ресурсы ввода-вывода и ЦП, подсчитывая их по процессам. Оставшиеся открытые файлы нежелательными процессами должны быть бессмысленным значением для предполагаемого результата.
Чтобы узнать, сколько файлов открыто в системе Linux, нет необходимости их подсчитывать; ядро Linux отслеживает, сколько файлов оно открыло.
Чтобы узнать это, выполните:
cat /proc/sys/fs/file-nr | awk ' { print $1 } '
или
sysctl fs.file-nr | awk ' { print $1 } '
Это гораздо эффективнее, чем подсчет всех файлов, открытых с помощью вывода lsof
, который будет проходить по всем /proc/$PID/fd
каталогам и отрицательно скажется на ресурсах ввода-вывода и ЦП вашей системы.
решение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
задач, которые попадают на ЦП, и периодическое отображение последних из этих счетчиков.
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");
}
Однако это приведет к потере всего, что не находится на ЦП; для получения полного списка потребуется полный обход процессов, а затем задач, хотя это может оказаться слишком медленным или слишком дорогим, если у вас миллионы 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