見習いプログラミング日記

Java EE を中心に色々なことを考えてみます。目指せ本物のプログラマ。

GrowthForecastでJBossの運用状況をグラフ化する

アプリケーションサーバでありがちなトラブルとしてDB接続プールの枯渇がある。原因はチューニングミスやSQLが長時間化してプールにコネクションが返って来ないなど色々とあるが、負荷試験時にモニタリングしておくと多くの問題は事前に検知・対処できる。JBossAS7以降、JBossにはHTTP API経由でサーバの運用状況を示すjsonを取得できる便利な機能がある。今回は、この機能を使って特にトラブルが起こりやすいデータソースの状況を取得し、GrowthForecastでグラフ化できないか考える。

JBossのHTTP 管理API

デフォルトでポート9990からアクセスできる。アクセスには認証が必要で、add-user.shで作成した管理ユーザのアカウントを使う。

以下の例ではデータソース名『PostgresDS』の状態をjson形式で取得する。

curl --digest -D - http://localhost:9990/management --header "Content-Type: application/json" -d '{"operation":"read-resource", "include-runtime":"true" , "address":["subsystem","datasources", "data-source", "PostgresDS", "statistics", "pool"], "json.pretty":1}' -u username:password -o datasource.json

結果は以下の通り。

{
    "outcome" : "success",
    "result" : {
        "ActiveCount" : "25",
        "AvailableCount" : "25",
        "AverageBlockingTime" : "65",
        "AverageCreationTime" : "117",
        "CreatedCount" : "25",
        "DestroyedCount" : "0",
        "InUseCount" : "0",
        "MaxCreationTime" : "335",
        "MaxUsedCount" : "25",
        "MaxWaitCount" : "19",
        "MaxWaitTime" : "220",
        "TimedOut" : "0",
        "TotalBlockingTime" : "83135",
        "TotalCreationTime" : "2940"
    }
}

他にも以下のような項目がjson形式で取得できる。

curl --digest -D - http://localhost:9990/management --header "Content-Type: application/json" -d '{"operation":"read-resource", "include-runtime":"true" , "address":["subsystem","transactions"], "json.pretty":1}' -u username:password -o transaction.json
  • スレッドプールの動作状況(動作スレッド数、平均/最大プールからの取得待ち時間)
curl --digest -D - http://localhost:9990/management --header "Content-Type: application/json" -d '{"operation":"read-resource", "include-runtime":"true" , "address":["subsystem","threads","blocking-bounded-queue-thread-pool", "http-executor"], "json.pretty":1}' -u username:password -o threadpool.txt
curl --digest -D - http://localhost:9990/management --header "Content-Type: application/json" -d '{"operation":"read-resource", "include-runtime":"true" , "address":["core-service","platform-mbean", "type", "memory"], "json.pretty":1}' -u username:password -o javaheap.json

他の例については、middle ware magicの記事が参考になると思う。

運用状況をグラフ化する

運用環境ではJP1やzabbixなどの監視ツールがあるシステムでも、負荷試験を行うようなテスト環境にはない場合も多いと思う。定期的に取得したデータを簡易にグラフ化するために、Web記事で良く見かけるGrowthForecastを使った。

このツールは以下のようにHTTP POSTするだけで、手軽にWebアクセスできるグラフが作成できてとても便利。

# http://example.com/api/:service_name/:section_name/:graph_name
curl -F number=10 http://localhost:5858/api/MyJBoss/datasource/InUseCount

今回はシェルスクリプトで管理APIからjson形式でデータソースの動作状況を取得し、GrowthForcastに向けてPOSTすることでグラフを作成する。絵にすると以下のような構成を作る。

f:id:n_agetsuma:20140317203520p:plain

1. 監視対象項目を考える

一口にデータソースといっても、取得できる項目は色々とあるため、今回は以下の4項目を対象とした。

項目 説明
AverageBlockingTime コネクション取得に関する平均ブロック時間
InUseCount 現在のコネクション使用数
MaxUsedCount 最大コネクション使用数
MaxWaitTime 最大コネクション取得待ち時間

特にInUseCountが常に上限に張り付いていたり、AverageBlokingTimeが1秒を超えるような状態は異常な状態と判断しても良いと思う。遅いSQLがコネクションを使用し続けているか、同時並列処理数に対してコネクション数が少なすぎる可能性が高い。

2. GrowthForecastのセットアップ

