どうも、cloudpackかっぱ (@inokara) です。

はじめに

JVM のヒープメモリを sensu で監視するにあたって Jolokia 経由での監視を考えていたのですが、既に java-permgen.rb というプラグインがあったのでそちらを試してみました。

参考

memo

java-permgen.rb の仕組み

ソースコードをざっくり見てみると jps で JVM の PID を取得して、取得した PID を利用して jstat を実行しているようです。また、jstat を実行して PGCMXPU という二つの値を取得して割り算して Permanent 領域の使用率をチェックしているようです。

Sensu Community Plugin 探訪 - java-permgen.rb: 仕組み

上記のようなフローになりますでしょうか…

jps について

jps とはJava 仮想マシンプロセスステータスツール とあります。

上記のドキュメントをもう少し読むと以下のように書かれています。

jps ツールは、ターゲットシステム上で計測された HotSpot Java 仮想マシン (JVM) を一覧表示します。このツールで表示できるレポート情報は、アクセス権を持った JVM に関するものに限定されます。

hostid を指定せずに jps を実行した場合、ローカルホストで計測された JVM が検索されます。hostid を指定して起動した場合、指定されたプロトコルとポートを使用して、指定されたホスト上の JVM を検索します。jstatd プロセスがターゲットホスト上で実行されていると想定されます。

ps コマンドのように実行中の JVM プロセス(ローカル VM 識別子)ID を出力してくれるようです。

試しに Play Framework が動作している環境で root 権限にて jps を実行してみます。

$ sudo su -
Last login: Tue Nov 18 10:41:32 UTC 2014 on pts/0
# jps
2294 NettyServer
2752 Jps

上記のように JVM の ID と共に実行しているアプリケーション名(クラス名、JAR ファイル名等)が出力されました。アプリケーション名の出力を抑制するオプション(-q)もあるようです。

jstat について

jstat とは Java 仮想マシン統計データ監視ツール とあります。

上記のドキュメントを読むと jstat は以下のように書かれています。

jstat ツールは、設置されている HotSpot Java 仮想マシン (JVM) のパフォーマンス統計データを表示します。ターゲット JVM は、仮想マシン識別子、つまり下記の vmid オプションによって識別されます。

jstat は以下のように実行します。

jstat ${jps で出力された ID}

さらに jstat には多くの出力オプションがあり、今回の java-permgem.rb プラグインでは以下のオプションがプラグイン内部で実行されています。

-gcold オプション

Old および Permanent 世代の統計データを出力します。
-gcold オプション付きで実行すると以下のように出力されます。

# jstat -gcold ${ID}
   PC       PU        OC          OU       YGC    FGC    FGCT     GCT
 21248.0  20028.7    699072.0         0.0      0     0    0.000    0.000

各項目は以下の通りです。(ドキュメントより抜粋)

項目 説明
PC Permanent 領域の現在の容量 (KB)
PU Permanent 領域の使用容量 (KB)※ドキュメントでは「使用率」とありますが「使用容量」と修正しました
OC Old 領域(Tenured Generation 又は Old Generation)の現在の容量 (KB)
OU Old 領域(Tenured Generation 又は Old Generation)の使用率 (KB)
YGC 若い世代(Young Generation)の GC イベント数
FGC フル GC イベント数
FGCT フルガベージコレクション時間
GCT ガベージコレクション総時間
-gcpermcapacity オプション

Permanent 世代の統計データを出力します。
-gcpermcapacity オプション付きで実行すると以下のように出力されます。

# jstat -gcpermcapacity ${ID}
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT
   21248.0   262144.0    21248.0    21248.0     0     0    0.000    0.000

各項目は以下の通りです。(ドキュメントより抜粋)

項目 説明
PGCMN Permanent 世代の最小容量 (KB)
PGCMX Permanent 世代の最大容量 (KB)
PGC Permanent 世代の現在の容量 (KB)
PC Permanent 領域の現在の容量 (KB)
YGC 若い世代の GC イベント数
FGC フル GC イベント数
FGCT フルガベージコレクション時間
GCT ガベージコレクション総時間
Java オブジェクトのメモリ領域

上記の Old 領域や Permanent 世代とかなんぞやって思っていたら、こちらの資料に辿り着いたので整理してみました。

領域 説明
New(Young Generaion)領域:ヒープ領域 New 領域は Eden と From と To の領域に分かれる。この領域が不足すると Scavenge GC が頻発する。
Old(Tenured Generation 又は Old Generation)領域:ヒープ領域 New 領域で破棄されなかったオブジェクトが配置される。この領域が不足すると Full GC が行われる。
Permanent 領域:非ヒープ領域 クラス、メソッドの情報が格納される。この領域が不足すると Full GC が行われる。

ふむふむ…あくまでもドキュメントの写経ですのでもっと JVM の勉強をする必要がありそうです…orz

Demo

準備

とりあえず sensu-plugin を入れておきましょう。

sudo gem install sensu-plugin --no-ri --no-rdoc -V

試す

root 権限で実行しましょう。

sudo su -
cd sensu-community-plugins/plugins/java

以下のように実行します。

# ./java-permgen.rb -w 1 -c 2
Java PermGen CRITICAL: Java processes Over PermGen CRIT threshold of 2%:

Critical を発生させる為に閾値を極端に低くしていますが、Critical を検出した JVM の ID(2294)も一緒に出力されています。

ちょっとデバッグ

PUPGCMX を出力させてみました。

# ./java-permgen.rb -w 1 -c 2
"pgcmx: "
"pgcmx: 262144.0"
"pu: 20028.7"
Java PermGen CRITICAL: Java processes Over PermGen CRIT threshold of 2%: 2294
# jstat -gcpermcapacity 2294
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT
   21248.0   262144.0    21248.0    21248.0     0     0    0.000    0.000
# jstat -gcold 2294
   PC       PU        OC          OU       YGC    FGC    FGCT     GCT
 21248.0  20028.7    699072.0         0.0      0     0    0.000    0.000

上記のように PUPGCMX の値が取得されていることが分かります。

それでは…

学んだこと

  • JVM のプロセス ID を取得する場合には jps を利用する
  • jstatで JVM のヒープ領域等の各種リソースを取得可能(オプションは多数あり取得出来る項目が異なる
  • java-permgen.rb プラグインは jstat の異なるオプションから取得する値を算出してチェックを行う

次はどんなプラグインに出会うんでしょうか

次はどんなプラグインに出会うんでしょうか。
非常に楽しみですね。

さよなら、さよなら。

元記事はこちらです。
Sensu Community Plugin 探訪(2)java-permgen.rb を試した