はじめに
Elastic Stack 6.3からAPMにJavaがサポートされたので(Betaですが)のアプリケーションパフォーマンスモニタリングについてちょっと調べてみた。
またSpring BootのサンプルアプリケーションであるSpring PetClinicの監視を行う。
パフォーマンスモニタリング手法の比較
Javaのパフォーマンスモニタリングを行う方法は一般的には以下の2つ。
- Java Mission Control(jmc)などでのJMX接続
- Java Fright Recoder(JFR)
Elastic Stackを利用する場合はJavaにかかわる情報を取得できるのは以下の方法が考えられる。
- APMのJava Agent
- MetricbeatのJolokia module
それぞれの手法の比較
手法 | 記録方法 | 記録内容 | Javaオプションへの追加 | 備考 |
---|---|---|---|---|
JMX | jmcで接続したPC | MBeanサーバで取得できる項目をユーザが設定 | JMXポートの開放とアクセス許可 | JDK同梱 |
JFR | ローカルもしくはjmcでフライトレコーダーを起動したPC | JFRで記録される項目 | JFR記録用の起動オプション。jmcで記録する場合はJMXと同じ設定を追加 | |
Elastic APM | APM Clientで取得しAPMサーバ経由でElasticsearchへ | Webアプリケーション向けの情報 | APMのjarやAPMサーバのアドレス | APM ClientのAPI |
Metricbeat | Jolokiaで取得しMetricbeatからElasticsearchへ | MBeanサーバで取得できる項目をユーザが設定 | Jolokiaのjarの追加、またはJMXポートの開放とアクセス許可 | Jolokia |
Kibana + Elasticsearch + APM Server の環境準備
Elastic社が出している公式のイメージを使って最低限の環境を準備。
version: '3'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.5.1
volumes:
- ./esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
kibana:
image: docker.elastic.co/kibana/kibana:6.5.1
ports:
- 5601:5601
apm:
image: docker.elastic.co/apm/apm-server:6.5.1
ports:
- 8200:8200
Spring PetClinicのビルド
今回はUbuntu Server 18.04のOpenJDK 11を利用してビルドを行う。
ただし、そのままではビルドできないのでひと手間加える。
sudo apt install default-jdk
git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic
ひと手間
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
ビルド
./mvnw package
起動
java -jar target/*.jar
ブラウザにアクセスして画面が表示されればOK
APMを利用したモニタリング
APMのダウンロード
curl -O https://search.maven.org/remotecontent?filepath=co/elastic/apm/elastic-apm-agent/1.0.1/elastic-apm-agent-1.0.1.jar
APM Clientをjavaの実行時引数に追加する。
詳細な設定方法は公式やKibanaのSetup Instructionsを確認すること。
java -javaagent:elastic-apm-agent-1.0.1.jar -Delastic.apm.service_name=petclinic -Delastic.apm.application_packages=org.example -Delastic.apm.server_urls=http://localhost:8200 -jar target/*.jar
PetClinicが起動すればAPMの正しく起動している。
起動できない場合は、エラーメッセージがターミナルに出ているはずなのでエラーメッセージを確認する。
起動後の設定
KibanaからAPMのSetup Instructionsを選択して一番下のLoad Kibana objectsのボタンを押下する。
成功すれば、監視対象のデータが読み込まれる。
取得できる情報
PetClinicの画面を適当に操作した結果のスクリーンショット
APMのダッシュボード
リクエストの処理状況
リクエストの平均処理時間の一覧が確認できる。
詳細が確認したいリクエストに関しては画面下部の表のURLをクリックすると詳細画面に遷移できる。
リクエストの詳細
各処理にかかる時間から、クエリの発行状況、リクエストのパラメータなど詳細が確認できる。
Javaアプリケーションエラー
Metricbeatを用いたモニタリング
Metricbeatを利用したモニタリングの構成は2種類存在する。
- JavaアプリケーションにJolokiaのJVM Agentサービスやwarを同居させる
- JMXで接続しJolokiaのproxyモード経由でアクセスする
今回はそれぞれの解説を行う。
導入方法がそれぞれ異なるため、環境に合わせて選択してほしい。
例えば新規でサーバを構築する場合は、apmのjarとJolokiaのjarを起動パラメータにあらかじめ追加する。
既存のサービスに追加する場合は、既存のサービスに大きな影響を与えないために、既存のアプリケーションサーバにJMXで接続するJolokiaのproxyモードを利用して接続する。
概要は以下の通り。
前者に関してはJVM Angetのモードを利用する。warに関してはアプリケーションサーバにデプロイするだけなので今回は後者と近いので割愛。
後者に関しては軽量なWebアプリケーションサーバを立ち上げてそこにwarをデプロイする形で利用する。
また、どちらもmetricbeatは同一のサーバで動作させることとする。
※もしJolokiaとmetricbeatを異なるサーバで実行する場合は、Elasticsearchに格納する日付がmetricbeatが実行されるサーバとなるため注意が必要。
また、Jolokiaの設定方法やできることなどは公式を参考にしてほしい。
Metricbeatの初期設定
curl -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-6.5.1-linux-x86_64.tar.gz
metricbeat.ymlの設定
Elastic SearchのURLを設定する。
output.elasticsearch:
# Array of hosts to connect to.
hosts: ["localhost:9200"]
Jolokiaの設定
1.JavaアプリケーションにJolokiaのJVM Agentサービスを同居させる場合
JolokiaのJVM Agentをダウンロードする。
curl -O http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-jvm/1.6.0/jolokia-jvm-1.6.0-agent.jar
Javaオプション
java -javaagent:jolokia-jvm-1.6.0-agent.jar -jar target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar
Jolokiaの起動確認
末尾に/を忘れるとJSONのレスポンスが返ってこない
curl http://localhost:8778/jolokia/ | jq
metricbeatのJolokia jvm agent向けの設定
Jolokiaのモジュールを有効化する。
今回は説明のため、sytemモジュールの情報は不要なので無効化している。
./metricbeat modules disable system
./metricbeat modules enable jolokia
Jolokia.ymlの設定
今回はJVMの起動時間と、Heapメモリの使用率を取得している。
取得したい情報はjmcなどで実際に接続して確認して選ぶこと。
- module: jolokia
metricsets: ["jmx"]
period: 10s
hosts: ["localhost:8778"]
path: "/jolokia/?ignoreErrors=true&canonicalNaming=false"
namespace: "metrics"
jmx.mappings:
- mbean: 'java.lang:type=Runtime'
attributes:
- attr: Uptime
field: uptime
- mbean: 'java.lang:type=Memory'
attributes:
- attr: HeapMemoryUsage
field: memory.heap_usage
- attr: NonHeapMemoryUsage
field: memory.non_heap_usage
Jolokiaモジュールの動作確認
./metricbeat test modules
metricbeatの起動と動作の確認
metricbeatのサービス化とKibanaの使用方法については割愛
./metricbeat
2.JMXで接続しJolokiaのproxyモード経由でアクセスする
設定が多いので以下の順番で行う。
- アプリケーションサーバのJMXの有効化
- Jolokiaのproxyモードを利用したアプリケーションサーバへの接続
アプリケーションサーバのJMXの有効化
今回は認証等のセキュリティ設定は行わなずに最低限の起動パラメータを追加した。
metricbeatのJolokiaモジュールはユーザIDとパスワードによる認証は対応している。
java -Dcom.sun.management.jmxremote.port=7091 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar
JMCを利用して接続を確認する。
Jolokiaのproxyモードを利用したアプリケーションサーバへの接続
Jolokiaのプロキシモードを利用してJMXで対象のJavaアプリケーションに接続する方法
技術的な詳細や詳細な設定内容はこちら
jettyサーバの設定
jettyサーバのダウンロードとポート番号等の変更を行う。
今回は PetClinicが8080ポートを利用しているため8081ポートに変更する。
jettyのバージョンは必要に応じて公式から選択すること
curl -O https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.4.14.v20181114/jetty-distribution-9.4.14.v20181114.tar.gz
tar xf jetty-distribution-9.4.14.v20181114.tar.gz
cd jetty-distribution-9.4.14.v20181114/
## Connector port to listen on
jetty.http.port=8081
次にJolokiaのproxyモードを利用して接続する場合はオプションを追加する必要がある。
今回は必要な設定をweb.xmlに追記する。
また、今回の構成では認証機能は有効にできないため無効化する。
cd webapps/
curl -O http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-war/1.6.0/jolokia-war-1.6.0.war
mv jolokia-war-1.6.0.war jolokia.war
mkdir jolokia
cd jolokia
jar xf ../jolokia.war
servletタグの中に以下の設定を追加する。
<servlet>
<init-param>
<param-name>dispatcherClasses</param-name>
<param-value>org.jolokia.jsr160.Jsr160RequestDispatcher</param-value>
</init-param>
...
</servlet>
認証機能に関するところを無効化する。
<web-app>
...
<!--
Security enabled by default. Please update to match you specific security setup (e.g. the auth-method)
-->
<!--
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>jolokia</realm-name>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Jolokia-Agent Access</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>jolokia</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>jolokia</role-name>
</security-role>
-->
</web-app>
Jolokiaサーバの起動確認
末尾に/を忘れるとJSONのレスポンスが返ってこない
curl -O http://localhost:8081/jolokia/ | jq
Jolokiaサーバのproxyモードによる接続の確認
curl -X POST -H 'Content-Type:application/json' -d '{"type":"read","mbean":"Tomcat:type=Server", "attribute" : "serverInfo", "target" : { "url": "service:jmx:rmi:///jndi/rmi://localhost:7091/jmxrmi" } }' http://localhost:8081/jolokia/ | jq
{
"request": {
"mbean": "Tomcat:type=Server",
"attribute": "serverInfo",
"type": "read",
"target": {
"url": "service:jmx:rmi:///jndi/rmi://localhost:7091/jmxrmi"
}
},
"value": "Apache Tomcat/9.0.12",
"timestamp": 1543418665,
"status": 200
}
設定が不足している場合はエラーメッセージが出力されるのでその内容を見て修正する。
metricbeatのJolokia proxyモードの設定
Jolokiaのモジュールを有効化する。
今回は説明のため、sytemモジュールの情報は不要なので無効化している。
./metricbeat modules disable system
./metricbeat modules enable jolokia
jolokia.ymlの設定
今回はJVMの起動時間と、Heapメモリの使用率を取得している。
取得したい情報はjmcなどで実際に接続して確認して選ぶこと。
また、本当にリモートから取得できているかを確認するためにテスト用にTomcatのバージョンを取得するMBeanも追加している。
- module: jolokia
metricsets: ["jmx"]
period: 10s
hosts: ["localhost:8081"]
path: "/jolokia/?ignoreErrors=true&canonicalNaming=false"
namespace: "metrics"
jmx.mappings:
- mbean: 'java.lang:type=Runtime'
attributes:
- attr: Uptime
field: uptime
target:
url: 'service:jmx:rmi:///jndi/rmi://localhost:7091/jmxrmi'
- mbean: 'java.lang:type=Memory'
attributes:
- attr: HeapMemoryUsage
field: memory.heap_usage
- attr: NonHeapMemoryUsage
field: memory.non_heap_usage
target:
url: 'service:jmx:rmi:///jndi/rmi://localhost:7091/jmxrmi'
- mbean: 'Tomcat:type=Server'
attributes:
- attr: serverInfo
field: tomcat.serverInfo
target:
url: 'service:jmx:rmi:///jndi/rmi://localhost:7091/jmxrmi'
Jolokiaモジュールの動作確認
./metricbeat test modules
ここから先は前述の動作確認を同じなので割愛。
おわりに
apm agentを利用すると簡単にWebアプリケーションのメトリックを取得することができた。
マイクロサービスととても相性が良いと感じた。
新規で作成するWebアプリケーションに関しては導入を検討するべき。
metricbeatのJolokiaモジュールはMBeanを利用した柔軟なデータ取得が魅力的である。
Webアプリケーション以外にも応用が利く。
また、JMXさえ準備できていれば既存のサービスのメトリックも取得できる。