paint-brush
Spring BootでのOpenTelemetryトレース: JavaエージェントとMicrometerの選択@nfrankel
193 測定値

Spring BootでのOpenTelemetryトレース: JavaエージェントとMicrometerの選択

Nicolas Fränkel8m2024/08/11
Read on Terminal Reader

長すぎる; 読むには

この投稿では、Java Agent v1、Java Agent v2、Micrometer Tracing を使用した Spring Boot アプリケーションの OpenTelemetry トレース ソリューションを比較します。構成、機能、トレース機能の違いを強調し、可観測性に対する各アプローチの有効性と適用性についての洞察を提供します。
featured image - Spring BootでのOpenTelemetryトレース: JavaエージェントとMicrometerの選択
Nicolas Fränkel HackerNoon profile picture

OpenTelemetry Tracing のデモには、2 つの Spring Boot コンポーネントが含まれています。1 つは Java エージェントを使用しており、最近 v1.x から v2.x にアップグレードしたときに動作が異なることに気付きました。もう 1 つは、GraalVM ネイティブにコンパイルするため、Micrometer Tracing を使用していますが、Java エージェントを処理できません。



この記事では、Java エージェント v1、Java エージェント v2、Micrometer Tracing の 3 つのアプローチを比較します。

ベースアプリケーションとそのインフラストラクチャ

同じベース アプリケーション、つまり Kotlin でコーディングされたシンプルな Spring Boot アプリケーションを使用します。単一のエンドポイントを提供します。


  • エンドポイントを超えた関数はentry()という名前です
  • これはintermediate()という別の関数を呼び出します。
  • 後者は、 RestTemplateの代わりとなるWebClientインスタンスを使用して、上記のエンドポイントを呼び出します。
  • 無限ループを避けるために、カスタムリクエストヘッダーを渡します。entry entry()関数がそれを見つけた場合、それ以上先に進みません。


サンプルアプリのシーケンス図


これは次のコードに変換されます。


 @SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } }


すべてのセットアップについて、OpenTelemetry が有効になっているプライマリ ステージと、追加の内部スパンを作成するためのカスタマイズ ステージの 2 つのステージを確認します。

マイクロメータトレース

Micrometer Tracing は、「ベンダー中立のアプリケーション可観測性ファサード」であるMicrometerから派生したものです。


Micrometer Tracing は、最も人気のあるトレーサー ライブラリのシンプルなファサードを提供し、ベンダー ロックインなしで JVM ベースのアプリケーション コードをインストルメント化できるようにします。トレースの収集アクティビティにオーバーヘッドをほとんど追加せず、トレース作業の移植性を最大限に高めるように設計されています。


--マイクロメータートレースサイト


Micrometer Tracing を開始するには、いくつかの依存関係を追加する必要があります。


  • Spring Boot アクチュエータ、 org.springframework.boot:spring-boot-starter-actuator
  • マイクロメータートレース自体、 io.micrometer:micrometer-tracing
  • ターゲット トレース バックエンド API への「ブリッジ」。私の場合は OpenTelemetry なので、 io.micrometer:micrometer-tracing-bridge-otelです。
  • バックエンドへの具体的なエクスポーター、 io.opentelemetry:opentelemetry-exporter-otlp


バージョンは Spring Boot の親ですでに定義されているため、BOM は必要ありません。


ただし、トレースの送信先とコンポーネントの名前という 2 つのランタイム構成パラメータが必要です。これらは、 MANAGEMENT_OTLP_TRACING_ENDPOINT変数とSPRING_APPLICATION_NAME変数によって制御されます。


 services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3
  1. JaegerのOpenTelemetryコレクターを有効にする
  2. Jaeger OpenTelemetry gRPC エンドポイントへの完全な URL
  3. OpenTelemetryのサービス名を設定する


結果は次のとおりです。

カスタマイズなしの Jaeger のマイクロメーター トレース


カスタマイズを行わない場合、Micrometer は HTTP リクエストの受信と送信時にスパンを作成します。


