micrometer-registry-datadogを使ったらDatadogのJVMのメトリックがわかりやすくなった
以前書いた「 Spring Bootを1.5から2へマイグレーションするステップとポイント 」 にて、 Datadogに対してメトリックを送信するの仕組みを micrometer-registry-datadog に変更したのですが、 Javaアプリケーションのメトリック取得がいい感じだったので、今回はそれを紹介します。
Micrometerって何
Micrometer はJVM上で動くアプリケーションのメトリックを取得するためのライブラリです。
各種モニタリングツールとの連携が可能で、2018/05時点では以下のモニタリングツールに対応しています。
これらのモニタリングツールと対になるライブラリを使用することで、取得したメトリックを容易に送ることができるのです。
Spring Boot アプリケーションに micrometer-registry-datadog を設定する
Spring Bootに micrometer-registry-datadog を入れて、 Datadogにメトリックを溜め込んでみましょう。
build.gradleの修正
build.gradle
の依存関係に micrometer-registry-datadog を追加します。
なお、Micrometer自体は spring-boot-starter-actuator
に含まれています。
1compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.1.RELEASE'
2compile group: 'io.micrometer', name: 'micrometer-registry-datadog', version: '1.0.3'
application.yamlの修正
application.yaml に設定を追加します。
公式ドキュメントだと指定可能なプロパティが全て列挙されていないので、
io.micrometer.datadog.DatadogConfig
クラスの中を見ることで確認できます。
1management:
2 metrics:
3 export:
4 datadog:
5 api-key: ${datadogのAPIキー}
6 step: 15s # メトリックの収集間隔
メトリックに情報を付与する
こちらは必須ではありません。
Datadog上でタグを使ってメトリックを横断的にフィルタできると嬉しいケースがあるので、 commonTags
を使って、ホスト名やモニターグループを設定すると良いと思います。
また、Spring Bootから取得しているメトリックであることを識別するために、メトリックに spring.
のprefixを付与しています。
1@Bean
2public MeterRegistryCustomizer<MeterRegistry> customizer() {
3 return registry -> {
4 try {
5 registry.config()
6 .meterFilter(new MeterFilter() {
7 @Override
8 public Meter.Id map(Meter.Id id) {
9 return id.withName("spring." + id.getName());
10 }
11 })
12 .commonTags("env", "local")
13 .commonTags("monitoring_group", "system_component_a")
14 .commonTags("host", InetAddress.getLocalHost().getHostName());
15 } catch (UnknownHostException e) {
16 LOGGER.error("fail to resolve hostname.", e);
17 }
18 };
19}
Datadog上でJVMのメトリックを見てみよう
さて本題です。アプリケーションを起動し、Datadog上でメトリックを確認してみましょう。
JVMの使用メモリ
全体の使用量
JVMの使用メモリ量は jvm.memory.used
のメトリックで確認できます。 (先程 spring.
のprefixをつけているので、下の図では spring.jvm.memory.used
)
ヒープ領域のみ
次に area:heap
を指定すると、ヒープ領域のみに絞りこむことができます。
Survivor領域
id:ps_survivor_space
を追加すると、 ヒープの中のさらにSurvivor領域のみにも絞り込めます。これは嬉しい。
領域毎にグループ化する
もちろん、 id
をfromではなく、グルーピングで使用すると、Heap領域に対する各領域の状態が確認できます。
JVMメトリックの構成
jvm.memory.used
メトリックの構造をまとめると以下。
metric | area | id |
---|---|---|
jvm.memory.used | heap | ps_eden_space |
ps_old_gen | ||
ps_survivor_space | ||
nonheap | metaspace | |
code_cache | ||
cmpressed_class_space |
他にも、例えば、 バッファメモリもそれぞれDirect BufferとMapped Bufferでメトリックが取れたりする。
metric | id |
---|---|
jvm.buffer.memory.used | direct |
mapped |
micrometer-registry-datadog使用時の注意点
Datadogへのメトリック送信に失敗した場合にはWARNログが出力される
micrometer-registry-datadog
がバックグラウンドで定期的にメトリックを打ち上げてくれますが、
通信に失敗した場合には WARN
レベルのログが出力されます。
そのため、 アプリケーションのログ監視をしている場合には、影響がないか確認しておきましょう 。
参考までに、エラーは以下のような感じで出ていました。
1failed to send metrics
2 java.net.SocketTimeoutException: connect timed out
3 at java.net.PlainSocketImpl.socketConnect(Native Method)
4 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
5 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
6 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
7 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
8 at java.net.Socket.connect(Socket.java:589)
9 at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:673)
10 at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
11 at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
12 at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
13 at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264)
14 (以下略)
まとめ
micrometer-registry-datadog
を使用すると、取得したいメトリックの情報が構造化されて、フィルタリングがしやすくなりました。
特にJVMのメモリのメトリックは以前よりも直感的になった印象があります。
今回のMicrometerに限らず、 Application Performance Monitoring 界隈のライブラリが様々出回ってきたので、この方面も学習していきたいですね。