Выбор процессов в элементах данных proc.mem и proc.num

Процессы, изменяющие свою командную строку

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

Пример из Linux. Наблюдение количество процессов Агента.

Команда 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

В данном случае простое переименование исполняемого файла на более длинное имя приводит к совершенно другому результату.

Агент начинает с проверки имени процесса. Открывается файл /proc//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
...

Очевидно, что этот вывод не идентичен значению zabbix_agentd_30 в параметре name ключа proc.num. Не найдя совпадение по имени процесса в файле status, Агент обращается к файлу /proc//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//cmdline содержат невидимые непечатаемые нулевые байты, которые используются для завершения строки в языке C. В этом примере нулевые байты отображаются как .

Агент проверяет cmdline основного процесса и извлекает zabbix_agentd_30, которое соответствует значению zabbix_agentd_30 параметра name. Таким образом, основной процесс учитывается элементом данных proc.numzabbix_agentd_30,zabbix.

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

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

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

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

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

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

Потоки ядра Linux

Нельзя выбрать потоки при помощи параметров 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

Причина такого поведения кроется в том, что Агент берет регулярное выражение, которое указано в параметре cmdline, и применяет его к содержимому относящегося к процессу файла /proc/<pid>/cmdline. В случае потоков ядра их файлы /proc/<pid>/cmdline – пустые. Поэтому параметр cmdline никогда не совпадет.

Потоки ядра Linux подсчитываются элементом данных proc.num, но не сообщают информацию о памяти в элементе данных proc.mem item, например:

$ 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 сообщил информацию о памяти только по пользовательскому процессу и вычислил память потока ядра, как будто оно было нулевым. Это отличается от случая выше, когда сообщалось ZBX_NOTSUPPORTED.

Следует внимательно использовать элементы данных proc.mem и proc.num при совпадении имени процесса с одним из потоков.

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