10 Remarques sur la sélection des processus dans les éléments proc.mem et proc.num

Processus modifiant leur ligne de commande

Certains programmes utilisent la modification de leur ligne de commande pour afficher leur activité actuelle. Un utilisateur peut voir l'activité en exécutant les commandes ps et top. PostgreSQL, Sendmail, Zabbix sont des exemples de tels programmes.

Voyons un exemple de Linux. Supposons que nous souhaitons surveiller un certain nombre de processus d'agent Zabbix.

La commande ps montre les processus qui nous intéressent

$ 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/ZBXNEXT-1078/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]
       ...

La sélection des processus par nom et utilisateur fait le travail :

$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd,zabbix]'
       6

Maintenant, renommons l'exécutable zabbix_agentd en zabbix_agentd_30 et redémarrons-le.

ps montre maintenant

$ 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/ZBXNEXT-1078/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]
       ...

Maintenant, la sélection des processus par nom et utilisateur produit un résultat incorrect :

$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd_30,zabbix]'
       1

Pourquoi un simple changement de nom d'exécutable en un nom plus long conduit à un résultat assez différent ?

L'agent Zabbix commence par vérifier le nom du processus. Le fichier /proc/<pid>/status est ouvert et la ligne Name est cochée. Dans notre cas, les lignes de Name sont :

$ 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

Le nom du processus dans le fichier status est tronqué à 15 caractères.

Un résultat similaire peut être vu avec la commande ps :

$ 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
        ...

Évidemment, proc.num[] n'est pas égal à notre valeur de paramètre de name : zabbix_agentd_30. N'ayant pas réussi à faire correspondre le nom de processus du fichier status, l'agent Zabbix se tourne vers le fichier /proc/<pid>/cmdline.

La manière dont l'agent voit le fichier "cmdline" peut être illustrée avec l'exécution d'une commande

$ 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/ZBXNEXT-1078/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>...

Les fichiers /proc/<pid>/cmdline dans notre cas contiennent des octets nuls invisibles et non imprimables, utilisés pour terminer les chaînes en langage C. Les octets nuls sont représentés par "<NUL>" dans cet exemple.

L'agent Zabbix vérifie dans "cmdline" le processus principal et prend zabbix_agentd_30, qui correspond à la valeur du paramètre name : zabbix_agentd_30. Ainsi, le processus principal est compté par l'élément 'proc.num[zabbix_agentd_30,zabbix].

Lors de la vérification du processus suivant, l'agent prend zabbix_agentd_30: collector [idle 1 sec] dans le fichier cmdline et il ne correspond pas à notre paramètre name zabbix_agentd_30. Ainsi, seul le processus principal qui ne modifie pas sa ligne de commande est compté. D'autres processus d'agent modifient leur ligne de commande et sont ignorés.

Cet exemple montre que le paramètre name ne peut pas être utilisé dans proc.mem[] et proc.num[] pour la sélection de processus dans ce cas.

L'utilisation du paramètre cmdline avec une expression régulière appropriée produit un résultat correct :

$ zabbix_get -s localhost -k 'proc.num[,zabbix,,zabbix_agentd_30[ :]]'
       6

Soyez prudent lorsque vous utilisez les éléments proc.mem[] et proc.num[] pour surveiller les programmes qui modifient leurs lignes de commande.

Avant de placer les paramètres name et cmdline dans les éléments proc.mem[] et proc.num[], vous pouvez tester les paramètres à l'aide de l'élément proc.num[] et de la commande ps.

Threads du noyau Linux

Les threads ne peuvent pas être sélectionnés avec le paramètre cmdline dans les éléments proc.mem[] et proc.num ]

Prenons comme exemple l'un des threads du noyau :

$ ps -ef| grep kthreadd
       root         2     0  0 09:33 ?        00:00:00 [kthreadd]

Il peut être sélectionné avec le paramètre name du processus :

$ zabbix_get -s localhost -k 'proc.num[kthreadd,root]'
       1

Mais avec la sélection par processus, le paramètre cmdline ne fonctionne pas :

$ zabbix_get -s localhost -k 'proc.num[,root,,kthreadd]'
       0

La raison en est que l'agent Zabbix prend l'expression régulière spécifiée dans le paramètre cmdline et l'applique au contenu du processus /proc/<pid>/cmdline. Pour les threads du noyau, leurs fichiers /proc/<pid>/cmdline sont vides. Ainsi, le paramètre cmdline ne correspond jamais.

Comptage des threads dans les éléments proc.mem[] et proc.num[]

Les threads du noyau Linux sont comptés par l'élément proc.num[] mais ne signalent pas la mémoire dans l'élément proc.mem[]. Par exemple :

$ 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.

Mais que se passe-t-il si un processus utilisateur porte le même nom qu'un thread du noyau ? Alors cela pourrait ressembler à ceci :

$ 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[] compte à la fois le thread du noyau et le processus utilisateur. proc.mem[] rapporte la mémoire pour le processus utilisateur uniquement et compte la mémoire du thread du noyau comme si elle était à 0. Cela est différent du cas ci-dessus lorsque ZBX_NOTSUPPORTED a été signalé.

Soyez prudent lorsque vous utilisez les éléments proc.mem[] et proc.num[] si le nom du programme correspond à l'un des threads.

Avant de mettre des paramètres dans les éléments proc.mem[] et proc.num[], vous pouvez les tester à l'aide de l'élément proc.num[] et de la commande ps.