理想的には、分散トレーシングを使用してシステム全体のリクエストをトレースする必要がありますが、Kafka はプロデューサーとコンシューマーが分離されているため、両者間を直接トレースできるトランザクションはありません。また Kafka では、明示的ではなく暗黙的な依存関係を持つ非同期プロセスも使用されます。そのため、マイクロサービスがどのように連携しているかを把握することが困難です。
ただし、分散トレーシングと OpenTelemetry を使用して Kafka クラスタをモニターすることは可能です。Jaeger などのオープンソースの分散トレースツールや New Relic などのオブザーバビリティプラットフォームを利用してトレースを分析および視覚化することができます。この記事では、シンプルなアプリケーションを活用して、これを実現する方法を説明します。
設計上の考慮事項とガイドライン
OpenTelemetry には通常、次の2つのアプローチがあります。
これらのアプローチについて説明する際、私は通常、上記の例え話を使います。既製のケーキを買って楽しむことも、材料をすべて買って自分でケーキを作ることもできます。OpenTelemetry のアプローチも非常に似ています。それぞれのアプローチの長所・短所は次のとおりです。
- ゼロコード計装:このアプローチでは、OpenTelemetry エージェントを使用し、起動時にアプリケーションにアタッチします。このエージェントが魔法のように機能し、多くのテレメトリーシグナル (メトリクス、トレース、ログ) とアプリケーションに関するインサイトを自動的に(ソースコードを変更することなく)提供します。
- 長所:
- すぐに始められる
- ソースコードの変更なし
- 短所:
- カスタマイズが制限される
- アプリケーションの可視性の深さが制限される可能性がある
- 長所:
- 手動による計装:このオプションでは、通常のソフトウェア開発ライフサイクル (SDLC) の一環として管理する必要がある依存関係とパッケージをソースコードに追加する必要があります。ただし、これにより、計装をより具体的にカスタマイズすることも可能になります。カスタムメトリック、トレース、属性を簡単にテレメトリーに追加できます。
- 長所:
- テレメトリーのカスタマイズがはるかに柔軟
- 計装の深さを簡単に追加、削除、調整可能
- 短所:
- ソースコード内の依存関係
- 実装にかかる労力が増える
- 長所:
サンプルアプリケーション
このブログで使用しているサンプルアプリケーション (この 公開GitHubリポジトリ で入手可能) は、次の高レベルアーキテクチャーに基づいています。
次のコンポーネントが含まれています。
- kafka-java-producer:Kafka トピックにメッセージを生成する Java Spring Boot アプリケーション
- Kafka broker
- kafka-java-consumer:Kafka トピックをサブスクライブし、そこからメッセージを読み取る Java Spring Boot アプリケーション。このコンポーネントは、外部の REST API サービス (当社の管理下にない) への呼び出しも行います
- kafka-java-service:コンシューマーサービスから呼び出される下流の Java Spring Boot アプリケーション
ゼロコード計装
まずは、ゼロコード計装、つまり自動計装から始めましょう。
設定
それぞれのサービスには、サービスを起動して実行するための「run.sh」スクリプトが含まれています。スクリプトは次のようになります。
ここで重要なのは最初の行です。ここでは JAVA_TOOL_OPTIONS を定義し、OpenTelemetry Javaエージェント の場所を指すように「-javaagent」を設定しています。
続く 3行は、各テレメトリーシグナルをどのように処理するかを設定します。今回のケースでは OpenTelemetry Line Protocol (OTLP) を介してエクスポートされるトレース、メトリクス、ログを定義します。
特に重要な環境変数は下記の 3つです。
- OTEL_EXPORTER_OTLP_ENDPOINT:データのエクスポート先となるターゲットシステム(つまり、テレメトリーバックエンド)。私の場合はNew Relic なので、New Relic のネイティブ OTLP エンドポイントを設定します。
- OTEL_EXPORTER_OTLP_HEADERS:上記のエクスポーターエンドポイントはオープンな API なので、API キーを設定する必要があります。New Relic の場合は、New Relic の License Key です。
- OTEL_SERVICE_NAME:サービス名として分かりやすい名前を付けてください。
基本的に設定する必要があるのはこれだけです。その他すべては OpenTelemetry Java エージェントによって処理されます。ソースコードを変更する必要はありません。
オブザーバビリティ
ゼロコード計装によって、サービスに対してどの程度の可視性を実現できるかを見てみましょう。
New Relic アカウントに移動すると、すべてのサービスが個別のエンティティにレポートされていることがわかります。
まず、kafka-java-producer サービスを調べてみましょう。
Summary (概要) ビューには、注目すべき重要なテレメトリーとメトリクスの概要が表示されます。
このブログでは、Distributed tracing (分散トレーシング) のセクションに興味があるので、この項目についてさらに詳しく見ていきましょう。
1つのトレースを調べることで、この特定のトレースの実行にかかった時間と、時間が費やされた場所に関する詳細な情報を確認できます。
また、特定のトレースに関係するさまざまなサービスすべてのエンティティマップも自動的に描画します。
ここで興味深いのは「Uninstrumented time (未計装領域の処理時間)」と表示されているスパンです。これはエージェントが内部メソッドで何が起こっているかに関する詳細な情報を取得できなかったコンシューマー内のコードです。
これはゼロコード計装の限界を示しています。エージェントはデフォルトではさまざまなメソッドやソースコードすべてを計装するのではなく、意図的にあるレベルで停止して、コードの処理をより広く可視化します。
手動による計装
前のセクションでは、アプリケーションの可視性に関して、ゼロコード計装にはいくつかの制限があることを説明しました。まさにここで手動計装が活躍します。
設定
同じアプリケーションを設定しましたが、今回はアプリケーションの起動時にエージェントを一切設定しません。
アプリケーションを実行するには、Maven wrapper を使用するだけです。
その他の設定の詳細は application.properties に記述します。
これらのプロパティは Spring Boot アプリケーションコードで使用され、トレース、メトリクス、ログの OpenTelemetry の設定を定義します。
オブザーバビリティ
手動計装の実装方法の詳細に入る前に、まず結果を見てみましょう。
以前は「Uninstrumented time」と表示されていたスパンが、この場合ではより詳細な情報を表示していることにお気づきでしょうか?以下の追加スパンが表示されるようになりました。
- ExecuteLongRunningTask
- WhyTheHeckDoWeSleepHere
- SomeTinyTask
- AnotherShortRunningTask
「WhyTheHeckDoWeSleepHere」と表示されているスパンが一番時間がかかっているようです。名前の通り、不思議ではありません😉。
ソースコードを見て、私が実装した手動計装を確認してみましょう。
ExecuteLongRunningTask というメソッドで、spanBuilder() メソッドを使用して現在のトレーサーに新しいスパンを作成しました。
それに加えて、ほんの楽しみのために、「WhyTheHeckDoWeSleepHere」という別のスパンを作成しました。これには、現在のスレッドでの人工的にスリープを行う命令が含まれています。
OpenTelemetry SDK を活用するこれらの概念により、アプリケーションとソースコードに関するインサイトとその詳細をより具体的に得ることができます。しかし、ご想像のとおり、ソースコード内にいくつかの依存関係とカスタムコードを用意する必要があるという注意点もあります。
まとめ
OpenTelemetry を活用してアプリケーションやサービスに関するインサイトを得ることがいかに簡単かをお見せできたと思います。コードを変更せずに開始するためにゼロコード計装を検討しましたが、詳細レベルが制限される可能性があります。次に、手動計装についても検討しました。これにより、より具体的に計装をカスタマイズできるようになりましたが、導入にかかる労力は少々高くなります。
OpenTelemetry とその魅力的な機能をぜひご覧ください。ご意見をお聞かせください。ご質問やさらに詳しい情報が必要な場合は、お気軽にご連絡ください。
楽しくコーディングしましょう!
本ブログに掲載されている見解は著者に所属するものであり、必ずしも New Relic 株式会社の公式見解であるわけではありません。また、本ブログには、外部サイトにアクセスするリンクが含まれる場合があります。それらリンク先の内容について、New Relic がいかなる保証も提供することはありません。