某些程序通过修改其命令行作为显示信息的一种方式 他们的当前活动。用户可以通过运行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_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 agent 从检查进程名称开始。/proc/<pid>/status
file 已开启并检查 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
file 中的进程名称被截断为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
. 未能匹配到来自 status
file 当 Zabbix agent 变为 /proc/<pid>/cmdline
file。
agent如何查看"cmdline"file可以通过运行一个 命令
$ 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会执行 zabbix_agentd_30: collector [idle 1 sec]
来自 cmdline
file 和 它不符合我们的name
参数zabbix_agentd_30
。因此,只有 主进程若未修改其命令行,则会被计入统计。其他 agent进程会修改其命令行参数因而被忽略
此示例表明name
参数无法在 proc.mem[]
和 proc.num[]
用于在此情况下选择进程。
使用带有正确正则表达式的cmdline
参数可生成 正确结果:
在使用proc.mem[]
和proc.num[]
监控项进行监控时需谨慎 修改其命令行参数的程序
在将name
和cmdline
参数放入proc.mem[]
之前 proc.num[]
监控项,您可能需要使用以下参数进行测试 proc.num[]
监控项 和 ps
命令
cmdline
parameter in proc.mem[]
and proc.num[]
items以其中一个内核线程为例:
可以通过进程name
参数进行选择:
但通过进程cmdline
参数选择无效:
原因是Zabbix agent会获取cmdline
参数中指定的正则表达式, 并将其应用于进程/proc/<pid>/cmdline
的内容。对于内核线程, 它们的/proc/<pid>/cmdline
文件为空。因此,cmdline
参数永远无法匹配。
proc.mem[]
and proc.num[]
itemsLinux内核线程会被proc.num[]
监控项计数,但不会在proc.mem[]
监控项中报告memory。例如:
$ 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[]
仅报告用户进程的memory,并将内核线程的memory视为0。这与之前报告ZBX_NOTSUPPORTED的情况不同。
当程序名恰好与某个线程匹配时,使用proc.mem[]
和proc.num[]
监控项需谨慎。
在将参数放入proc.mem[]
和proc.num[]
监控项之前,建议先使用proc.num[]
监控项和ps
命令测试参数。