8 Note sulla selezione dei processi negli item proc.mem e proc.num
Processi che modificano la propria command line
Alcuni programmi usano la modifica della propria command line come metodo per visualizzare la loro attività corrente. Un utente può vedere l'attività eseguendo i comandi ps e top. Esempi di tali programmi includono PostgreSQL, Sendmail, Zabbix.
Vediamo un esempio da Linux. Supponiamo di voler monitorare un numero di processi di Zabbix agent.
Il comando ps mostra i processi di interesse come
$ 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]
...
La selezione dei processi per nome e utente funziona:
$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd,zabbix]'
6
Ora rinominiamo l'eseguibile zabbix_agentd in zabbix_agentd_30 e riavviamolo.
ps ora mostra
$ 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]
...
Ora la selezione dei processi per nome e utente produce un risultato errato:
$ zabbix_get -s localhost -k 'proc.num[zabbix_agentd_30,zabbix]'
1
Perché una semplice rinomina dell'eseguibile con un nome più lungo porta a un risultato così diverso?
Zabbix agent inizia controllando il nome del processo. Viene aperto il file /proc/<pid>/status e viene controllata la riga Name. Nel nostro caso le righe Name sono:
$ 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
Il nome del processo nel file status viene troncato a 15 caratteri.
Un risultato simile si può vedere con il comando 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
...
Ovviamente, questo non è uguale al valore del parametro name zabbix_agentd_30 del nostro proc.num[]. Non riuscendo a far corrispondere il nome del processo dal file status, Zabbix agent passa al file /proc/<pid>/cmdline.
Come l'agent vede il file "cmdline" può essere illustrato eseguendo il comando
$ 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>...
Nel nostro caso i file /proc/<pid>/cmdline contengono byte null invisibili e non stampabili, usati per terminare le stringhe nel linguaggio C. In questo esempio i byte null sono mostrati come "<NUL>".
Zabbix agent controlla "cmdline" per il processo principale e prende zabbix_agentd_30, che corrisponde al valore del nostro parametro name zabbix_agentd_30. Quindi il processo principale viene conteggiato dall'item proc.num[zabbix_agentd_30,zabbix].
Quando controlla il processo successivo, l'agent prende zabbix_agentd_30: collector [idle 1 sec] dal file cmdline e questo non corrisponde al nostro parametro name zabbix_agentd_30. Quindi viene conteggiato solo il processo principale, che non modifica la propria command line. Gli altri processi agent modificano la propria command line e vengono ignorati.
Questo esempio mostra che il parametro name non può essere usato in proc.mem[] e proc.num[] per selezionare i processi in questo caso.
Per l'item proc.get[], quando Zabbix agent controlla "cmdline" per il nome del processo, userà solo la parte del nome che inizia dall'ultima barra e termina al primo spazio o ai due punti. Il nome del processo ricevuto dal file cmdline verrà usato solo se il suo inizio corrisponde completamente al nome abbreviato del processo nel file status. L'algoritmo è lo stesso sia per il nome del processo nel filtro sia per quello nell'output JSON.
L'uso del parametro cmdline con un'espressione regolare appropriata produce un risultato corretto:
$ zabbix_get -s localhost -k 'proc.num[,zabbix,,zabbix_agentd_30[ :]]'
6
Prestare attenzione quando si usano gli item proc.get[], proc.mem[] e proc.num[] per monitorare programmi che modificano le proprie command line.
Prima di inserire i parametri name e cmdline negli item proc.get[], proc.mem[] e proc.num[], può essere utile testare i parametri usando l'item proc.num[] e il comando ps.
Thread del kernel Linux
I thread non possono essere selezionati con il parametro cmdline negli item proc.get[], proc.mem[] e proc.num[]
Prendiamo come esempio uno dei thread del kernel:
$ ps -ef| grep kthreadd
root 2 0 0 09:33 ? 00:00:00 [kthreadd]
Può essere selezionato con il parametro name del processo:
$ zabbix_get -s localhost -k 'proc.num[kthreadd,root]'
1
Ma la selezione tramite il parametro cmdline del processo non funziona:
$ zabbix_get -s localhost -k 'proc.num[,root,,kthreadd]'
0
Il motivo è che Zabbix agent prende l'espressione regolare specificata
nel parametro cmdline e la applica al contenuto di
/proc/<pid>/cmdline del processo. Per i thread del kernel, i file
/proc/<pid>/cmdline sono vuoti. Pertanto, il parametro cmdline non trova mai corrispondenza.
Conteggio dei thread negli item proc.mem[] e proc.num[]
I thread del kernel Linux vengono conteggiati dall'item proc.num[], ma non riportano
memoria nell'item proc.mem[]. Per esempio:
$ 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.
Ma cosa succede se esiste un processo utente con lo stesso nome di un thread del kernel? In tal caso potrebbe apparire così:
$ 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[] ha conteggiato sia il thread del kernel sia il processo utente.
proc.mem[] riporta la memoria solo per il processo utente e considera la
memoria del thread del kernel come se fosse 0. Questo è diverso dal caso
precedente, in cui veniva riportato ZBX_NOTSUPPORTED.
Prestare attenzione quando si utilizzano gli item proc.mem[] e proc.num[] se il nome del programma
coincide con quello di uno dei thread.
Prima di inserire parametri negli item proc.mem[] e proc.num[], si
consiglia di testare i parametri usando l'item proc.num[] e il comando ps.