これは、なにをしたくて書いたもの?
Infinispan 14で、OpenTelemetryトレーシングとのインテグレーションが追加されたようなので、試してみたいと思います。
Infinispan 14 OpenTelemetry tracing integration
Infinispan 14でのOpenTelemetryのトレーシングとのインテグレーション
Infinispan 14のOpenTelemetryトレーシングとのインテグレーションについては、こちらのブログに記載があります。
Infinispan 14 OpenTelemetry tracing integration
対応内容は、全部で3つあるようです。
- Infninspan Serverでの対応
- Hot Rod Clientでの対応
- REST Clientでの対応
それぞれ見ていきます。
InfinispanのOpenTelemetryトレーシングへの対応で、ちょっと変わっているような気がするのは、Spanを記録するのは
Hot Rod ClientやREST Clientではなく、Infinispan Serverだということですね。
Hot Rod ClientやREST Clientは、そのアプリケーションが動作しているOpenTelemetry TraceとInfinispan Server側のSpanを
紐付ける役割を担います。
Infinispan ServerでのOpenTelemetryトレーシングとのインテグレーション
Infinispan ServerのOpenTeremetryトレーシングに関するドキュメントは、こちら。
Guide to Infinispan Server / Enabling and configuring Infinispan OpenTelemetry tracing
Infinispan ServerでOpenTelemetryトレーシングとのインテグレーションを有効化すると、OpenTelemetryのSpanを開始し、
キャッシュ操作に関連するトレースデータをエクスポートできるようになります。
Infinispan generates tracing spans compatible with the OpenTelemetry standard, allowing you to export, visualize, and analyze tracing data related to the most important cache operations.
有効化の方法は、Infinispan Serverの起動時にシステムプロパティで-Dinfinispan.tracing.enabled=true
を指定します。
ドキュメントでは-Dotel.〜
なシステムプロパティが並びますが、これはOpenTelemetry SDKの設定です。
詳しく見る場合は、こちらですね。
注意点としては、otel.exporter.otlp.endpoint
システムプロパティ(またはOTEL_EXPORTER_OTLP_ENDPOINT
環境変数)を
指定する時は、gRPCを使うOTLPのポートを指定する必要があります。Jaegerの場合は、4317ポートです。
このことは、ブログにのみ書かれています。
Infinispan 14 OpenTelemetry tracing integration
Hot Rod ClientでのOpenTelemetryトレーシングとのインテグレーション
Hot Rod ClientでのOpenTelemetryトレーシングとのインテグレーションに関するドキュメントは、こちら。
Using Hot Rod Java clients / Hot Rod client tracing propagation
Infinispan Serverだと「InfinispanのOpenTelemetryトレーシングの有効化と設定」という見出しだったのですが、こちらだと
「Hot Rod Clientでのトレーシングの伝播」という見出しになっています。
※トレースコンテキストの伝播、と呼んだ方がよさそうですが
これは、Infinispan ServertとHot Rod Clientを使うアプリケーションの 両方で OpenTelemetryトレーシングを有効にしていると、
Hot Rod Client側が関連付けられているTraceに、Infinispan Server側で作成されるSpanを紐付けられる機能です。
デフォルトで有効になっており、無効にすることもできますが、それだとInfinispan Serverで開始されるSpanはどこにも紐付かない
トレースデータになります…。
無効にする場合は、Hot Rod ClientのConfigurationBuilder#disableTracingPropagation
で指定するか、hotrod-client.properties
で
infinispan.client.hotrod.tracing.propagation_enabled
プロパティをfalse
にします。
Hot Rod URIの場合はtracing.propagation_enabled
ですね。
org.infinispan.client.hotrod.configuration (Infinispan 14.0 JavaDoc)
さらっと読んでいると勘違いしやすい気がしますが、 Hot Rod Client自体はトレースデータを生成しない という点には要注意です。
Hot Rod Client自体はSpanを開始しませんが、ブログにあるように任意の操作の際にSpanを定義することはできます。
※ふつうだと思いますが…
Infinispan 14 OpenTelemetry tracing integration
また、ドキュメントやブログには書かれていないのですが、新しいHot Rod ClientもOpenTelemetryトレーシングとのインテグレーションには
対応している感じがしました。
REST ClientでのOpenTelemetryトレーシングとのインテグレーション
REST ClientでのOpenTelemetryインテグレーションですが、実体としてはなにもありません。
ブログに書かれているように、Spanを開始して自分でW3CTraceContextPropagator
に関連付ければOKです。
Infinispan 14 OpenTelemetry tracing integration
REST Clientには、ドキュメントもないのでこれ以上言うことがありません…。
注意点
Infinispan 14時点でのOpenTelemetryトレーシングとのインテグレーションですが、すべての操作に関するトレースデータがエクスポート
されるわけではありません。
キャッシュに対するget
などは対象外です。
Pull Requestとそのコメントを見ると、初期バージョンではすべてのread操作をトレーシングの対象にするわけではないというコメントが
あります。
https://github.com/infinispan/infinispan/pull/10177#discussion_r915489186
もっとも、どの操作が対象になっているかは、実行結果またはソースコードを見ないとわからないのですが…。
Pull Requestの元のissueを見ると意図がわかるのかなと思いきや、このissueは見れません…。
https://issues.redhat.com/browse/ISPN-13725
とりあえず、ここまでの点を踏まえたうえで、Infinispan ServerとHot Rod ClientでOpenTelemetryトレーシングとのインテグレーションを
試してみます。
お題
今回のお題は、以下のようにします。
flowchart LR クライアント --> |curl/HTTP| A subgraph アプリケーション A[JAX-RS Resource] --> B[Hot Rod Client] end subgraph Infinispanクラスター I1[Infinispan Server 1] --> I2[Infinispan Server 2] I2 --> I3[Infinispan Server 3] I3 --> I1 end B --> |Hot Rod Protocol/テレメトリーデータの伝播| Infinispanクラスター A --> |テレメトリーデータ| J[Jaeger] Infinispanクラスター --> |テレメトリーデータ| J
JAX-RS(RESTEasy)を使ったアプリケーションを作成し、その中でHot Rod Clientを利用してInfinispan Serverへアクセスします。
この時、JAX-RSおよびInfinispan ServerでOpenTelemetry SDKを有効にしておき、Infinispan Server側で開始するSpanとアプリケーションで
開始するTracingを関連付けます。
テレメトリーデータは、Jaegerで収集します。
Infinispanで扱うデータのお題は、書籍にします。
環境
今回の環境は、こちらです。
$ java --version openjdk 17.0.8.1 2023-08-24 OpenJDK Runtime Environment (build 17.0.8.1+1-Ubuntu-0ubuntu122.04) OpenJDK 64-Bit Server VM (build 17.0.8.1+1-Ubuntu-0ubuntu122.04, mixed mode, sharing) $ mvn --version Apache Maven 3.9.5 (57804ffe001d7215b5e7bcb531cf83df38f93546) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.8.1, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.15.0-87-generic", arch: "amd64", family: "unix"
Infinispan Serverは、172.18.0.2〜172.18.0.4の3ノードで動作しているものとします。
$ java --version openjdk 17.0.8.1 2023-08-24 OpenJDK Runtime Environment Temurin-17.0.8.1+1 (build 17.0.8.1+1) OpenJDK 64-Bit Server VM Temurin-17.0.8.1+1 (build 17.0.8.1+1, mixed mode, sharing) $ java --version openjdk 17.0.8.1 2023-08-24 OpenJDK Runtime Environment Temurin-17.0.8.1+1 (build 17.0.8.1+1) OpenJDK 64-Bit Server VM Temurin-17.0.8.1+1 (build 17.0.8.1+1, mixed mode, sharing) ispn@5dc68b8abf64:/opt/infinispan-server$ bin/server.sh --version Infinispan Server 14.0.19.Final (Flying Saucer) Copyright (C) Red Hat Inc. and/or its affiliates and other contributors License Apache License, v. 2.0. http://www.apache.org/licenses/LICENSE-2.0
Jaegerは、172.18.0.5で動作しているものとします。
$ ./jaeger-all-in-one version 2023/10/30 07:56:16 maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined 2023/10/30 07:56:16 application version: git-commit=d482f3f7bf780f72a20ddfedbe3aa6ec5c5e4613, git-version=v1.50.0, build-date=2023-10-08T00:14:18Z {"gitCommit":"d482f3f7bf780f72a20ddfedbe3aa6ec5c5e4613","gitVersion":"v1.50.0","buildDate":"2023-10-08T00:14:18Z"}
Infinispan Serverの設定を行う
まず最初に、Infinispan Serverの設定を行いましょう。
以下のコマンドで、管理用ユーザーとアプリケーション用ユーザーを作成しておきます。
$ bin/cli.sh user create -g admin -p password ispn-admin $ bin/cli.sh user create -g application -p password ispn-user
そして、1度OpenTelemetryに関する設定をせずに起動してみます。
$ bin/server.sh \ -b 0.0.0.0 \ -Djgroups.tcp.address=$(hostname -i)
すると、ログには以下のように「OpenTelemetryとのインテグレーションが無効だ」と出力されました。
2023-10-30 08:01:30,797 INFO (ForkJoinPool.commonPool-worker-2) [org.infinispan.server.core.telemetry.TelemetryServiceFactory] ISPN000953: OpenTelemetry integration is disabled
今度は-Dinfinispan.tracing.enabled=true
を指定して起動してみます。
$ bin/server.sh \ -b 0.0.0.0 \ -Djgroups.tcp.address=$(hostname -i) \ -Dinfinispan.tracing.enabled=true
今度は、OpenTelemetryに関する情報が出力されるようになりました。OpenTelemetryとのインテグレーションが有効になったようです。
2023-10-30 08:03:06,438 INFO (ForkJoinPool.commonPool-worker-2) [org.infinispan.server.core.telemetry.TelemetryServiceFactory] ISPN000952: OpenTelemetry instance loaded: OpenTelemetrySdk{tracerProvider=SdkTracerProvider{clock=SystemClock{}, idGenerator=RandomIdGenerator{}, resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.9.0, attributes={service.name="unknown_service:java", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.15.0"}}, spanLimitsSupplier=SpanLimitsValue{maxNumberOfAttributes=128, maxNumberOfEvents=128, maxNumberOfLinks=128, maxNumberOfAttributesPerEvent=128, maxNumberOfAttributesPerLink=128, maxAttributeValueLength=2147483647}, sampler=ParentBased{root:AlwaysOnSampler,remoteParentSampled:AlwaysOnSampler,remoteParentNotSampled:AlwaysOffSampler,localParentSampled:AlwaysOnSampler,localParentNotSampled:AlwaysOffSampler}, spanProcessor=BatchSpanProcessor{spanExporter=io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter@63df352f, scheduleDelayNanos=5000000000, maxExportBatchSize=512, exporterTimeoutNanos=30000000000}}, meterProvider=SdkMeterProvider{clock=SystemClock{}, resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.9.0, attributes={service.name="unknown_service:java", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.15.0"}}, metricReaders=[], views=[]}}
ですが、このままだとOpenTelemetry SDKの設定をなにも行っていません。
1度Infinispan Serverを停止します。
OpenTelemetry SDKの設定は、システムプロパティではなく環境変数で設定することにしました。
$ export OTEL_TRACES_EXPORTER=otlp $ export OTEL_METRICS_EXPORTER=none $ export OTEL_LOGS_EXPORTER=none $ export OTEL_EXPORTER_OTLP_ENDPOINT=http://172.18.0.5:4317 $ export OTEL_SERVICE_NAME=infinispan-server $ export OTEL_NODE_RESOURCE_DETECTORS='env,host,os,process,container'
あとでわかりますが、OTEL_NODE_RESOURCE_DETECTORS
環境変数は設定する意味がなさそうでした…。
これで再びInfinispan Serverを起動すると
$ bin/server.sh \ -b 0.0.0.0 \ -Djgroups.tcp.address=$(hostname -i) \ -Dinfinispan.tracing.enabled=true
ログで、少なくともサービス名は認識していることが確認できます。
2023-10-30 08:09:44,404 INFO (ForkJoinPool.commonPool-worker-1) [org.infinispan.SERVER] ISPN080018: Started connector HotRod (internal) 2023-10-30 08:09:44,569 INFO (ForkJoinPool.commonPool-worker-2) [org.infinispan.server.core.telemetry.TelemetryServiceFactory] ISPN000952: OpenTelemetry instance loaded: OpenTelemetrySdk{tracerProvider=SdkTracerProvider{clock=SystemClock{}, idGenerator=RandomIdGenerator{}, resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.9.0, attributes={service.name="infinispan-server", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.15.0"}}, spanLimitsSupplier=SpanLimitsValue{maxNumberOfAttributes=128, maxNumberOfEvents=128, maxNumberOfLinks=128, maxNumberOfAttributesPerEvent=128, maxNumberOfAttributesPerLink=128, maxAttributeValueLength=2147483647}, sampler=ParentBased{root:AlwaysOnSampler,remoteParentSampled:AlwaysOnSampler,remoteParentNotSampled:AlwaysOffSampler,localParentSampled:AlwaysOnSampler,localParentNotSampled:AlwaysOffSampler}, spanProcessor=BatchSpanProcessor{spanExporter=io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter@b0a04db, scheduleDelayNanos=5000000000, maxExportBatchSize=512, exporterTimeoutNanos=30000000000}}, meterProvider=SdkMeterProvider{clock=SystemClock{}, resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.9.0, attributes={service.name="infinispan-server", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.15.0"}}, metricReaders=[], views=[]}}
ここまでは、すべてのInfinispan Serverで行います。
最後にキャッシュを作成します。どれかひとつのInfinispan Serverのインスタンスを選び、管理CLIでログインします。
$ bin/cli.sh -c http://ispn-admin:password@localhost:11222
作成するキャッシュの定義は、エンコーディングをProtoStreamにしたDistributed Cacheにします。
cache.xml
<?xml version="1.0" encoding="utf-8"?> <distributed-cache> <encoding> <key media-type="application/x-protostream"/> <value media-type="application/x-protostream"/> </encoding> </distributed-cache>
キャッシュの作成。名前はbookCache
としました。
[a2bfdcf42e2d-4538@cluster//containers/default]> create cache --file=/path/to/cache.xml bookCache
確認。
[a2bfdcf42e2d-4538@cluster//containers/default]> describe caches/bookCache { "bookCache" : { "distributed-cache" : { "mode" : "SYNC", "encoding" : { "key" : { "media-type" : "application/x-protostream" }, "value" : { "media-type" : "application/x-protostream" } } } } }
アプリケーションを作成する
では、アプリケーションを作成していきます。
構成は、RESTEasyとJAX-RSのSeBootstrapを使うことにしましょう。
Maven依存関係など。
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-client-hotrod-jakarta</artifactId> <version>14.0.19.Final</version> </dependency> <dependency> <groupId>org.infinispan.protostream</groupId> <artifactId>protostream-processor</artifactId> <version>4.6.5.Final</version> <optional>true</optional> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> <version>1.31.0</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-core</artifactId> <version>6.2.5.Final</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-undertow-cdi</artifactId> <version>6.2.5.Final</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> <version>6.2.5.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.6.1</version> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/libs</outputDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>libs/</classpathPrefix> <mainClass>org.littlewings.infinispan.remote.otlp.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build>
Maven Pluginのところは、java -jar
で起動できるようにするためです。
今回の依存関係のポイントは、こちらですね。
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> <version>1.31.0</version> </dependency>
こちらがないと、Hot Rod ClientでOpenTelemetryトレーシングデータを扱うことができません。
続いて、ソースコードの方へ。
お題となる書籍クラス。このクラスは、ProtoStreamでマーシャリング/アンマーシャリングします。
src/main/java/org/littlewings/infinispan/remote/otlp/Book.java
package org.littlewings.infinispan.remote.otlp; import org.infinispan.protostream.annotations.ProtoField; import org.infinispan.protostream.descriptors.Type; public class Book { @ProtoField(number = 1, type = Type.STRING) String isbn; @ProtoField(number = 2, type = Type.STRING) String title; @ProtoField(number = 3, type = Type.INT32, defaultValue = "0") int price; 〜getter/setterは省略〜 }
Protocol BuffersのIDLとMarshallerを自動生成するためのインターフェース。
src/main/java/org/littlewings/infinispan/remote/otlp/EntitiesInitializer.java
package org.littlewings.infinispan.remote.otlp; import org.infinispan.protostream.SerializationContextInitializer; import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder; @AutoProtoSchemaBuilder( includeClasses = {Book.class}, schemaFileName = "entities.proto", schemaFilePath = "proto/", schemaPackageName = "entity" ) public interface EntitiesInitializer extends SerializationContextInitializer { }
JAX-RSリソースクラス。このクラスで、Hot Rod Clientを扱います。
src/main/java/org/littlewings/infinispan/remote/otlp/BooksResource.java
package org.littlewings.infinispan.remote.otlp; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCacheManager; import org.infinispan.client.hotrod.configuration.Configuration; import org.infinispan.client.hotrod.configuration.ConfigurationBuilder; import java.util.Comparator; import java.util.List; @Path("books") @ApplicationScoped public class BooksResource { private RemoteCacheManager remoteCacheManager; private RemoteCache<String, Book> bookCache; @PostConstruct public void init() { String uri = """ hotrod://ispn-user:password@172.18.0.2:11222,172.18.0.3:11222,172.18.0.4:11222\ ?context-initializers=org.littlewings.infinispan.remote.otlp.EntitiesInitializerImpl\ """; Configuration configuration = new ConfigurationBuilder() .uri(uri) .build(); remoteCacheManager = new RemoteCacheManager(configuration); bookCache = remoteCacheManager.getCache("bookCache"); } @PreDestroy public void destroy() { remoteCacheManager.close(); } @GET @Path("{isbn}") @Produces(MediaType.APPLICATION_JSON) public Book find(@PathParam("isbn") String isbn) { return bookCache.get(isbn); } @GET @Produces(MediaType.APPLICATION_JSON) public List<Book> findAll() { return bookCache .values() .stream() .sorted(Comparator.<Book, Integer>comparing(b -> b.getPrice()).reversed()) .toList(); } @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Book register(Book book) { bookCache.put(book.getIsbn(), book); return book; } }
JAX-RSの有効化。
src/main/java/org/littlewings/infinispan/remote/otlp/JaxrsActivator.java
package org.littlewings.infinispan.remote.otlp; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("") public class JaxrsActivator extends Application { }
main
クラス。RESTEasyを起動し、Enterで終了するようにしています。
src/main/java/org/littlewings/infinispan/remote/otlp/App.java
package org.littlewings.infinispan.remote.otlp; import jakarta.ws.rs.SeBootstrap; import org.jboss.logging.Logger; import java.util.concurrent.ExecutionException; public class App { public static void main(String... args) throws ExecutionException, InterruptedException { Logger logger = Logger.getLogger(App.class); SeBootstrap.Configuration configuration = SeBootstrap .Configuration .builder() .host("0.0.0.0") .port(8080) .build(); SeBootstrap.Instance instance = SeBootstrap .start(new JaxrsActivator(), configuration) .toCompletableFuture() .get(); logger.info("server startup."); System.console().readLine("> Enter stop."); instance .stop() .toCompletableFuture() .get(); } }
CDIの有効化のため、beans.xml
を作成。
src/main/resources/META-INF/beans.xml
中身はありません。
以上でソースコードは作成できました。
アプリケーションを動作させ、OpenTelemetryトレースデータを記録してみる
では、動かしてみましょう。まずはパッケージング。
$ mvn package
実行する…前に、OpenTelemetry Collector Agentをダウンロードします。
$ curl -LO https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.31.0/opentelemetry-javaagent.jar
$ export OTEL_TRACES_EXPORTER=otlp $ export OTEL_METRICS_EXPORTER=none $ export OTEL_LOGS_EXPORTER=none $ export OTEL_EXPORTER_OTLP_ENDPOINT=http://172.18.0.5:4317 $ export OTEL_SERVICE_NAME=api $ export OTEL_NODE_RESOURCE_DETECTORS='env,host,os,process,container'
起動は、以下のコマンドになります。
$ java -javaagent:opentelemetry-javaagent.jar -jar target/remote-opentelemetry-tracing-0.0.1-SNAPSHOT.jar
起動したら、まずはデータを登録。
$ curl -XPOST -H 'Content-Type: application/json' localhost:8080/books -d '{ "isbn": "978-1484280782", "title": "Java EE to Jakarta EE 10 Recipes: A Problem-Solution Approach for Enterprise Java", "price": 7163 }' {"isbn":"978-1484280782","title":"Java EE to Jakarta EE 10 Recipes: A Problem-Solution Approach for Enterprise Java","price":7163} $ curl -XPOST -H 'Content-Type: application/json' localhost:8080/books -d '{ "isbn": "978-1484282137", "title": "Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development", "price": 8373 }' {"isbn":"978-1484282137","title":"Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development","price":8373}
この時点で、JaegerのWeb UIを確認してみます。http://[Jaegerが動作しているホストのIPアドレス]:16686/
にアクセスしてみます。
アプリケーションのサービス名をapp
で登録したので、こちらで検索するとinfinispan-server
のSpanも紐付けられていることが確認できます。
Traceを選択して見てみましょう。
Infinispan ServerのSpanを開くと、こんな感じです。
OpenTelemetryのInstrumentationが不足しているので、リソースの情報が記録されませんね…。
OTEL_NODE_RESOURCE_DETECTORS
環境変数で記録するリソースを指定していましたが、意味がなさそうです…。
Infinispan Serverに含まれているOpenTelemetry SDKの依存関係は、これくらいです。
https://github.com/infinispan/infinispan/blob/14.0.19.Final/server/core/pom.xml#L127-L147
JAX-RS側だと、こんな感じに記録されます。
続いて、参照系のアクセスを行ってみましょう。
4 curl localhost:8080/books [{"isbn":"978-1484282137","title":"Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development","price":8373},{"isbn":"978-1484280782","title":"Java EE to Jakarta EE 10 Recipes: A Problem-Solution Approach for Enterprise Java","price":7163}] $ curl localhost:8080/books/978-1484282137 {"isbn":"978-1484282137","title":"Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development","price":8373}
ここで、JaegerのWeb UIを確認してみます。
参照系の時は、Infinispan ServerのSpanが記録されていません。
サービスinfinispan-server
で絞り込んでも表示されないので、本当にありません。
というわけで、前段にも書きましたが、現時点ですべての操作のトレースデータが記録されるわけではありません。
ひとまず、最低限の動作確認としてはOKです。
Hot Rod Clientのトレースコンテキストの伝播を無効にしてみる
最後にHot Rod Clientのトレースコンテキストの伝播を無効にしてみましょう。
Hot Rod ClientでInfinispan Serverに接続する時のURIを、こちらから
String uri = """ hotrod://ispn-user:password@172.18.0.2:11222,172.18.0.3:11222,172.18.0.4:11222\ ?context-initializers=org.littlewings.infinispan.remote.otlp.EntitiesInitializerImpl\ """;
こうしてみます。tracing.propagation_enabled
をfalse
にしました。
String uri = """ hotrod://ispn-user:password@172.18.0.2:11222,172.18.0.3:11222,172.18.0.4:11222\ ?tracing.propagation_enabled=false\ &context-initializers=org.littlewings.infinispan.remote.otlp.EntitiesInitializerImpl\ """;
あとは、ビルドして再実行。
$ mvn package $ java -javaagent:opentelemetry-javaagent.jar -jar target/remote-opentelemetry-tracing-0.0.1-SNAPSHOT.jar
トレースデータが記録される、更新処理を行ってみます。
$ curl -XPOST -H 'Content-Type: application/json' localhost:8080/books -d '{ "isbn": "978-1484280782", "title": "Java EE to Jakarta EE 10 Recipes: A Problem-Solution Approach for Enterprise Java", "price": 7163 }' {"isbn":"978-1484280782","title":"Java EE to Jakarta EE 10 Recipes: A Problem-Solution Approach for Enterprise Java","price":7163} $ curl -XPOST -H 'Content-Type: application/json' localhost:8080/books -d '{ "isbn": "978-1484282137", "title": "Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development", "price": 8373 }' {"isbn":"978-1484282137","title":"Pro Jakarta EE 10: Open Source Enterprise Java-based Cloud-native Applications Development","price":8373}
JaegerのWeb UIで確認してみましょう。上2つのトレースデータが、URI変更後に行った操作に該当します。
今回は、app
とinfinispan-server
の紐付けがなくなりましたね。
トレースコンテキストが伝播していないことは、サービス名infinispan-server
で検索するとわかります。
というわけで、これでHot Rod Client側が行っているトレースコンテキスト伝播の役割が確認できましたね。
トレースコンテキストの伝播を無効にすると、トレースが分断されてしまうので嬉しくないというか、Infinispan ServerのSpanが
独立したトレースになってしまうので意味がありません…。
これで、今回やりたかったことは確認できました。
少し実装を追ってみる
最後に、少し実装を追ってみましょう。
Hot Rod Client
まずはHot Rod Client側です。
Hot Rod Client側では、トレースコンテキスの伝播が無効になっていない場合(デフォルト)
OpenTelemetry SDKに含まれるW3CTraceContextPropagator
クラスがクラスパス上に存在する場合、TelemetryServiceImpl
の
インスタンス(TelemetryService
インターフェースの実装クラス)を作成します。
TelemetryServiceImpl
がやっているのは、トレースコンテキストの伝播そのものですね。
これがどこで使われるかというと、RetryOnFailureOperation
抽象クラスです。TelemetryService
のインスタンスがnull
でない場合に
使われます。
RetryOnFailureOperation
クラスは、キャッシュの各操作を表すクラスの親クラスになっています。
たとえばCache#put
に対応するPutOperation
ではコンストラクタでTelemetryService
のインスタンスを渡しています。
一方で、Cache#get
に相当するGetOperation
では、親クラスのコンストラクタを呼び出す際に渡すTelemetryService
のインスタンスは
常にnull
です。
つまり、仮にInfinispan Server側で参照系の処理のトレースデータを記録するようにしても、ここが追従しないと参照系の処理の
トレースコンテキストの伝播は途切れることになります。現時点だと意図的にこうなっているようなので仕方ありません。
現時点でなんとかしたかったら、手動で伝播させるようにするんでしょうね。
どの操作がOpenTelemetryに対応していて、どの操作が対応していないかはわからないので、以下のパッケージからひとつひとつ
見ていくか、実際に動作させるしかありません…。
Server側
Server側です。
まず、システムプロパティinfinispan.tracing.enabled
を参照してOpenTelemetryとのインテグレーションを切り替えているのは、こちら。
そしてトレースデータ生成のところですが。
Infinispan Server(Hot Rodプロトコル)では、こちらを見るとよいでしょう。
たとえばput操作だと、HotRodTelemetryService#requestStart
とHotRodTelemetryService#requestEnd
でSpanを開始、終了していることが
わかります。
反対にget操作だと、HotRodTelemetryService
に対する操作が登場しません。
これが操作によってトレースデータが生成されたり、されなかったりすることになる理由ですが。対応範囲は、
CacheRequestProcessor
クラスを見ることで良さそうです。
おわりに
Infinispan Server 14で追加された、OpenTelemetryトレーシングとのインテグレーションを試してみました。
トレースデータが生成される場所がInfinispan Serverだったり、クライアント側の対応はトレースコンテキストの伝播の役割だったりと
ちょっと不思議なのですが。
使い方はわかったので、今回は良しとしておきましょう。
今回作成したソースコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-opentelemetry-tracing