
Ich möchte die Anzahl der geöffneten Dateien in Linux überwachen können. Derzeit zähle ich die Anzahl der Dateien in /proc/<pid>/fd
und fdinfo
.
Mein Load Balancer hat etwa eine Million FDs. Die Ausführung dauert also etwa 20 Sekunden.
Dies führt jedoch zu einer hohen CPU-Auslastung:47.18% [kernel] [k] __d_lookup
Gibt es eine effizientere Möglichkeit, diese Nummer zu erhalten?
Antwort1
Für einen dedizierten Load Balancer würde ich die Gesamtzahl der im System geöffneten Dateien verfolgen, anstatt E/A- und CPU-Ressourcen zu verschwenden, indem ich sie pro Prozess zähle. Die verbleibenden offenen Dateien von unerwünschten Prozessen sollten für das beabsichtigte Ergebnis ein bedeutungsloser Wert sein.
Um die global vom Linux-System geöffneten Dateien zu kennen, ist es nicht notwendig, sie zu zählen; der Linux-Kernel verfolgt, wie viele Dateien er geöffnet hat.
Um dies herauszufinden, führen Sie Folgendes aus:
cat /proc/sys/fs/file-nr | awk ' { print $1 } '
oder
sysctl fs.file-nr | awk ' { print $1 } '
Dies ist viel effizienter als das Zählen aller mit der Ausgabe von geöffneten Dateien lsof
, das alle Verzeichnisse durchläuft /proc/$PID/fd
und sich negativ auf die E/A-/CPU-Ressourcen Ihres Systems auswirkt.
Antwort2
Das Einfache:
lsof | wc -l
gibt die Anzahl der im System geöffneten Dateien an.
Antwort3
Wie effizient ist dieser SystemTap-Code für Ihren Anwendungsfall? Es ist keine perfekte Ansicht, da Änderungen nur ab dem Beginn verfolgt werden (alles, was vor dem Start geöffnet wurde, würde also übersehen werden) und es wird zusätzliche Arbeit erforderlich sein, um die Ausgabe lesbarer oder geeigneter zu machen.
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")
}
Ausführen über etwas wie:
... (install systemtap here) ...
# stap-prep
... (fix any reported systemtap issues here) ...
# stap procfdcount.stp
Der Nachteil dieser Methode ist, dass alle „offenen Dateien“ (Sockets usw.) identifiziert und die Anzahl dann über entsprechende Systemaufruf-Hooks (falls verfügbar) angepasst werden muss; oben werden nur Dateidateien verfolgt. Eine andere Möglichkeit wäre, task_open_file_handles
Aufgaben aufzurufen, die auf die CPU gelangen, und die aktuellsten dieser Zählungen regelmäßig anzuzeigen.
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");
}
Dabei würde allerdings alles übersehen, was sich nicht auf der CPU befände; für eine vollständige Liste wäre ein vollständiger Durchlauf der Prozesse und dann der Tasks erforderlich, was allerdings zu langsam oder zu teuer sein könnte, wenn Sie Millionen von FDs haben.
Außerdem scheinen diese Sonden nicht stabil zu sein, also vielleicht eBPF oder so etwas in der Zukunft? Beispielsweise explodiert die zweite auf Centos 7 nach einiger Zeit auf
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