Эффективный мониторинг количества открытых ФД на процесс?

Эффективный мониторинг количества открытых ФД на процесс?

Я хочу иметь возможность отслеживать количество открытых файлов в 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

Связанный контент