10 Notes sobre la selecció de processos als elements proc.mem i proc.num

Processos modificant la línia de comandes

Alguns programes empren la modificació de la seva línia de comandes per mostrar la seva activitat actual. Un usuari pot veure l'activitat executant les comandes ps i top. PostgreSQL, Sendmail, Zabbix són exemples d'aquests programes.

Veieu un exemple de Linux. Suposeu que ens cal monitorar un cer nombre de processos d'agent Zabbix.

La comanda ps mostra els processos que ens calen

$ 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 selecció dels processos per nom d'usuari fan aquesta feina:

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

Mentrestant, reanomenem l'executable zabbix_agentd a zabbix_agentd_30 i el reengeguem.

ps ensenya ara:

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

Mentrestant, la selecció dels processos per nom i usuari produeix un resultat incorrecte:

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

Per què un simple canvi de nom d'executable cap a un nom més llarg ens porta a un resultat ben diferent?

L'agent Zabbix comença verificant el nom dels processos. L'arxiu /proc/<pid>/status és obert i la línia Name marcada. En el nostre cas, les línies de Name són:

$ 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

El nom dels processos dins l'arxiu status es retalla a 15 caràcters.

Un resultat semblant es pot veure amb la comanda 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
        ...

Evidentment, proc.num[] no és igual al nostre valor del paràmetre name : zabbix_agentd_30. Com ha fallat la coincidència del nom de processos de l'arxiu status, l'agent Zabbix passa al fitxer /proc/<pid>/cmdline.

Com l'agent veu l'arxiu "cmdline" es pot il·lustrar amb l'execució d'una comanda

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

Els arxius /proc/<pid>/cmdline del nostre cas contenen octets nuls invisibles i no imprimibles, emprats per acabar les cadenes en llenguatge C. Els octets nuls es representen amb "<NUL>" en aquest exemple.

L'agent Zabbix verifica a la "cmdline" el procés principal i pren zabbix_agentd_30, que correspón al valor del paràmetre name: zabbix_agentd_30. Així, el procés principal es compta per l'element 'proc.num[zabbix_agentd_30,zabbix].

Quan es verifica el següent procés, l'agent pren zabbix_agentd_30: col·lector [idle 1 sec] dins l'arxiu cmdline i no correspon pas al nostre paràmetre name zabbix_agentd_30. Així, sobre el procés principal que no modifica pas la línia de comandes, es compta. Altres processos d'agent modifiquen la seva línia de comandes i s'ignoren.

Aquest exemple mostra que el paràmetre name no pot pas ésser emprat a proc.mem[] i proc.num[] per la selecció de processos en aquest cas.

L'ús del paràmetre cmdline amb una expressió regular apropiada produeix un resultat correcte:

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

Sigueu prudent emprant els elements proc.mem[] i proc.num[] per monitorar els programes que modifiquen le seves línies de comandes.

Abans de posar els paràmetres name i cmdline dins els elements proc.mem[] i proc.num[], podeu provar els paràmetres amb l'ajuda de l'element proc.num[] i de la comanda ps.

Fils del kernel de Linux

els fils no es poden pas triar amb el paràmetre cmdline dins els elements proc.mem[] i proc.num[]

Preneu com a exemple un dels fils del kernel:

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

Es pot triar amb el paràmetre name dels processos:

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

Però amb la selecció per processos, el paràmetre cmdline no funciona pas:

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

La raó en que l'agent Zabbix pren l'expressió regular especificada al paràmetre cmdline i l'aplica al contenidor de processos /proc/<pid>/cmdline. Per als fils de kernel, els fitxers /proc/<pid>/cmdline són buits. Així, el paràmetre cmdline no coincidirà mai.

El recompte dels fils dels elements proc.mem[] i proc.num[]

Els fils de kernel Linux es compten amb l'element proc.num[], però no assenyalen pas la memòria de l'element proc.mem[]. Per 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.

Però què passa si un procés d'usuari porta el mateix nom que un fil de kernel? S'assemblarà a això:

$ 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[] compta tant els fils de kernel com els processos d'usuari. proc.mem[] reporta la memòria només per als processos d'usuaris i compta la memòria del fil de kernel com si tingués estat 0. Aquesta és diferent del cas que hi ha aquí dalt, quan ZBX_NOTSUPPORTED ha estat reportat.

Mireu d'ésser prudents quan empreu els elements proc.mem[] i proc.num[] si el nom del programa correspon a un dels fils.

Abans d'afegir els paràmetres als elements proc.mem[] i proc.num[], podeu testar amb l'ajuda de l'element proc.num[] i la comanda ps.