10 Uwagi dotyczące wybierania procesów w pozycjach proc.mem i proc.num

Procesy modyfikujące swoją linię poleceń

Niektóre programy używają modyfikacji swojej linii poleceń jako metody wyświetlania bieżącej aktywności. Użytkownik może zobaczyć tę aktywność, uruchamiając polecenia ps i top. Przykłady takich programów to PostgreSQL, Sendmail, Zabbix.

Zobaczmy przykład z systemu Linux. Załóżmy, że chcemy monitorować liczbę procesów agenta Zabbix.

Polecenie ps pokazuje interesujące nas procesy jako:

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

Wybór procesów według nazwy i użytkownika spełnia zadanie:

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

Teraz zmieńmy nazwę pliku wykonywalnego zabbix_agentd na zabbix_agentd_30 i zrestartujmy go.

ps teraz pokazuje:

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

Teraz wybór procesów według nazwy i użytkownika daje nieprawidłowy wynik:

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

Dlaczego prosta zmiana nazwy pliku wykonywalnego na dłuższą nazwę prowadzi do zupełnie innego wyniku?

Agent Zabbix zaczyna od sprawdzenia nazwy procesu. Otwiera plik /proc/<pid>/status i sprawdza linię Name. W naszym przypadku linie Name to:

$ 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

Nazwa procesu w pliku status jest skrócona do 15 znaków.

Podobny wynik można zobaczyć za pomocą polecenia 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
        ...

Oczywiście, to nie jest równe naszej wartości parametru name w proc.num[] zabbix_agentd_30. Nie udało się dopasować nazwy procesu z pliku status, więc agent Zabbix przechodzi do pliku /proc/<pid>/cmdline.

Jak agent widzi plik "cmdline", można zobrazować, uruchamiając polecenie:

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

Pliki /proc/<pid>/cmdline w naszym przypadku zawierają niewidoczne, nieczytelne bajty null, używane do zakończenia ciągów w języku C. W tym przykładzie bajty null są pokazane jako "<NUL>".

Agent Zabbix sprawdza "cmdline" dla głównego procesu i bierze zabbix_agentd_30, który pasuje do naszej wartości parametru name zabbix_agentd_30. Tak więc główny proces jest liczony przez pozycję proc.num[zabbix_agentd_30,zabbix].

Podczas sprawdzania kolejnego procesu, agent bierze zabbix_agentd_30: collector [idle 1 sec] z pliku cmdline i nie spełnia to naszego parametru name zabbix_agentd_30. Tak więc tylko główny proces, który nie modyfikuje swojej linii poleceń, jest liczony. Inne procesy agenta modyfikują swoją linię poleceń i są ignorowane.

Ten przykład pokazuje, że parametr name nie może być używany w proc.mem[] i proc.num[] do wybierania procesów w tym przypadku.

Użycie parametru cmdline z odpowiednim wyrażeniem regularnym daje prawidłowy wynik:

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

Bądź ostrożny, używając pozycji proc.mem[] i proc.num[] do monitorowania programów, które modyfikują swoje linie poleceń.

Przed wstawieniem parametrów name i cmdline do pozycji proc.mem[] i proc.num[], możesz chcieć przetestować parametry za pomocą pozycji proc.num[] i polecenia ps.

Wątki jądra Linuksa

Wątki nie mogą być wybrane za pomocą parametru cmdline w pozycjach proc.mem[] i proc.num[]

Weźmy jako przykład jeden z wątków jądra:

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

Może być wybrany za pomocą parametru name procesu:

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

Ale wybór za pomocą parametru cmdline procesu nie działa:

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

Powodem jest to, że agent Zabbix bierze wyrażenie regularne określone w parametrze cmdline i stosuje je do zawartości procesu /proc/<pid>/cmdline. Dla wątków jądra ich pliki /proc/<pid>/cmdline są puste. Więc parametr cmdline nigdy się nie zgadza.

Liczenie wątków w pozycjach proc.mem[] i proc.num[]

Wątki jądra Linux są liczone przez pozycję proc.num[], ale nie raportują pamięci w pozycji proc.mem[]. Na przykład:

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

Ale co się stanie, jeśli istnieje proces użytkownika o tej samej nazwie co wątek jądra? Wtedy może to wyglądać tak:

$ 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[] policzył zarówno wątek jądra, jak i proces użytkownika. proc.mem[] raportuje pamięć tylko dla procesu użytkownika i liczy pamięć wątku jądra jakby była równa 0. To różni się od powyższego przypadku, kiedy zgłoszono ZBX_NOTSUPPORTED.

Bądź ostrożny, używając pozycji proc.mem[] i proc.num[] jeśli nazwa programu przypadkowo odpowiada jednemu z wątków.

Przed wstawieniem parametrów do pozycji proc.mem[] i proc.num[], możesz chcieć przetestować parametry za pomocą pozycji proc.num[] i polecenia ps.