Você está visualizando a documentação da versão de desenvolvimento, que pode estar incompleta.
Esta página foi traduzida automaticamente. Se você notar um erro, selecione-o e pressione Ctrl+Enter para reportá-lo aos editores.

8 Notas sobre a seleção de processos em itens proc.mem e proc.num

Processos que modificam sua linha de comando

Alguns programas usam a modificação da linha de comando como um método para exibir sua atividade atual. Um usuário pode ver a atividade executando os comandos ps e top. Exemplos de tais programas incluem PostgreSQL, Sendmail, Zabbix.

Vamos ver um exemplo no Linux. Vamos supor que queremos monitorar o número de processos do agent do Zabbix.

O comando ps mostra os processos de interesse como

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

Selecionar processos por nome e usuário faz o trabalho:

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

Agora vamos renomear o executável zabbix_agentd para zabbix_agentd_30 e reiniciá-lo.

O ps agora 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/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]                   
       ...

Agora selecionar processos por nome e usuário produz um resultado incorreto:

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

Por que uma simples renomeação do executável para um nome mais longo levou a um resultado tão diferente?

O agent do Zabbix começa verificando o nome do processo. O arquivo /proc/<pid>/status é aberto e a linha Name é verificada. No nosso caso, as linhas Name são:

$ 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

O nome do processo no arquivo status é truncado para 15 caracteres.

Um resultado semelhante pode ser visto com o 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
        ...

Obviamente, isso não é igual ao valor do parâmetro name do nosso proc.num[] zabbix_agentd_30. Não conseguindo corresponder ao nome do processo do arquivo status, o agent do Zabbix recorre ao arquivo /proc/<pid>/cmdline.

Como o agent vê o arquivo "cmdline" pode ser ilustrado executando um 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/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>...

Os arquivos /proc/<pid>/cmdline no nosso caso contêm bytes nulos invisíveis e não imprimíveis, usados para terminar strings na linguagem C. Os bytes nulos são mostrados como "<NUL>" neste exemplo.

O agent do Zabbix verifica o "cmdline" para o processo principal e pega um zabbix_agentd_30, que corresponde ao valor do nosso parâmetro name zabbix_agentd_30. Portanto, o processo principal é contado pelo item proc.num[zabbix_agentd_30,zabbix].

Ao verificar o próximo processo, o agent pega zabbix_agentd_30: collector [idle 1 sec] do arquivo cmdline e ele não corresponde ao nosso parâmetro name zabbix_agentd_30. Portanto, apenas o processo principal que não modifica sua linha de comando é contado. Outros processos do agent modificam sua linha de comando e são ignorados.

Este exemplo mostra que o parâmetro name não pode ser usado em proc.mem[] e proc.num[] para selecionar processos neste caso.

Para o item proc.get[], quando o agent do Zabbix verifica o "cmdline" para o nome do processo, ele usará apenas parte do nome começando a partir da última barra e até o primeiro espaço ou sinal de dois pontos. O nome do processo recebido do arquivo cmdline só será usado se seu início corresponder completamente ao nome do processo encurtado no arquivo status. O algoritmo é o mesmo tanto para o nome do processo no filtro quanto na saída JSON.

Usar o parâmetro cmdline com uma expressão regular adequada produz um resultado correto:

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

Tenha cuidado ao usar os itens proc.get[], proc.mem[] e proc.num[] para monitorar programas que modificam suas linhas de comando.

Antes de colocar os parâmetros name e cmdline nos itens proc.get[], proc.mem[] e proc.num[], você pode querer testar os parâmetros usando o item proc.num[] e o comando ps.

Threads do kernel do Linux

Threads não podem ser selecionados com o parâmetro cmdline em itens proc.get[], proc.mem[] e proc.num[]

Vamos tomar como exemplo uma das threads do kernel:

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

Ela pode ser selecionada com o parâmetro name do processo:

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

Mas a seleção pelo parâmetro cmdline do processo não funciona:

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

A razão é que o agent do Zabbix pega a expressão regular especificada no parâmetro cmdline e a aplica ao conteúdo do processo /proc/<pid>/cmdline. Para threads do kernel, seus arquivos /proc/<pid>/cmdline estão vazios. Portanto, o parâmetro cmdline nunca corresponde.

Contagem de threads em itens proc.mem[] e proc.num[]

Threads do kernel do Linux são contadas pelo item proc.num[], mas não relatam memória no item proc.mem[]. Por exemplo:

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

Mas o que acontece se houver um processo de usuário com o mesmo nome de uma thread do kernel? Então poderia ser assim:

$ 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[] contou tanto a thread do kernel quanto o processo de usuário. proc.mem[] relata a memória apenas para o processo de usuário e conta a memória da thread do kernel como se fosse 0. Isso é diferente do caso acima, quando ZBX_NOTSUPPORTED foi relatado.

Tenha cuidado ao usar os itens proc.mem[] e proc.num[] se o nome do programa coincidir com o de uma thread.

Antes de colocar parâmetros nos itens proc.mem[] e proc.num[], você pode querer testar os parâmetros usando o item proc.num[] e o comando ps.