Edited at

Elasticsearchを利用したjavaアプリの状態監視


はじめに

Elastic Stack 6.3からAPMにJavaがサポートされたので(Betaですが)のアプリケーションパフォーマンスモニタリングについてちょっと調べてみた。

またSpring BootのサンプルアプリケーションであるSpring PetClinicの監視を行う。


パフォーマンスモニタリング手法の比較

Javaのパフォーマンスモニタリングを行う方法は一般的には以下の2つ。

Elastic Stackを利用する場合はJavaにかかわる情報を取得できるのは以下の方法が考えられる。

それぞれの手法の比較

手法
記録方法
記録内容
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社が出している公式のイメージを使って最低限の環境を準備。

https://www.docker.elastic.co/


docker-compose.yml

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を利用してビルドを行う。

ただし、そのままではビルドできないのでひと手間加える。


terminal

sudo apt install default-jdk

git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic

ひと手間


pom.xml

<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>

ビルド


terminal

./mvnw package


起動


terminal

java -jar target/*.jar


ブラウザにアクセスして画面が表示されればOK


APMを利用したモニタリング


APMのダウンロード


terminal

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を確認すること。


terminal(追加例)

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種類存在する。


  1. JavaアプリケーションにJolokiaのJVM Agentサービスやwarを同居させる

  2. JMXで接続しJolokiaのproxyモード経由でアクセスする

今回はそれぞれの解説を行う。

導入方法がそれぞれ異なるため、環境に合わせて選択してほしい。

例えば新規でサーバを構築する場合は、apmのjarとJolokiaのjarを起動パラメータにあらかじめ追加する。

既存のサービスに追加する場合は、既存のサービスに大きな影響を与えないために、既存のアプリケーションサーバにJMXで接続するJolokiaのproxyモードを利用して接続する。

概要は以下の通り。

前者に関してはJVM Angetのモードを利用する。warに関してはアプリケーションサーバにデプロイするだけなので今回は後者と近いので割愛。

後者に関しては軽量なWebアプリケーションサーバを立ち上げてそこにwarをデプロイする形で利用する。

また、どちらもmetricbeatは同一のサーバで動作させることとする。

※もしJolokiaとmetricbeatを異なるサーバで実行する場合は、Elasticsearchに格納する日付がmetricbeatが実行されるサーバとなるため注意が必要。

また、Jolokiaの設定方法やできることなどは公式を参考にしてほしい。


Metricbeatの初期設定


terminal

curl -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-6.5.1-linux-x86_64.tar.gz



metricbeat.ymlの設定

Elastic SearchのURLを設定する。


metricbeat.yml

output.elasticsearch:

# Array of hosts to connect to.
hosts: ["localhost:9200"]


Jolokiaの設定


1.JavaアプリケーションにJolokiaのJVM Agentサービスを同居させる場合

JolokiaのJVM Agentをダウンロードする。


terminal

curl -O http://search.maven.org/remotecontent?filepath=org/jolokia/jolokia-jvm/1.6.0/jolokia-jvm-1.6.0-agent.jar



Javaオプション


terminal

java -javaagent:jolokia-jvm-1.6.0-agent.jar -jar target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar



Jolokiaの起動確認

末尾に/を忘れるとJSONのレスポンスが返ってこない


terminal

curl http://localhost:8778/jolokia/ | jq



metricbeatのJolokia jvm agent向けの設定

Jolokiaのモジュールを有効化する。

今回は説明のため、sytemモジュールの情報は不要なので無効化している。


terminal

./metricbeat modules disable system

./metricbeat modules enable jolokia


Jolokia.ymlの設定

今回はJVMの起動時間と、Heapメモリの使用率を取得している。

取得したい情報はjmcなどで実際に接続して確認して選ぶこと。


module.d/jolokia.yml

- 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モジュールの動作確認


terminal

./metricbeat test modules



metricbeatの起動と動作の確認

metricbeatのサービス化とKibanaの使用方法については割愛


terminal

./metricbeat



2.JMXで接続しJolokiaのproxyモード経由でアクセスする

設定が多いので以下の順番で行う。


  • アプリケーションサーバのJMXの有効化

  • Jolokiaのproxyモードを利用したアプリケーションサーバへの接続


アプリケーションサーバのJMXの有効化

今回は認証等のセキュリティ設定は行わなずに最低限の起動パラメータを追加した。

metricbeatのJolokiaモジュールはユーザIDとパスワードによる認証は対応している。


termainl

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のバージョンは必要に応じて公式から選択すること


terminal

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/


start.ini

## Connector port to listen on

jetty.http.port=8081

次にJolokiaのproxyモードを利用して接続する場合はオプションを追加する必要がある。

今回は必要な設定をweb.xmlに追記する。

また、今回の構成では認証機能は有効にできないため無効化する。


terminal

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タグの中に以下の設定を追加する。


WEB-INF/web.xml

<servlet>

<init-param>
<param-name>dispatcherClasses</param-name>
<param-value>org.jolokia.jsr160.Jsr160RequestDispatcher</param-value>
</init-param>
...
</servlet>

認証機能に関するところを無効化する。


WEB-INF/web.xml

<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のレスポンスが返ってこない


tarminal

curl -O http://localhost:8081/jolokia/ | jq



Jolokiaサーバのproxyモードによる接続の確認


tarminal(リクエスト)

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



terminal(リザルト例)

{

"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モジュールの情報は不要なので無効化している。


terminal

./metricbeat modules disable system

./metricbeat modules enable jolokia


jolokia.ymlの設定

今回はJVMの起動時間と、Heapメモリの使用率を取得している。

取得したい情報はjmcなどで実際に接続して確認して選ぶこと。

また、本当にリモートから取得できているかを確認するためにテスト用にTomcatのバージョンを取得するMBeanも追加している。


module.d/jolokia.yml

- 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モジュールの動作確認


terminal

./metricbeat test modules


ここから先は前述の動作確認を同じなので割愛。


おわりに

apm agentを利用すると簡単にWebアプリケーションのメトリックを取得することができた。

マイクロサービスととても相性が良いと感じた。

新規で作成するWebアプリケーションに関しては導入を検討するべき。

metricbeatのJolokiaモジュールはMBeanを利用した柔軟なデータ取得が魅力的である。

Webアプリケーション以外にも応用が利く。

また、JMXさえ準備できていれば既存のサービスのメトリックも取得できる。