フレームワークは、送信のためにRestClientに魔法を注入する必要があります。そのためには、前者が後者をインスタンス化できるようにする必要があります。


 @SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() }


手動スパンは、OpenTelemetry API 自体を使用する方法など、いくつかの方法で作成できます。ただし、セットアップには多くの定型コードが必要です。最も簡単な方法は、Micrometer のObservation API を使用することです。その主な利点は、メトリックトレースの両方を管理する単一の API を使用できることです。


観測APIクラス図

更新されたコードは次のとおりです。


 class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } }


追加された観察呼び出しは、生成されたトレースに反映されます。


Observation API を使用した Jaeger のマイクロメーター トレース

オープンテレメトリエージェント v1

Micrometer Tracing の代替として、汎用OpenTelemetry Java Agentがあります。その主な利点は、コードにも開発者にも影響を与えないことです。エージェントは、純粋にランタイム スコープの問題です。


 java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar


エージェントは、環境変数を使用した OpenTelemetry の構成に従います。


 services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080"
  1. プロトコル、ドメイン、ポートを設定します。ライブラリは/v1/tracesを追加します。
  2. OpenTelemetryのサービス名を設定する
  3. メトリックもログもエクスポートしない


これ以上の設定を行わない場合、次のトレースが得られます。


カスタマイズなしの Jaeger 上の Agent v1 トレース


エージェントは、受信および送信されたリクエストと、Spring 関連のアノテーションでマークされた関数を自動的に追跡します。トレースは、コール スタックに従って、互いに正しくネストされます。追加の関数をトレースするには、コードベースに依存関係io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotationsを追加する必要があります。これで、以前はトレースされていなかった関数に@WithSpanアノテーションを付けることができます。

@WithSpan クラス図


value()部分はトレースのラベルを制御し、 kind span.kind属性として変換されます。値が空の文字列に設定されている場合 (デフォルト)、関数の名前が出力されます。私の目的には、デフォルト値で十分です。


 @WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() }


期待どおりの新しいintermediate()トレースが生成されます。

注釈付きの Jaeger 上の Agent v1 トレース

オープンテレメトリエージェント v2

OpenTelemetry は今年 1 月にエージェントの新しいメジャー バージョンをリリースしました。私はデモをそれに合わせて更新しました。これで、トレースはアプリがリクエストを受信および送信するときにのみ作成されるようになりました。

カスタマイズなしの Jaeger 上の Agent v2 トレース


以前のバージョンと同様に、 @WithSpanアノテーションを使用してトレースを追加できます。唯一の違いは、 entry()関数にもアノテーションを付けなければならないことです。デフォルトではトレースされません。

注釈付きの Jaeger 上の Agent v2 トレース


議論

Spring が成功した理由は 2 つあります。複雑なソリューション (EJB 2など) を簡素化し、競合ライブラリに対する抽象化レイヤーを提供したことです。Micrometer Tracing は Zipkin と Jaeger に対する抽象化レイヤーとして始まり、完全に理にかなったものでした。この議論は、OpenTelemetry がプログラミング言語やトレース コレクターのほとんどのライブラリでサポートされているため、意味をなさなくなりました。Observation API は、Metrics と Traces に対して単一の API を使用するため、依然として Micrometer Tracing の大きな利点です。


Java エージェント側では、OpenTelemetry 構成はすべての技術スタックとライブラリ (環境変数) で同様です。新しいエージェントは Spring に対応していないため、v1 から v2 にアップグレードしたときに少しがっかりしました。Spring アノテーション付き関数はデフォルトではトレースされません。


結局のところ、これは賢明な決断です。表示したくないスパンを削除するよりも、必要なスパンを明示的に指定したほうがはるかに良いのです。


ご協力とレビューをいただいたJonatan Ivanov 氏に感謝します


この投稿の完全なソースコードは GitHub で見つかります:

さらに進むには:


2024年8月3日にA Java Geekで最初に公開されました