Tech Sketch Bucket of Technical Chips by TIS Inc.

zabbixでhadoopクラスタのJVMを監視したい

Pocket

なぜzabbix?

Hadoop監視ツールとしてはAmazon Elastic MapReduceでの利用や、NTTデータが公表した 検証資料 で採用された Ganglia の方が有名ですが、日本ではユーザ会の活動も活発なzabbix を使って監視したい!という方のためのアプローチです。zabbixに強いTISの某I氏が作成したものを引き取ってJVM監視用に拡張しました。
zabbix-server-1.8.5に含まれているzabbix-templateにはjmxを使った定義も格納されているのですが、portの特定等少々面倒なようなので、新たに定義しなおしています。


監視のためにやったこと

基本的にはawkでJVMやリソース情報を取るスクリプト書き、zabbix-agentから呼び出しています。
こんな感じです。

  • ps auxww で取れる情報から、指定のプロセスを実行クラス名でgrep 取得
  • zabbix-agentにこのスクリプトと監視対象のクラス名を渡して、監視

呼び出す監視スクリプトは、現在はマシンリソース用とJVMリソース用の2点用意しました。
今回の動作検証は、下記のマシン上で検証してます。

  • Hadoop 0.20.2-cdh3u0(JDK 1.6.0_25)
  • Linux version 2.6.35.13(Fedora 14)
  • Zabbix Server jp-1.8

1. リソース監視用のhadoop_resource.sh を作る

これは、psの結果から、CPUやメモリの利用率(%)を返してます。

シェルを直接実行すると、こんな結果が返ります。

[root@tc-hadoop02]# ./hadoop_resource.sh org.apache.hadoop.mapred.TaskTracker CPU
0.3

12行目で加算しているのは、org.apache.hadoop.mapred.Childが複数立ちあがるからです。
スロット数(1ノードで動くスレーブプロセス上限)が2以上だと、2つのプロセスが存在するので、2行出力されます。
スクリプトは、その総和を取っているので、CPU使用率が100%を超える環境もありますが、大体の動作状況をみる分にはこれで良しとしてます。

2. JVMの監視用 jvm_stats.sh を作る

上と同じようにpsを用いて、今度はプロセスIDを取ります。これをjstat に渡して、対象JVMの情報を取得します。 jstat はJ2SE5.0以上のJDKに含まれるツールで、以前のバージョンではjvmstatとして提供されていました。jstatの仕様に準じて、JVMの世代毎(Survivor/Eden/Young)のGC実行回数やGC実行時間といったメモリ領域とGCの振舞いを割合細かく監視できます。(参考記事: APサーバからの応答がなくなった、なぜ?―GCをチューニングしよう。―
jvm_stats.shは、直接jstatにプロセスIDとjstatで取れるどの値を見るかを指示しているだけです。今回は、とりあえず世代毎のメモリ比率とGC合計時間のみ例に記載してますが、お好みで拡張して下さい。

3. Hadoop監視環境へシェルを配置

二つのシェルを、zabbix_agentdから見える場所に配置します。
今回はHadoopクラスタを構成するサーバ、スレーブの全ての/home/hadoop/zabbix_template/ に置いています。
/etc/zabbix/zabbix_agentd.confへ下記の記述を追記して、スクリプトの仕様をagent に伝えます。

4. zabbix サーバ側のHadoop 監視テンプレートへ登録

これらを監視項目としてzabbix-serverに登録します。
コンソールを使うか、これらを定義したテンプレートファイルを作ってzabbix_serverにアップロードします。

hadoop_resouce用キー hadoop.resource [org.apache.hadoop.mapred.TaskTracker,CPU]
  • 第一引数が監視対象javaクラス
  • 第二引数がCPU/Memory
jstat用のキー hadoop.jstat [org.apache.hadoop.mapred.TaskTracker,fullgc_count]
  • 第一引数が監視対象javaクラス
  • 第二引数がjstatに渡すパラメータ(スクリプトに準じる)

grep へ渡すjavaクラス名は、一意に特定する為に、パッケージ名付きでクラス名を渡してます。
最後にzabbix-agentを各環境で起動します。

[root@tc-hadoop00]# for i in `seq 1 5`; do ssh tc-hadoop0$i service zabbix-agent start;done;
root@tc-hadoop01's password:<パスワード入力>
...

あとは、お好みでスクリーンを定義して監視して下さい。

実際にSlaveの状態を見てチューニング

実行時のパラメータで処理時間や、mapの重さを調整できるので、モンテカルロ計算で円周率を求めるpi(PiEstimator)というHadoopサンプルを用いました。

[hadoop@tc-hadoop01]# hadoop jar hadoop-0.20.2-examples.jar pi 10000 200000

結果、検証環境4ノードで55分かかりました。
で、Slaveのメモリ状況を見てみます。結構余裕がありCPUも使いきっている様子がありません。
もう少しSlaveのプロセスが効率良くリソースを使ったら速くなりそうです。

hadoop_memory.png

早速ChildのJVMをzabbixで見てみると、残念ながら下記のようにラインを描けるデータが取れていません。

child_jvm.png

Childプロセスの生存期間が短いので、リソースを使いきる前に終わっている、と推測できます。
Childプロセスの生存期間を長くする事を考えます。
org.apache.hadoop.mapred.Childは、処理対象データをブロックサイズ(64Mbyte~)のサイズに分割して、特に指定しなければ、ブロック毎にJVMを起動しmapタスクを実行します。これを改善する方法として、①ブロックサイズを大きくする、②プログラム自体を改変するといった方法もありますが、簡単なので③オプションを指定して、JVMのリソースを再利用、してみます。

 mapred.job.reuse.jvm.num.tasks=-1

指定した数のタスク(JVM)が再利用されますが、-1では、最初にキックしたJVMプロセスをずっと使いまわします。
参考) Map/Reduce Tutorial タスク JVM の再利用

JVMを再利用させると期待通り、55分→13分で終了、JVMの状況も下記のように上手くリソースを使いきれるようになりました。

hadoop_memory_reuse.png

勿論、元々のプログラム中でnew を頻繁に呼べば、GCの発生頻度が増加するかもしれません。実際、reuseオプションを使う前と後ではFullGC Countが0→24となってます。リソース利用状況を見ながら調整するのに利用してみてはどうでしょう。

エンジニア採用中!私たちと一緒に働いてみませんか?