公式サイトの手順参照のこと。
growthforecast.pl --data-dir /home/test/growthforecast を実行して、GrowthForecastが起動するまで進める。

3. スクリプトを書く

少し長いが、手元で試しに作ってみたソースを以下に示す。

大まかな流れ。

  1. curlJBossよりデータソースの状態を取得する
  2. jqを使って、jsonから監視した項目を抽出する
  3. 取得したデータをGrowthForecastに送る

jqはコマンドラインベースで、jsonから任意のプロパティ文字列を取得するのに便利なツール。bashではjsonが扱いにくいので、取得したjsonから例えばInUseCount(現在のコネクション使用数)などのプロパティを取得するために使った。

/home/test/monitor.sh

#!/bin/sh

# JBossの管理ユーザ名とパスワード(add-user.sh)
USER=
PASSWORD=

JBOSS_HOME=/home/test/jboss-as-7.1.1.Final
TIME=`date +%Y%m%d%H%M%S`

END_POINT=http://localhost:9990/management
LOG_DIR=${JBOSS_HOME}/standalone/log/runtime/${TIME}

APP_NAME=PerformanceTest
GROWTH_FORCAST_ENDPOINT=http://localhost:5125/api/${APP_NAME}

mkdir -p ${LOG_DIR}

# JBossの管理APIよりデータソース運用状況の取得
curl --digest -D - ${END_POINT} --header "Content-Type: application/json" -d '{"operation":"read-resource", "include-runtime":"true" , "address":["subsystem","datasources","data-source","PostgresDS","statistics","pool"], "json.pretty":1}' -u ${USER}:${PASSWORD} -o ${LOG_DIR}/datasource.json 1>/dev/null 2>/dev/null

# jsonから各種データを抽出する
InUseCount=`/usr/local/bin/jq ".result .InUseCount | tonumber" ${LOG_DIR}/datasource.json`
MaxUsedCount=`/usr/local/bin/jq ".result .MaxUsedCount | tonumber" ${LOG_DIR}/datasource.json`
AverageBlockingTime=`/usr/local/bin/jq ".result .AverageBlockingTime | tonumber" ${LOG_DIR}/datasource.json`
MaxWaitTime=`/usr/local/bin/jq ".result .MaxWaitTime | tonumber" ${LOG_DIR}/datasource.json`

# GrowthForecastに送信する
curl -F number=${InUseCount} ${GROWTH_FORCAST_ENDPOINT}/datasource/InUseCount 1>/dev/null 2>/dev/null
curl -F number=${MaxUseCount} ${GROWTH_FORCAST_ENDPOINT}/datasource/MaxUsedCount 1>/dev/null 2>/dev/null
curl -F number=${AverageBlockingTime} ${GROWTH_FORCAST_ENDPOINT}/datasource/AverageBlockingTime 1>/dev/null 2>/dev/null
curl -F number=${MaxWaitTime} ${GROWTH_FORCAST_ENDPOINT}/datasource/MaxWaitTime 1>/dev/null 2>/dev/null

bashでは多少強引な感じがするので、HTTP-APIを持っていたり、jsonをパースするのが得意な言語で書くともっとスマートにできると思う。今後時間があるときにGroovy書き換えにトライしたい

4. 作成したスクリプトをcronに登録

先ほど作成したシェル(/home/test/monitor.sh)を、cronに登録する。今回は10秒間隔でデータを取得することにした。

# touch /etc/cron.d/jboss-monitoring
# vim jboss-monitoring

* * * * * test for i in `seq 0 10 59`; do (sleep ${i}; /home/test/tools/monitor.sh) & done;
5. できあがったグラフを見る

ブラウザでhttp://localhost:5125/にアクセスすると、以下のようなグラフが確認できたら成功である。

f:id:n_agetsuma:20140317213907p:plain

まとめ

今回はJBossの管理HTTP-APIを使ってデータを収集し、GrowthForecastでグラフ化する方法を紹介した。例ではJBossとGrowthForecastが同じlocalhostで起動しているが、実際に長時間負荷試験などを行う場合は、別のマシンにそれぞれセットアップすることをお勧めする。

また、冒頭に書いたとおり、JBossの管理APIで取得できるのはデータソースの情報だけではなく、スレッドプールやトランザクションの状況などの様々な情報を収集できるので、同様の方法で色々なパラメータを監視することができる。ぜひテスト環境でもモニタリングを行って、運用し始めるまえに問題を検知して対処されることが広まると嬉しい。