WebSphere LibertyのMicroProfile Metricsを使用すると、RESTコールで、簡単にLibertyのパフォーマンス・データを取得することができます。ただ、パフォーマンスの応答が、Prometheus Text形式であり、Prometheusなどのツールと連携する場合には、問題ありませんが、Prometheusが無い環境では、グラフ化をしたい場合に、手間がかかると思います。
LibertyのMP Metricsの応答データを、CSV出力するシェル・プログラムを紹介します。CSVに変換することで、エクセルなどを用いて、必要なパフォーマンス・データを容易にグラフ化できます。
MP Metricsを取得するためのLibertyの設定
MP Metricsを有効化し、RESTコールで、Metrics(パフォーマンス)データを取得できるようにするためには、Libertyのserver.xmlに下記の定義を追加します。
<server>
<featureManager>
<feature>mpMetrics-5.0</feature>
</featureManager>
<mpMetrics authentication="false"/>
</server>
<mpMetrics authentication="false"/>
を追加することで、認証なしで、Metricsデータを取得することができます。認証ありでの設定についてはOpen Libertyのドキュメントを参照ください。
Open Libertyドキュメント - MicroProfile Metrics
上記の設定を行ったLibertyサーバーに対して、/metricsのURLにGETリクエストを送信すると、下記のようにPrometheus Text形式の応答が返ります。
$ curl http://localhost:9080/metrics
# HELP servlet_responseTime_total_seconds The total response time of this servlet since the start of the server.
# TYPE servlet_responseTime_total_seconds gauge
servlet_responseTime_total_seconds{mp_scope="vendor",servlet="io_openliberty_microprofile_metrics_5_0_public_internal_PublicMetricsRESTProxyServlet",} 0.06364990000000001
# HELP classloader_loadedClasses_total Displays the total number of classes that have been loaded since the Java virtual machine has started execution.
# TYPE classloader_loadedClasses_total counter
classloader_loadedClasses_total{mp_scope="base",} 10576.0
// 途中略
# HELP gc_total Displays the total number of collections that have occurred. This attribute lists -1 if the collection count is undefined for this collector.
# TYPE gc_total counter
gc_total{mp_scope="base",name="global",} 0.0
gc_total{mp_scope="base",name="scavenge",} 73.0
# HELP requestTiming_slowRequestCount The number of servlet requests that are currently running but are slow.
# TYPE requestTiming_slowRequestCount gauge
requestTiming_slowRequestCount{mp_scope="vendor",} 0.0
# HELP session_liveSessions The number of users that are currently logged in.
# TYPE session_liveSessions gauge
session_liveSessions{appname="default_host_metrics",mp_scope="vendor",} 1.0
$
#で始まる行は、Metrics項目の説明と、Metrics値の種類で、補足です。実際のMetricsの項目名と値は、#のない行です。
MP MetricsのデータをCSVに変換するシェル・プログラム
下記に、/metricsのURLを定期的に呼び、取得したMetricデータをCSV形式でファイルに記録するサンプル・シェル・プログラム(metrics2csv.sh)を紹介します。
実行方法は、下記のように、第一引数にmetricの取得間隔(秒)を指定し、標準出力をリダイレクトすることで、ファイルにCSV形式でMetricsデータを記録できます。計測を停止するには、[Ctrl]+[c]で停止してください。
$ ./metrics2csv.sh 30 > ./csv/metrics_myhostname_202403051935.csv
出力結果は、下記のようになります。
$ cat ./csv/metrics_myhostname_202403051935.csv
Shell start date = Tue Mar 5 19:35:03 JST 2024
Shell running host = myhost
Connect host = xxx.xxx.xxx.xxx
MPMetrics retrieve interval = 30 sec
--------------------
Metrics item num = 31
--------------------
date, time, classloader_loadedClasses_count{mp_scope="base";}, classloader_loadedClasses_total{mp_scope="base";}, classloader_unloadedClasses_total{mp_scope="base";}, cpu_availableProcessors{mp_scope="base";}, cpu_processCpuLoad_percent{mp_scope="base";}, cpu_processCpuTime_seconds{mp_scope="base";}, cpu_systemLoadAverage{mp_scope="base";}, gc_time_seconds_total{mp_scope="base";name="global";}, gc_time_seconds_total{mp_scope="base";name="scavenge";}, gc_total{mp_scope="base";name="global";}, gc_total{mp_scope="base";name="scavenge";}, jvm_uptime_seconds{mp_scope="base";}, memory_committedHeap_bytes{mp_scope="base";}, memory_maxHeap_bytes{mp_scope="base";}, memory_usedHeap_bytes{mp_scope="base";}, requestTiming_activeRequestCount{mp_scope="vendor";}, requestTiming_hungRequestCount{mp_scope="vendor";}, requestTiming_requestCount_total{mp_scope="vendor";}, requestTiming_slowRequestCount{mp_scope="vendor";}, servlet_request_total{mp_scope="vendor";servlet="io_openliberty_microprofile_metrics_5_0_public_internal_PublicMetricsRESTProxyServlet";}, servlet_responseTime_total_seconds{mp_scope="vendor";servlet="io_openliberty_microprofile_metrics_5_0_public_internal_PublicMetricsRESTProxyServlet";}, session_activeSessions{appname="default_host_metrics";mp_scope="vendor";}, session_create_total{appname="default_host_metrics";mp_scope="vendor";}, session_invalidated_total{appname="default_host_metrics";mp_scope="vendor";}, session_invalidatedbyTimeout_total{appname="default_host_metrics";mp_scope="vendor";}, session_liveSessions{appname="default_host_metrics";mp_scope="vendor";}, thread_count{mp_scope="base";}, thread_daemon_count{mp_scope="base";}, thread_max_count{mp_scope="base";}, threadpool_activeThreads{mp_scope="vendor";pool="LargeThreadPool";}, threadpool_size{mp_scope="vendor";pool="LargeThreadPool";}
2024/03/05, 19:35:03, 10578.0, 10578.0, 0.0, 16.0, 5.078023396707402E-5, 20.671875, -1.0, 0.0, 0.258, 0.0, 80.0, 10409.406, 1.37756672E8, 5.36870912E8, 5.638344E7, 1.0, 0.0, 7.0, 0.0, 6.0, 0.0883503, 0.0, 1.0, 1.0, 1.0, 0.0, 257.0, 254.0, 305.0, 3.0, 200.0
2024/03/05, 19:35:33, 10578.0, 10578.0, 0.0, 16.0, 3.250790757920611E-5, 20.6875, -1.0, 0.0, 0.258, 0.0, 80.0, 10439.448, 1.37756672E8, 5.36870912E8, 5.700348E7, 1.0, 0.0, 8.0, 0.0, 7.0, 0.0923153, 0.0, 1.0, 1.0, 1.0, 0.0, 257.0, 254.0, 305.0, 3.0, 200.0
2024/03/05, 19:36:03, 10578.0, 10578.0, 0.0, 16.0, 0.0, 20.6875, -1.0, 0.0, 0.258, 0.0, 80.0, 10469.475, 1.37756672E8, 5.36870912E8, 5.8364896E7, 1.0, 0.0, 9.0, 0.0, 8.0, 0.095949, 0.0, 1.0, 1.0, 1.0, 0.0, 257.0, 254.0, 305.0, 3.0, 200.0
2024/03/05, 19:36:33, 10578.0, 10578.0, 0.0, 16.0, 6.50493913929816E-5, 20.71875, -1.0, 0.0, 0.258, 0.0, 80.0, 10499.501, 1.37756672E8, 5.36870912E8, 6.053168E7, 1.0, 0.0, 10.0, 0.0, 9.0, 0.0994072, 0.0, 1.0, 1.0, 1.0, 0.0, 257.0, 254.0, 305.0, 3.0, 200.0
$
metrics2csvの内容を下記に添付しますので、自由に変更して活用ください。
#!/bin/bash
# 実行方法:
# ./metrics2csv.sh ([metric取得間隔(秒)]) (> [結果出力ファイル名])
# 実行例:
# ./metrics2csv.sh 30 > metrics_hostname_hhmmss.csv
# 終了方法:
# [Ctrl]+[c]
# 実行例(バックグラウンド):
# nohup ./metrics2csv.sh 30 > metrics_hostname_hhmmss.csv &
# 終了方法(バックグラウンド):
# ps -ef | grep metrics2csv
# kill <psコマンドで確認したプロセスID>
# 第一引数をメトリック取得の間隔に設定。引数が無い場合は60秒間隔とする。
if [ "$#" -eq 0 ]; then
interval=60
elif [ "$#" -eq 1 ] && [[ "${1}" =~ ^[0-9]+$ ]]; then
interval=${1}
else
echo "エラー: 引数は、metric取得間隔の1個、または、0個(取得間隔は60秒)を指定します." >&2
echo "実行方法: ./metrics2csv.sh ([metric取得間隔(秒)]) (> [結果出力ファイル名])" >&2
echo "実行例: ./metrics2csv.sh 30 > metrics_hostname_hhmmss.csv" >&2
exit 1
fi
echo "Shell start date = "$(date)
echo "Shell running host = "$(hostname)
# localhost
connecthost=localhost
# remote server
# connecthost=xxx.xxx.xxx.xxx
echo "Connect host = ""$connecthost"
echo "MPMetrics retrieve interval = ""$interval"" sec"
# Metric項目数
lastitemnum=0
# ここからループ
while true; do
# dateコマンドで、日付と時刻部分を取得
yyyymmdd=$(date '+%Y/%m/%d')
hhmmss=$(date '+%H:%M:%S')
# MPMetricの取得
raw_metrics=$(curl -s http://"$connecthost":9080/metrics)
# 必要な行のみ抽出 #で始まる項目の説明行を削除して、ソート
row=$(echo "$raw_metrics" | egrep -v "^#" | sort)
# MPMetricの項目数
itemnum=$(echo "$row" | wc -l)
# 「} 」で区切って、項目名と値を分離する
# ヘッダー行は、最初の1回目のリクエストと、もし項目数が変わった時だけ、出力する
if [ $((itemnum)) -ne $((lastitemnum)) ]; then
echo "--------------------"
echo "Metrics item num = ""$itemnum"
echo "--------------------"
lastitemnum="$itemnum"
# 「}」で区切った前半が項目名。項目名の中の「,」は「;」に置き換え。CSVファイルとして開きやすくするため。
item=$(echo "$row" | sed "s/,/;/g" | awk '{print ", " substr($0,1,index($0,"}") )}')
# 項目の一、二列目は日付と時間とし、その後、項目名を出力
echo "date, time""$item" | sed -z "s/\n//g"
echo
fi
# 「}」で区切った後半が値
value=$(echo "$row" | awk '{print ", " substr($0,index($0,"}")+2 )}')
# 一、二列目はcurl呼び出しの日付と時間を挿入し、その後、項目値を出力
echo "$yyyymmdd"", ""$hhmmss""$value" | sed -z "s/\n//g"
echo
# コマンド引数で指定した秒数sleepして無限ループ
sleep $interval
done
上記で掲載したサンプルの出力結果は、ほとんどLibertyをインストールしただけで、まだ、アプリケーションがデプロイされていない状態のLibertyの出力例なので、Metricsの項目数が、31と少ないですが、実際にアプリケーションがデプロイされると簡単に数百の項目数になります。
実際にMetricsデータを取得し、出力するデータを抽出しているのは、下記の部分になります。
# MPMetricの取得
raw_metrics=$(curl -s http://"$connecthost":9080/metrics)
# 必要な行のみ抽出 #で始まる項目の説明行を削除して、ソート
row=$(echo "$raw_metrics" | egrep -v "^#" | sort)
出力項目を、特定の項目にしぼる場合、例えば、HTTPセッションとスレッド・プールのデータ項目のみを出力する場合には、下記のように抽出条件を修正します。
row=$(echo "$raw_metrics" | egrep -v "^#" | egrep "session|threadpool" | sort)
MP Metricsで取得できるデータ項目については、下記のドキュメントを参照ください。
Open Libertyドキュメント - MicroProfile Metrics 5.0 metrics reference
どのメトリックを見るべきかは、下記のQiitaの記事も参考になります。
Qiita - Libertyの性能情報をPythonのSidecarで取得する(mpMetrics)