8 proc.memおよびproc.numアイテムでのプロセスの選択に関する注意

コマンドラインを変更するプロセス

一部のプログラムは、現在の動作状況を表示する方法としてコマンドラインを変更します。ユーザーは pstop コマンドを実行することで、その動作状況を確認できます。そのようなプログラムの例としては、PostgreSQLSendmailZabbix があります。

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 言語で文字列終端に使用される不可視の非表示文字である null バイトが含まれています。この例では null バイトを "<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 に一致しません。そのため、コマンドラインを変更しないメインプロセスだけがカウントされます。他のエージェントプロセスはコマンドラインを変更するため、無視されます。

この例は、このようなケースでは proc.mem[] および proc.num[] でプロセスを選択するために name パラメータを使用できないことを示しています。

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[] アイテムの使用に注意してください。

name および cmdline パラメータを proc.get[]proc.mem[]proc.num[] アイテムに設定する前に、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コマンドを使用してパラメータをテストすることをお勧めします。