8 Напомене о одабиру процеса у proc.mem и proc.num ставкама

Процеси који модификују своју командну линију

Неки програми користе модификацију своје командне линије као метод за приказивање њихове тренутне активности. Корисник може да види активност покретањем ps и top команде. Примери таквих програма укључују PostgreSQL, Sendmail, Zabbix.

Погледајмо пример из Linux-a. Претпоставимо да желимо да надгледамо број процеса Zabbix агента.

Команда ps приказује процесе од интереса као

$ ps -fu zabbix
       UID PID PPID C STIME TTYTIME 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]
       ...

Избор процеса по имену и кориснику обавља посао:

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

Сада преименујмо извршну датотеку zabbix_agentd у zabbix_agentd_30 и поново покренимо.

ps сада приказује

$ ps -fu zabbix
       UID PID PPID C STIME TTYTIME 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]      
       ...

Сада одабир процеса по имену и кориснику даје нетачан резултат:

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

Зашто једноставно преименовање извршног фајла у дуже име доводи до прилично другачијег резултата?

Zabbix агент почиње са провером имена процеса. /proc/<pid>/status датотека се отвара и линија Name је означена. У нашем случају Name линије су:

$ 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

Име процеса у датотеци status је скраћено на 15 карактера.

Сличан резултат се може видети са командом ps:

$ ps -u zabbix
         PID TTYTIME 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
        ...

Очигледно, то није једнако нашој вредности параметра proc.num[] name zabbix_agentd_30. Пошто није успео да се подудара са именом процеса из status датотеке коју Zabbix агент претвара у /proc/<pid>/cmdline датотеку.

Како агент види датотеку "cmdline" може се илустровати покретањем команда

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

/proc/<pid>/cmdline датотеке у нашем случају садрже невидљиве, нештампане нулте бајтове, који се користе за завршавање стрингова у C језику. Нулти бајтови су приказани као "<NUL>" у овом примеру.

Zabbix агент проверава "cmdline" за главни процес и узима zabbix_agentd_30, који одговара нашој вредности параметра name zabbix_agentd_30. Дакле, главни процес се рачуна по ставкама proc.num[zabbix_agentd_30,zabbix].

Приликом провере следећег процеса, агент узима `zabbix_agentd_30: collector [idle 1 sec] из датотекеcmdlineи не испуњава наш параметарnamezabbix_agentd_30`. Дакле, само се рачуна главни процес који не мења своју командну линију. Остали агентски процеси мењају своју командну линију и игноришу се.

Овај пример показује да параметар name не може да се користи у proc.mem[]иproc.num[]` за избор процеса у овом случају.

За proc.get[] ставку, када Zabbix агент провери "cmdline" за име процеса, користиће само део имена почевши од последње косе црте па до првог знака размака или двотачке. Име процеса примљено из cmdline датотеке ће се користити само ако се његов почетак у потпуности поклапа са скраћеним именом процеса у датотеци status. Алгоритам је исти за име процеса у филтеру и за JSON излаз.

Коришћење параметра cmdline са одговарајућим регуларним изразом производи тачан резултат:

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

Будите пажљиви када користите ставке proc.get[], proc.mem[] и proc.num[] за надгледање програма који модификују своје командне линије.

Пре него што ставите параметре name и cmdline у ставке proc.get[], proc.mem[] и proc.num[], можда ћете желети да тестирате параметре користећи proc.num[] item и ps команде.

Linux kernel threads

Нити се не могу изабрати параметром cmdline у ставкама proc.get[], proc.mem[] и proc.num[]

Узмимо као пример једну од нити језгра:

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

Може се изабрати помоћу параметра name процеса:

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

Али избором параметра cmdline процес не ради:

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

Разлог је тај што Zabbix агент узима наведени регуларни израз у параметру cmdline и примењује га на садржај процеса /proc/<pid>/cmdline. За нити кернела њихове /proc/<pid>/cmdline датотеке су празне. Дакле, параметар cmdline се никада не подудара.

Бројање нити у proc.mem[] и proc.num[] ставкама

Нити Linux кернела се броје према proc.num[] ставки, али се не извештава меморија у ставци proc.mem[]. на пример:

$ 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.num[kthreadd]'
       ZBX_NOTSUPPORTED: Cannot get amount of "VmSize" memory.

Али шта се дешава ако постоји кориснички процес са истим именом као кернел нит? Тада би то могло изгледати овако:

$ 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[] је бројао и нит кернела и кориснички процес. proc.mem[] пријављује меморију само за кориснички процес и броји меморију нити кернела као да је 0. Ово се разликује од случаја изнад када је пријављен ZBX_NOTSUPPORTED.

Будите пажљиви када користите ставке proc.mem[] и proc.num[] ако се име програма случајно подудара са једном од нити.

Пре него што ставите параметре у ставке proc.mem[] и proc.num[], можда желите да тестирате параметре користећи ставку proc.num[] item и ps команду.