3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaアプリケーションをElastic APMで計測してみる

Last updated at Posted at 2020-07-19

はじめに

JavaアプリケーションでElastic APMを使って可視化してみたメモ。
APMに関する説明は他の方の投稿を参考にしてください。

環境

使用した環境は以下のとおり。

  • CentOS 7.5
  • Elasticsearch 7.8.0
  • Kibana 7.8.0
  • APM Server 7.8.0
  • APM Java Agent 1.17.0

アプリケーションは測定対象のアプリケーションはWindows上で動かします。

OpenJDKのインストール

まず、OpenJDK 8をインストールします。

# yum install java-1.8.0-openjdk-devel

# java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

JAVA_HOMEを設定し、PATHにJavaのパスを追加しています。

# echo "export JAVA_HOME=$(readlink -e $(which java)|sed 's:/bin/java::')" > /etc/profile.d/java.sh
# echo "PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java.sh
# source /etc/profile

Elasticsearchのインストール

Elasticsearch, Kibana, APM Serverを順番にインストールしていきます。
まずは、Elasticsearchをインストールします。

curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.8.0-x86_64.rpm
rpm -i elasticsearch-7.8.0-x86_64.rpm

Elasticsearchを外部からアクセスできるように設定します。
※今回の構成ではやらなくてもOKだったはずです。

# vi /etc/elasticsearch/elasticsearch.yml
#network.host: 192.168.0.1
network.host: 0.0.0.0
transport.host: localhost

自動起動するように設定し、起動まで実行します。

# systemctl enable elasticsearch
# systemctl start elasticsearch

最後に動作確認。

