[comment]: # ({b3f6bc92-c42d1f48})
# 8 Hinweise zur Auswahl von Prozessen in proc.mem- und proc.num-Datenpunkten

[comment]: # ({/b3f6bc92-c42d1f48})

[comment]: # ({e9ff6ad6-93778d6f})
#### 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.

:::noteclassic
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.

[comment]: # ({/e9ff6ad6-93778d6f})

[comment]: # ({0ff11097-0ff11097})
#### Linux-Kernel-Threads

[comment]: # ({/0ff11097-0ff11097})

[comment]: # ({7212f400-3588d8df})
##### 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.

[comment]: # ({/7212f400-3588d8df})

[comment]: # ({8d1ef0a6-8d1ef0a6})
##### 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.

[comment]: # ({/8d1ef0a6-8d1ef0a6})
