[comment]: # translation:outdated

[comment]: # ({new-75dc9168})
# 9 Заметки по выбору процессов в элементах данных proc.mem и proc.num

[comment]: # ({/new-75dc9168})

[comment]: # ({new-93778d6f})
#### Процессы, меняющие свои командную строку

Некоторые программы используют изменение своих командных стро как метод
отображения своей текущей активности. Пользователь может просматривать
эту активность при выполнении команд `ps` и `top`. Примеры таких
программ включают *PostgreSQL*, *Sendmail*, *Zabbix*.

Давайте рассмотрим пример с Linux. Давайте предположим, что мы хотим
наблюдать количество процессов Zabbix агента.

Команда `ps` отобразит интересующие процессы

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

Выбор процессов по имени и пользователю делает свое дело:

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

Теперь выбор процессов по имени и пользователю выдает неправильный
результат:

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

Очевидно, что этот вывод не идентичен нашему `proc.num[]` значению
`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`, которое соответствует значению `zabbix_agentd_30`
нашего параметра `имя`. Таким образом, основной процесс засчитывается
элементом данных `proc.num[zabbix_agentd_30,zabbix]`.

При проверке следующего процесса, агент берет
`zabbix_agentd_30: collector [idle 1 sec]` из файла `cmdline` и оно не
соответствует нашему `zabbix_agentd_30` параметра `имя` . То есть,
засчитывается только основной процесс, который не меняет свою командную
строку. Другие процессы агента модифицируют свои командные строки и они
игнорируются.

Этот пример показывает, что в этом случае параметр `имя` нельзя
использовать в `proc.mem[]` и `proc.num[]` для выбора процессов.

Использование параметра `cmdline` с надлежащим регулярным выражением
даст правильный результат:

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

Будьте осторожны в использовании элементов данных `proc.mem[]` и
`proc.num[]` при наблюдении за программами, которые модифицируют свои
командные строки.

Перед тем как поместить параметры `имя` и `cmdline` в элементах данных
`proc.mem[]` и `proc.num[]`, вы мозможно захотите протестировать эти
параметры, используя элемент данных `proc.num[]` и команду `ps`.

[comment]: # ({/new-93778d6f})

[comment]: # ({new-0ff11097})
#### Потоки ядра Linux

[comment]: # ({/new-0ff11097})

[comment]: # ({new-3588d8df})
##### Нельзя выбрать потоки при помощи `cmdline` параметров в элементах данных `proc.mem[]` и `proc.num[]`

Давайте возьмем в качестве примера один из потоков ядра:

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

Его можно выбрать при помощи параметра `имя`:

    $ 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`
никогда не совпадет.

[comment]: # ({/new-3588d8df})

[comment]: # ({new-8d1ef0a6})
##### Вычисление потоков в элементах данных `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.mem[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[]` и команду `ps`.

[comment]: # ({/new-8d1ef0a6})