[root@elasticserver1 ~]# curl http://127.0.0.1:9200
{
  "name" : "elasticserver1",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "ZUiSSmOETuOAnZp2Adz9dQ",
  "version" : {
    "number" : "7.8.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
    "build_date" : "2020-06-14T19:35:50.234439Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Kibanaのインストール

Elasticsearchのインストールが終わったら、次はKibanaをインストールします。

# wget https://artifacts.elastic.co/downloads/kibana/kibana-7.8.0-x86_64.rpm
# rpm -i kibana-7.8.0-x86_64.rpm

Kibanaを外部から接続できるように設定します。

# vi /etc/kibana/kibana.yml

#server.host: "localhost"
server.host: "0.0.0.0"

自動起動するように設定し、起動まで実行します。

# systemctl enable kibana
# systemctl start kibana

最後に動作確認。以下のURLをブラウザから開いて、Kibanaの画面が表示されることを確認します。

  • http://[KibanaサーバーのIPアドレス]:5601

APM Serverのインストール

サーバ側では最後の設定となるAPM Serverのインストールを実施します。

# curl -L -O https://artifacts.elastic.co/downloads/apm-server/apm-server-7.8.0-x86_64.rpm
# rpm -vi apm-server-7.8.0-x86_64.rpm

$ su - apm-server
$ apm-server setup --index-management
Index setup finished.
$ apm-server setup --pipelines
Loaded Ingest pipelines

APM Serverを外部からアクセスできるように設定します。

# vi /etc/apm-server/apm-server.yml
apm-server:
  # Defines the host and port the server is listening on. Use "unix:/path/to.sock" to listen on a unix domain socket.
  #host: "localhost:8200"
  host: "0.0.0.0:8200"

自動起動するように設定し、起動まで実行します。

# systemctl enable apm-server
# systemctl start apm-server

最後に動作確認。

# curl -L http://localhost:8200
{
  "build_date": "2020-06-14T17:10:16Z",
  "build_sha": "06c58bf4e5b675d04314bf44961ffd6b0e13f544",
  "version": "7.8.0"
}

Java agentの設定

Java agentの設定方法は以下のサイトを参考にして実施します。

Java agentは以下の3つの方法で動かすことができます。

  1. javaagentフラグを使用した手動セットアップ
  2. apm-agent-attach-standalone.jarを使用した自動セットアップ
  3. apm-agent-attachをアプリケーションに組み込み

Java agentのモジュールは以下からダウンロードします。

javaagentフラグを使用した手動セットアップ

以下のようにjavaコマンド実行時に「-javaagent」フラグを指定する方法です。

java -javaagent:/path/to/elastic-apm-agent-<version>.jar -Delastic.apm.service_name=my-cool-service -Delastic.apm.application_packages=org.example,org.another.example -Delastic.apm.server_urls=http://localhost:8200 -jar my-application.jar

Tomcatならsetenv.shに設定したりと、少し手が入るので今回はapm-agent-attach-standalone.jarを使用した自動セットアップを試してみました。

apm-agent-attach-standalone.jarを使用した自動セットアップ

apm-agent-attach-standalone.jarをダウンロードし、以下のように実行します。
事前にアプリケーションは起動しておきます。

apm-agent-attach-standalone.jarは以下からダウンロードします。今回ダウンロードしたのはv1.17.0です。

>java -jar apm-agent-attach-1.17.0-standalone.jar --list
このコマンドでプロセスIDを調べます。

調べたプロセスIDを指定し以下を実行します。
>java -jar apm-agent-attach-1.17.0-standalone.jar --pid 4628 --config service_name=my-cool-service server_urls=http://localhost:8200
2020-07-18 08:18:46.651  INFO Attaching the Elastic APM agent to 4628
2020-07-18 08:18:50.017  INFO Done

[server_urls=http://localhost:8200]はAPM Serverのアドレスを指定します。

Kibana APM UI

Java agentがアプリケーションから収集した情報はAPM Serverへ送信されます。
APM ServerはそれをElasticsearchに格納し、Kibana APM UIで可視化することができます。

まず、Kibanaのトップ画面から[APM]を選択します(画面左下)。

image.png

サービスの一覧が以下のように表示されます。
[my-cool-service]がapm-agent-attach-standalone.jarを実行した際に指定したサービス名です。

image.png

[my-cool-service]を選択すると、以下のように様々な情報が表示されます。

  • Time spent by span type: spanタイプごとの実行時間の割合
  • Transaction duration: トランザクションの平均実行時間の推移
  • Requests per minute: 1分ごとのリクエスト数の推移
  • Transactions: トランザクションの一覧

image.png

ここで、トランザクションの一覧から1つのトランザクションを選択します。
遷移後の画面でサンプルのトランザクションを選択すると、以下のようにSpanのタイムラインを表示することができます。

image.png

作成したアプリケーションは、以下の流れになっています。

  1. GETリクエストを受信。
  2. 内部の別のGETを受け付けるRESTサービスをリクエスト。レスポンスを受信。
  3. PostgreSQLへJDBCでSELECTを実行。

※本当は2.のRESTサービスを別サービスにしておけばよかったのですが、手抜きで同じサービス名にしています。そのため、モノリシックアーキテクチャでもトレーシングは有効だという例になっています。

既存のアプリケーションに対して、Java agentを外部からattachしただけでこれだけの情報を表示してくれます。
[SELECT FROM test]のSPANを選択すると、以下のように実行したSQLも表示されます。

image.png

このような情報が表示できるのはJava agentがフレームワークやJDBC等を自動で計測することができるからです。対応しているフレームワークやDBは以下に記載があります。

apm-agent-attachをアプリケーションに組み込み

最初からAPMを使用することが決まってアプリケーションを開発するのであれば、apm-agent-attachをアプリケーションに組み込みのが良いと思います。

Mavenであれば、pom.xmlに以下の依存性を追記します。

pom.xml
		<dependency>
		    <groupId>co.elastic.apm</groupId>
		    <artifactId>apm-agent-attach</artifactId>
		    <version>${elastic-apm.version}</version>
		</dependency>

アプリケーションの起動メソッドでElasticApmAttacher.attach()メソッドを呼び出します。

	public static void main(String[] args) throws Exception {
		logger.info("start ");

		ElasticApmAttacher.attach(); // ★ここ!

		org.apache.camel.spring.Main main = new org.apache.camel.spring.Main();
		main.setApplicationContextUri("META-INF/spring/camel-context.xml");
		main.run(args);
	}

最後に[elasticapm.properties]を以下のように作成し、クラスパスが通ったディレクトリに置きます。

elasticapm.properties
# サービス名
service_name=my-cool-service
# 計測対象のパッケージ
application_packages=example
# 接続先のAPM Serverのアドレス
server_urls=http://192.168.10.126:8200

APIのPublic APIを使用して、独自のSpanを作成する。

他にも@CaptureSpanアノテーションをメソッドにつけて独自のSpanを作成することができます。

まず、pom.xmlにapm-agent-apiを追加。

pom.xml
		<dependency>
		    <groupId>co.elastic.apm</groupId>
		    <artifactId>apm-agent-api</artifactId>
		    <version>${elastic-apm.version}</version>
		</dependency>

対象のメソッドに@CaptureSpanアノテーションを付与します。現在のSpanの子Spanとなります。

    	@CaptureSpan(value = "TestSleep", type = "ext", subtype = "class-method")
    	public void sleep(int sleepMs) {
    		try {
    			 Thread.sleep(sleepMs);
    		} catch (InterruptedException e) {
    		}
    	}

特定のロジックに対してSpanを作成したい場合は、以下のようにstartSpanメソッドを使用します。ここではspanの名前を[TEST SPAN]に設定しています。

		Span parentSpan = ElasticApm.currentSpan();
		Span span = parentSpan.startSpan("app", "java logic", "test");
		try (final Scope scope = span.activate()) {
		    span.setName("TEST SPAN");
			// ここにロジックが入る。
		} catch (Exception e) {
		    span.captureException(e);
		    throw e;
		} finally {
		    span.end();
		}

Kibanaで該当のトランザクションを表示すると以下のように、[TEST SPAN]が表示されるようになります。

image.png

Profiling configuration options

サンプリングプロファイラー(async-profiler)の周期に基づいて自動でメソッド単位のスパンを作成することができます。デフォルトだと全てのクラス・メソッドが対象となるため、対象を絞るように設定するのが好ましいです。
機能を有効にする場合、[profiling_inferred_spans_enabled]を"true"に設定します。なお、Windowsでは利用できません。

Linux上で本オプションを有効にした場合、以下のように可視化されました。
ここではMyCodeProcessor#processorメソッドが自動的に追加されています。

image.png

[Profiling configuration options]については、以下にオプションの詳細の説明があります。

以下は設定・実行例です。

# プロファイリング(スパンの推定)を有効にする。
JAVA_OPTS="$JAVA_OPTS -Delastic.apm.profiling_inferred_spans_enabled=true"
# スパンの推定の頻度を指定する。短いほど正確に取得できる。ただし、オーバーヘッドが大きくなる。
JAVA_OPTS="$JAVA_OPTS -Delastic.apm.profiling_inferred_spans_sampling_interval=50ms"
# スパンの推定の最小時間
JAVA_OPTS="$JAVA_OPTS -Delastic.apm.profiling_inferred_spans_min_duration=0ms"
# スパンを推定するクラスを指定する。値を設定すると推定するスパンを限定できるのでオーバーヘッドを減少できる。","区切りで指定する。
JAVA_OPTS="$JAVA_OPTS -Delastic.apm.profiling_inferred_spans_included_classes=org.example.myapp.*"
# スパンの推定から除外するクラスを指定する。","区切りで指定する。
JAVA_OPTS="$JAVA_OPTS -Delastic.apm.profiling_inferred_spans_excluded_classes=org.example.myapp2.*"

java -javaagent:/path/to/elastic-apm-agent-<version>.jar $JAVA_OPTS その他のオプション -jar my-application.jar

APM Java agentによる負荷

agentはかなりのデータをAPM Serverへ送信しているだったので、負荷についてドキュメントを確認してみた。

  • レイテンシー

シングルスレッドでのベンチマークでは、99%まで10マイクロ秒以下のオーバーヘッド。

  • CPU

APM Serverへ送信する際にイベントをシリアル化、圧縮するなど、多少のCPU負荷はあるが、特に問題はない。

  • メモリー

必要とするメモリサイズは小さく、通常はアプリケーションのヒープサイズを増やす必要はない。

  • ネットワーク

agentが記録されたイベントをAPM Serverに送信するので、ネットワーク帯域はある程度必要となる。

agentはデフォルトで全てのトランザクションをサンプリングします。
そのため、Elasticsearchで必要とするストレージや計測対象のサーバの負荷を下げる目的で、サンプルレートを変更することができます。
transaction_sample_rateプロパティを0.0~1.0で調整するようです。

アプリケーションログとの連携

アプリケーションログをElasticsearchに送信し、APMのトレースデータとログを関連付けて表示することもできます。
連携方法については以下に記事を書きました。

参考

APM APIを使用したアプリケーション実行時に、「No compatible attachment provider is available」というエラーが発生することがあります。
この場合、使用するJDKを変更すると動くことがあります。(OracleJDKだとエラーになるのかも)

[2020-07-19 06:50:03.555], [INFO ], e.Main, main, example.Main, start
Exception in thread "main" java.lang.IllegalStateException: No compatible attachment provider is available
        at co.elastic.apm.attach.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:602)
        at co.elastic.apm.attach.bytebuddy.agent.ByteBuddyAgent.attach(ByteBuddyAgent.java:273)
        at co.elastic.apm.attach.ElasticApmAttacher.attach(ElasticApmAttacher.java:159)
        at co.elastic.apm.attach.ElasticApmAttacher.attach(ElasticApmAttacher.java:113)
        at co.elastic.apm.attach.ElasticApmAttacher.attach(ElasticApmAttacher.java:70)
        at example.camelbegginer.restdsl.Main.main(Main.java:15)
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?