Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

SpringPetClinic.png

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のボタンを押下する。
成功すれば、監視対象のデータが読み込まれる。

apm_check.png

取得できる情報

PetClinicの画面を適当に操作した結果のスクリーンショット

APMのダッシュボード

apm_dash_1.png

リクエストの処理状況

リクエストの平均処理時間の一覧が確認できる。
詳細が確認したいリクエストに関しては画面下部の表のURLをクリックすると詳細画面に遷移できる。

apm_request.png

リクエストの詳細

各処理にかかる時間から、クエリの発行状況、リクエストのパラメータなど詳細が確認できる。

apm_transaction_1.png
apm_transaction_2.png
apm_transaction_3.png

Javaアプリケーションエラー

apm_error.png
apm_error_detail.png

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

heap_usage.png

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を利用して接続を確認する。

jmc.png

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さえ準備できていれば既存のサービスのメトリックも取得できる。

whale_shark
東京で働いているしがないSE
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away