[comment]: # translation:outdated

[comment]: # ({b3f6bc92-c42d1f48})
# 8 在 proc.mem 和 proc.num items 监控项中选择进程

[comment]: # ({/b3f6bc92-c42d1f48})

[comment]: # ({cfc9a7c7-93778d6f})
#### 修改其命令行的进程

一些程序使用修改它们的命令行作为显示当前活动的方用户可以通过运行 `ps` 和
`top` 命令来查看活动。这些程序的例子包括 *PostgreSQL*、*Sendmail*、*Zabbix*。

让我们来看一个 Linux 的例子。假设我们想要监控许多 Zabbix agent 进程。

`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 agent 启动时检查进程名。 `/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[]` `name` 参数值 `zabbix_agentd_30`并不一样。Zabbix agent 从 `status` 文件中匹配进程名失败后，会转到 `/proc/<pid>/cmdline` 文件。

agent 如何看待 "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 agent 检查 "cmdline" ，得到 `zabbix_agentd_30` 值，该值匹配我们的 `name` 参数值 `zabbix_agentd_30`。因此，主进程会被监控项 `proc.num[zabbix_agentd_30,zabbix]` 计数。

当检查下一进程时，agent 从 `cmdline` 文件中得到 `zabbix_agentd_30: collector [idle 1 sec]` ，但不匹配 `name` 参数值 `zabbix_agentd_30`。所以，只有不改变命令行的主进程被计数，其他的 agent 进程改变了命令行而被忽略。

这个例子展示了 `name` 参数不能用在 `proc.mem[]` 和 `proc.num[]` 监控项中来选择进程。

:::noteclassic
对于 `proc.get[]` 监控项，当 Zabbix agent 检查 "cmdline" 中的进程名称时，它只会使用从最后一个斜杠开始直到第一个空格或冒号的名称的一部分。 仅当其开头完全匹配 `status` 文件中的缩短进程名称时，才会使用从 cmdline 文件接收的进程名称。 过滤器中的进程名称和 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[]` 监控项和 `ps` 命令来测试参数。

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

[comment]: # ({0ff11097-0ff11097})
#### Linux 内核线程

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

[comment]: # ({7212f400-3588d8df})
#####  `proc.get[]`、`proc.mem[]` 和 `proc.num[]` 监控项中的 `cmdline` 参数不可以使用线程

让我们以内核线程为例：

    $ 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 agent 采用 `cmdline` 参数中指定的正则表达式，并将其应用于进程的内容 `/proc/<pid>/cmdline`。对于内核线程的 `/proc/<pid>/cmdline` 文件是空的，所以 `cmdline` 参数不会匹配到。

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

[comment]: # ({8d1ef0a6-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]: # ({/8d1ef0a6-8d1ef0a6})
