OTEL、Jaeger、およびPrometheusでサービスを制御する

重要な問題を議論しましょう:何かがうまくいかない場合、どのようにしてサービスを監視するか?

一方で、アラートを備えたPrometheusやダッシュボードなどの便利な機能を備えたKibanaがあります。また、ELKスタックを使用してログを収集する方法も知っています。ただし、単純なログ記録だけでは常に十分ではありません。それは、要求がコンポーネントの全エコシステムを横断する旅の包括的なビューを提供してくれません。

ELKに関する詳細はこちらで確認できます。

しかし、リクエストを視覚化したい場合はどうでしょうか?システム間を移動するリクエストを相関させる必要がある場合はどうでしょうか?これはマイクロサービスでもモノリスでも適用されます。重要なのは、サービスの数ではなく、その遅延をどのように管理するかです。

実際に、各ユーザーリクエストは独立したサービス、データベース、メッセージキュー、外部APIを通過する可能性があります。

そのような複雑な環境では、遅延が発生している具体的な場所を特定したり、どの部分がパフォーマンスのボトルネックとして機能しているかを特定したり、障害の原因を迅速に見つけることが非常に困難になります。

これらの課題に効果的に対処するためには、トレース、メトリクス、ログなどのテレメトリデータを収集するための中央集権的で一貫したシステムが必要です。そのために、OpenTelemetryとJaegerが救世主として登場します。

基本を見てみましょう

理解する必要がある2つの主要な用語があります:

トレースID

トレースIDは16バイトの識別子で、通常は32文字の16進数文字列として表されます。トレースの開始時に自動的に生成され、特定のリクエストによって作成されたすべてのスパンで同じままです。これにより、リクエストがシステム内のさまざまなサービスやコンポーネントを通過する方法が簡単に確認できます。

スパンID

トレース内の個々の操作ごとに固有のスパンIDが割り当てられ、通常はランダムに生成される64ビットの値です。スパンは同じトレースIDを共有しますが、それぞれが固有のスパンIDを持つため、各スパンがワークフローのどの部分を表しているかを正確に特定できます(たとえば、データベースクエリや他のマイクロサービスへの呼び出し)。

それらはどのように関連していますか?

トレースID スパンIDはお互いを補完します。

リクエストが開始されると、トレースIDが生成され、関係するすべてのサービスに渡されます。その後、それぞれのサービスは、トレースIDにリンクされた固有のスパンIDを持つスパンを作成し、リクエストの開始から終了までの完全なライフサイクルを視覚化できるようにします。

では、なぜJaegerを使用しないのですか OTEL(OpenTelemetry)やその仕様が必要な理由は何ですか それは素晴らしい質問です!ステップバイステップで解説していきましょう。

Jaegerの詳細はこちらでご確認いただけます。

要約

  • Jaegerは、分散トレースを保存および可視化するシステムです。リクエストがサービスを通過する過程を示すデータを収集、保存、検索、表示します。
  • OpenTelemetry(OTEL)は、アプリケーションやインフラストラクチャからテレメトリデータ(トレース、メトリクス、ログ)を収集するための標準(およびライブラリのセット)です。特定の可視化ツールやバックエンドに結び付けられていません。

簡単に言うと:

  • OTELは、テレメトリ収集のための「汎用言語」とライブラリのセットです。
  • Jaegerは、分散トレースを表示および分析するためのバックエンドおよびUIです。

なぜJaegerがすでにあるのにOTELが必要なのか?

1. 収集のための単一の標準

過去には、OpenTracingやOpenCensusなどのプロジェクトがありました。OpenTelemetryはこれらのメトリクスとトレースを収集するアプローチを1つの汎用標準に統一します。

2. 簡単な統合

Go(または他の言語)でコードを記述し、自動インジェクションインターセプターとスパンのためのOTELライブラリを追加するだけです。その後、データを送信したい場所はどこでも問題ありません—Jaeger、Tempo、Zipkin、Datadog、カスタムバックエンド—OpenTelemetryが配管を処理します。単にエクスポーターを交換するだけです。

3. トレースだけでなく

OpenTelemetryはトレースをカバーしていますが、メトリクスとログも取り扱います。追跡だけでなく、すべてのテレメトリニーズのための単一のツールセットが得られます。

4. バックエンドとしてのJaeger

Jaegerは、分散トレースの可視化に主に興味がある場合には優れた選択肢です。しかし、デフォルトではクロスランゲージの計測を提供しません。一方、OpenTelemetryはデータを収集するための標準化された方法を提供し、その後どこに送信するか(Jaegerを含む)を決定します。

実際には、彼らはしばしば一緒に機能します:

あなたのアプリケーションはOpenTelemetryを使用し→OTLPプロトコルを介して通信し→OpenTelemetryコレクター(HTTPまたはgRPC)に送信し→可視化のためにJaegerにエクスポートします。


テクニカル部分

システム設計(少しだけ)

