8 proc.memおよびproc.numアイテムでのプロセスの選択に関する注意
コマンドラインを変更するプロセス
一部のプログラムは、現在のアクティビティを表示する方法としてコマンドラインの変更を使用します。ユーザーは 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/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/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[] の 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/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] でカウントされます。
次のプロセスをチェックする際、エージェントは cmdline ファイルから zabbix_agentd_30: collector [idle 1 sec] を取得しますが、これは name パラメータ zabbix_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[] アイテムの使用に注意してください。
proc.get[]、proc.mem[]、proc.num[] アイテムに name および cmdline パラメータを設定する前に、proc.num[] アイテムや ps コマンドを使ってパラメータをテストすることをお勧めします。
Linuxカーネルスレッド
proc.get[]、proc.mem[]、proc.num[]アイテムのcmdlineパラメータでスレッドを選択できません
カーネルスレッドの1つを例にとってみましょう:
$ 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.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が報告された上記の場合とは異なります。
プログラム名がスレッドの1つと一致する場合は、proc.mem[]およびproc.num[]アイテムを使用するときに注意してください。
パラメータをproc.mem[]およびproc.num[]アイテムに入れる前に、proc.num[]アイテムとpsコマンドを使用してパラメータをテストすることをお勧めします。