8 Hinweise zur Auswahl von Prozessen in proc.mem- und proc.num-Datenpunkten
Prozesse, die ihre Befehlszeile verändern
Einige Programme verwenden das Verändern ihrer Befehlszeile als Methode, um
ihre aktuelle Aktivität anzuzeigen. Ein Benutzer kann die Aktivität sehen, indem er die Befehle ps
und top ausführt. Beispiele für solche Programme sind PostgreSQL,
Sendmail, Zabbix.
Sehen wir uns ein Beispiel unter Linux an. Nehmen wir an, wir möchten eine Anzahl von Zabbix-Agent-Prozessen überwachen.
Der Befehl ps zeigt die relevanten Prozesse wie folgt an:
$ ps -fu zabbix
UID PID PPID C STIME TTY TIME CMD
...
zabbix 6318 1 0 12:01 ? 00:00:00 sbin/zabbix_agentd -c /home/zabbix/zabbix_agentd.conf
zabbix 6319 6318 0 12:01 ? 00:00:01 sbin/zabbix_agentd: collector [idle 1 sec]
zabbix 6320 6318 0 12:01 ? 00:00:00 sbin/zabbix_agentd: listener #1 [waiting for connection]
zabbix 6321 6318 0 12:01 ? 00:00:00 sbin/zabbix_agentd: listener #2 [waiting for connection]
zabbix 6322 6318 0 12:01 ? 00:00:00 sbin/zabbix_agentd: listener #3 [waiting for connection]
zabbix 6323 6318 0 12:01 ? 00:00:00 sbin/zabbix_agentd: active checks #1 [idle 1 sec]
...
Die Auswahl von Prozessen nach Name und Benutzer erfüllt ihren Zweck:
$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd,zabbix]'
6
Benennen wir nun die ausführbare Datei zabbix_agentd in zabbix_agentd_30 um und
starten sie neu.
ps zeigt nun Folgendes an:
$ ps -fu zabbix
UID PID PPID C STIME TTY TIME CMD
...
zabbix 6715 1 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30 -c /home/zabbix/zabbix_agentd.conf
zabbix 6716 6715 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30: collector [idle 1 sec]
zabbix 6717 6715 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30: listener #1 [waiting for connection]
zabbix 6718 6715 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30: listener #2 [waiting for connection]
zabbix 6719 6715 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30: listener #3 [waiting for connection]
zabbix 6720 6715 0 12:53 ? 00:00:00 sbin/zabbix_agentd_30: active checks #1 [idle 1 sec]
...
Nun liefert die Auswahl von Prozessen nach Name und Benutzer ein falsches Ergebnis:
$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd_30,zabbix]'
1
Warum führt ein einfaches Umbenennen der ausführbaren Datei in einen längeren Namen zu einem so anderen Ergebnis?
Der Zabbix-Agent beginnt mit der Prüfung des Prozessnamens. Die Datei /proc/<pid>/status
wird geöffnet und die Zeile Name wird geprüft. In unserem Fall lauten die Name-Zeilen:
$ grep Name /proc/{6715,6716,6717,6718,6719,6720}/status
/proc/6715/status:Name: zabbix_agentd_3
/proc/6716/status:Name: zabbix_agentd_3
/proc/6717/status:Name: zabbix_agentd_3
/proc/6718/status:Name: zabbix_agentd_3
/proc/6719/status:Name: zabbix_agentd_3
/proc/6720/status:Name: zabbix_agentd_3
Der Prozessname in der Datei status wird auf 15 Zeichen gekürzt.
Ein ähnliches Ergebnis ist mit dem Befehl ps zu sehen:
$ ps -u zabbix
PID TTY TIME CMD
...
6715 ? 00:00:00 zabbix_agentd_3
6716 ? 00:00:01 zabbix_agentd_3
6717 ? 00:00:00 zabbix_agentd_3
6718 ? 00:00:00 zabbix_agentd_3
6719 ? 00:00:00 zabbix_agentd_3
6720 ? 00:00:00 zabbix_agentd_3
...
Offensichtlich ist das nicht gleich unserem name-Parameterwert zabbix_agentd_30 von
proc.num[]. Nachdem der Zabbix-Agent den Prozessnamen aus der Datei status nicht
abgleichen konnte, greift er auf die Datei /proc/<pid>/cmdline zurück.
Wie der Agent die Datei "cmdline" sieht, lässt sich durch Ausführen des folgenden Befehls veranschaulichen:
$ for i in 6715 6716 6717 6718 6719 6720; do cat /proc/$i/cmdline | awk '{gsub(/\x0/,"<NUL>"); print};'; done
sbin/zabbix_agentd_30<NUL>-c<NUL>/home/zabbix/zabbix_agentd.conf<NUL>
sbin/zabbix_agentd_30: collector [idle 1 sec]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
sbin/zabbix_agentd_30: listener #1 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
sbin/zabbix_agentd_30: listener #2 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
sbin/zabbix_agentd_30: listener #3 [waiting for connection]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
sbin/zabbix_agentd_30: active checks #1 [idle 1 sec]<NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>...
Die Dateien /proc/<pid>/cmdline enthalten in unserem Fall unsichtbare, nicht druckbare
Null-Bytes, die in der Sprache C zum Beenden von Zeichenketten verwendet werden. Die Null-Bytes
werden in diesem Beispiel als "<NUL>" dargestellt.
Der Zabbix-Agent prüft "cmdline" für den Hauptprozess und entnimmt
zabbix_agentd_30, was mit unserem name-Parameterwert
zabbix_agentd_30 übereinstimmt. Daher wird der Hauptprozess vom Datenpunkt
proc.num[zabbix_agentd_30,zabbix] gezählt.
Bei der Prüfung des nächsten Prozesses entnimmt der Agent
zabbix_agentd_30: collector [idle 1 sec] aus der Datei cmdline, und
dies entspricht nicht unserem name-Parameter zabbix_agentd_30. Daher wird nur der
Hauptprozess gezählt, der seine Befehlszeile nicht verändert. Andere
Agent-Prozesse verändern ihre Befehlszeile und werden ignoriert.
Dieses Beispiel zeigt, dass der Parameter name in diesem Fall nicht in
proc.mem[] und proc.num[] zur Auswahl von Prozessen verwendet werden kann.
Beim Datenpunkt proc.get[] verwendet der Zabbix-Agent, wenn er "cmdline" auf den Prozessnamen prüft, nur den Teil des Namens ab dem letzten Schrägstrich bis zum ersten Leerzeichen oder Doppelpunkt. Der aus der Datei cmdline erhaltene Prozessname wird nur verwendet, wenn sein Anfang vollständig mit dem gekürzten Prozessnamen in der Datei status übereinstimmt. Der Algorithmus ist sowohl für den Prozessnamen im Filter als auch in der JSON-Ausgabe derselbe.
Die Verwendung des Parameters cmdline mit einem geeigneten regulären Ausdruck liefert ein
korrektes Ergebnis:
$ zabbix_get -s localhost -k 'proc.num[,zabbix,,zabbix_agentd_30[ :]]'
6
Seien Sie vorsichtig bei der Verwendung von proc.get[]-, proc.mem[]- und proc.num[]-Datenpunkten zur Überwachung
von Programmen, die ihre Befehlszeilen verändern.
Bevor Sie die Parameter name und cmdline in proc.get[]-, proc.mem[]- und proc.num[]-Datenpunkten verwenden, sollten Sie die Parameter möglicherweise mit dem
Datenpunkt proc.num[] und dem Befehl ps testen.
Linux-Kernel-Threads
Threads können in proc.get[]-, proc.mem[]- und proc.num[]-Datenpunkten nicht mit dem Parameter cmdline ausgewählt werden
Nehmen wir als Beispiel einen der Kernel-Threads:
$ ps -ef| grep kthreadd
root 2 0 0 09:33 ? 00:00:00 [kthreadd]
Er kann mit dem Prozessparameter name ausgewählt werden:
$ zabbix_get -s localhost -k 'proc.num[kthreadd,root]'
1
Die Auswahl über den Prozessparameter cmdline funktioniert jedoch nicht:
$ zabbix_get -s localhost -k 'proc.num[,root,,kthreadd]'
0
Der Grund dafür ist, dass der Zabbix Agent den im Parameter cmdline angegebenen regulären Ausdruck verwendet und ihn auf den Inhalt von /proc/<pid>/cmdline des Prozesses anwendet. Bei Kernel-Threads sind ihre Dateien /proc/<pid>/cmdline leer. Daher liefert der Parameter cmdline niemals eine Übereinstimmung.
Zählung von Threads in proc.mem[]- und proc.num[]-Datenpunkten
Linux-Kernel-Threads werden vom proc.num[]-Datenpunkt gezählt, melden jedoch
keinen Speicher im proc.mem[]-Datenpunkt. Zum Beispiel:
$ ps -ef | grep kthreadd
root 2 0 0 09:51 ? 00:00:00 [kthreadd]
$ zabbix_get -s localhost -k 'proc.num[kthreadd]'
1
$ zabbix_get -s localhost -k 'proc.mem[kthreadd]'
ZBX_NOTSUPPORTED: Cannot get amount of "VmSize" memory.
Aber was passiert, wenn es einen Benutzerprozess mit demselben Namen wie ein Kernel-Thread gibt? Dann könnte es so aussehen:
$ ps -ef | grep kthreadd
root 2 0 0 09:51 ? 00:00:00 [kthreadd]
zabbix 9611 6133 0 17:58 pts/1 00:00:00 ./kthreadd
$ zabbix_get -s localhost -k 'proc.num[kthreadd]'
2
$ zabbix_get -s localhost -k 'proc.mem[kthreadd]'
4157440
proc.num[] zählte sowohl den Kernel-Thread als auch den Benutzerprozess.
proc.mem[] meldet Speicher nur für den Benutzerprozess und zählt den
Speicher des Kernel-Threads so, als wäre er 0. Dies unterscheidet sich von dem oben
beschriebenen Fall, in dem ZBX_NOTSUPPORTED gemeldet wurde.
Seien Sie vorsichtig bei der Verwendung von proc.mem[]- und proc.num[]-Datenpunkten, wenn der Programmname zufällig mit einem der Threads übereinstimmt.
Bevor Sie Parameter in proc.mem[]- und proc.num[]-Datenpunkte eintragen, sollten Sie die Parameter möglicherweise mit dem proc.num[]-Datenpunkt und dem Befehl ps testen.