以下のことを行ういくつかのサービスを簡単に描いてみましょう:

  1. 購入サービス – 支払いを処理し、MongoDBに記録します
  2. Debeziumを使用したCDC – MongoDBテーブルの変更をリッスンし、それをKafkaに送信します
  3. 購入プロセッサ – Kafkaからメッセージを消費し、検証のためにAuth Serviceにuser_idを照会します
  4. Auth Service – シンプルなユーザーサービス

要約すると:

  • 3つのGoサービス
  • Kafka
  • CDC(Debezium)
  • MongoDB

コード部分

インフラストラクチャから始めましょう。すべてを1つのシステムにまとめるために、大きなDocker Composeファイルを作成します。まず、テレメトリーの設定を行います。

注意: すべてのコードは、記事の最後にリンクを介して利用できます。その中にはインフラストラクチャも含まれます。

YAML

 

また、テレメトリを収集するコンポーネントであるコレクターを構成します。

ここでは、データ転送に gRPC を選択し、通信は HTTP/2 を介して行われます。

YAML

 

必要に応じてアドレスを調整して、ベースの構成が完了です。

既に OpenTelemetry(OTEL)が2つの重要な概念、トレースIDスパンID、を使用してリクエストを分散システムで追跡および監視することがわかっています。

コードの実装

さて、Goコードでこれを動作させる方法を見てみましょう。以下のimport文が必要です:

Go

 

次に、アプリケーションの起動時にmain()内でトレーサーを初期化する関数を追加します:

Go

 

トレースが設定されているため、コード内にスパンを配置して呼び出しを追跡するだけです。たとえば、パフォーマンスの問題を解決する場合は通常最初にデータベース呼び出しを測定したいので、次のように記述できます:

Go

 

サービス層でトレースを行っていますが、データベース層にさらに深く入り込むこともできます:

Go

 

これで、リクエストの経過を完全に把握できます。Jaeger UI に移動し、auth-serviceの下で最後の20件のトレースをクエリし、すべてのスパンとそれらがどのようにつながっているかを1か所で確認できます。

今、すべてが見えるようになりました。必要な場合は、クエリ全体をタグに含めることができます。ただし、テレメトリを過負荷にしないように注意してください。データを慎重に追加してください。私は単に可能なことを示しているだけですが、通常はこの方法でクエリ全体を含めることはお勧めしません。

gRPCクライアントサーバ

2つのgRPCサービスにまたがるトレースを見たい場合、非常に簡単です。必要なのは、ライブラリから提供されているインターセプターを追加するだけです。たとえば、サーバーサイドでは次のようにします:

Go

 

クライアントサイドでは、コードは同じくらい短くなります:

Go

 

それだけです!エクスポーターが正しく構成されていることを確認し、クライアントがサーバーを呼び出すときにこれらのサービス全体で単一のトレースIDが記録されるのを見ることができます。

CDCイベントの処理とトレース

CDCからのイベントを処理したいですか?1つの簡単なアプローチは、MongoDBが保存するオブジェクトにトレースIDを埋め込むことです。これにより、Debeziumが変更をキャプチャしKafkaに送信するときに、トレースIDがレコードの一部としてすでに含まれています。

たとえば、MongoDBを使用している場合、次のようなことができます:

Go

 

その後、Debeziumはこのオブジェクト(trace_idを含む)を拾い上げ、Kafkaに送信します。コンシューマ側では、受信メッセージを単純に解析し、trace_idを抽出してトレースコンテキストにマージします:

Go

 

Go

 

別の方法:Kafkaヘッダーの使用

時々、Trace IDをペイロード自体ではなく、Kafkaヘッダーに保存する方が簡単です。CDCワークフローでは、これがデフォルトで利用可能ではないことがあります — Debeziumはヘッダーに追加される情報を制限することがあります。しかし、プロデューサーサイドを制御できる場合(または標準のKafkaプロデューサーを使用している場合)、Saramaを使用して次のようなことができます:

ヘッダーへのTrace IDの挿入

Go

 

コンシューマーサイドでのTrace IDの抽出

Go

 

ユースケースやCDCパイプラインの設定に応じて、最適なアプローチを選択できます:

  1. データベースレコードにTrace IDを埋め込むことで、CDCを介して自然にフローさせることができます。
  2. Kafkaヘッダーを使用すると、プロデューサーサイドでより多くの制御が可能になり、メッセージペイロードの膨張を避けることができます。

いずれの場合も、KafkaとDebeziumを介して非同期に処理されるイベントでも、複数のサービス間でトレースを一貫させることができます。

結論

OpenTelemetryとJaegerを使用することで、詳細なリクエストトレースを提供し、分散システムで遅延が発生する原因や場所を特定するのに役立ちます。

Prometheusを追加することで、メトリクス(パフォーマンスや安定性の主要な指標)も含めることができます。これらのツールを組み合わせることで、包括的な観測スタックが形成され、より迅速な問題検出と解決、パフォーマンスの最適化、システム全体の信頼性が実現されます。

このアプローチは、マイクロサービス環境でのトラブルシューティングを大幅に加速し、プロジェクトに実装する最初のアプローチの1つです。

リンク

Source:
https://dzone.com/articles/control-services-otel-jaeger-prometheus