パフォーマンスチューニングガイド
より良いパフォーマンスを実現するための Jaeger インスタンスの調整
Jaeger は、最初から大量のデータを耐障害性のある方法で取り込むことができるように設計されています。ストレージやネットワーク通信など、遅延の原因となる可能性のあるリソースをより有効に活用するために、Jaeger はデータをバッファリングしてバッチ処理します。Jaeger が安全に処理できるよりも多くのスパンが生成されると、スパンがドロップされる可能性があります。ただし、デフォルト設定はすべてのシナリオに適しているとは限りません。
デプロイに関する考慮事項
個々のコンポーネントのパフォーマンスチューニングは重要ですが、Jaeger のデプロイ方法は、最適なパフォーマンスを得る上で決定的な役割を果たす可能性があります。
コレクターのスケールアップとスケールダウン
プラットフォームの自動スケーリング機能を使用します。**jaeger-collector** はほぼ水平方向にスケール可能であるため、オンデマンドでインスタンスを追加および削除できます。スケールアップとスケールダウンを行う良い方法は、`jaeger_collector_queue_length` メトリックを確認することです。長期間にわたって長さが最大サイズの 50% を超える場合は、インスタンスを追加します。考慮できるもう 1 つのメトリックは `jaeger_collector_in_queue_latency_bucket` で、これはワーカーがスパンを拾う前にキューで待機していた時間を示すヒストグラムです。キューの待ち時間が時間の経過とともに長くなる場合は、ワーカーの数を増やすか、ストレージのパフォーマンスを向上させることをお勧めします。
プラットフォームが自動スケーリング機能を提供する場合、または実行中のインスタンスを変更するよりも **jaeger-collector** インスタンスの起動/停止が容易な場合は、**jaeger-collector** インスタンスを追加することをお勧めします。CPU 使用率をノード間で分散する必要がある場合にも、水平方向へのスケーリングが推奨されます。
ストレージが追いつけるようにする
各スパンは、1 つのワーカーを使用して **jaeger-collector** によってストレージに書き込まれ、スパンが保存されるまでブロックされます。ストレージが遅すぎる場合、ストレージによってブロックされるワーカーの数が多くなりすぎて、スパンがドロップされる可能性があります。この状況の診断に役立つように、ヒストグラム `jaeger_collector_save_latency_bucket` を分析できます。理想的には、待ち時間は時間の経過とともに同じままである必要があります。ヒストグラムで、ほとんどのスパンが時間の経過とともにますます時間がかかることを示している場合、ストレージに注意が必要であることを示しています。
エージェントをアプリケーションの近くに配置する
**jaeger-agent** は、ネットワーク経由での UDP パケット損失を回避するために、計測対象のアプリケーションと同じホストに配置することを目的としています。これは、従来のアプリケーションではベアメタルホストごとに 1 つの **jaeger-agent** を持つことによって、または Kubernetes などのコンテナ環境でサイドカーとして配置することによって通常達成されます。これは、**jaeger-agent** で処理される負荷を分散するのに役立ち、さらに各 **jaeger-agent** をアプリケーションのニーズと重要度に応じて個別に調整できるという利点があります。
中間バッファとして Apache Kafka を使用する
Jaeger はApache Kafka を使用して、**jaeger-collector** と実際のバックエンドストレージ(Elasticsearch、Apache Cassandra)の間にバッファを作成できます。これは、トラフィックのスパイクが比較的頻繁に発生する(ピークタイムのトラフィック)が、トラフィックが正常化するとストレージが最終的に追いつくことができる場合に理想的です。そのため、**jaeger-collector** で `SPAN_STORAGE_TYPE` 環境変数を `kafka` に設定し、Kafka からデータを読み取ってストレージに書き込む **jaeger-ingester** コンポーネントを使用する必要があります。
パフォーマンスの側面に加えて、スパンを Kafka に書き込むことは、トレースからの集計と機能抽出のためのリアルタイムデータパイプラインを構築するのに役立ちます。
**jaeger-collector** は、ストレージに直接書き込む場合と同様にスケーリングできます。トレース ID は Kafka パーティションのシャーディングキーとして使用され、特定のトレースのすべてのスパンが Kafka トピックの同じパーティションに配置されます。各 **jaeger-collector** は任意のパーティションに書き込むことができます。
**jaeger-ingester** も必要に応じてスケーリングしてスループットを維持できます。これらは自動的に Kafka パーティションをネゴシエートして再バランスします。ただし、Kafka トピックのパーティション数よりも多くの **jaeger-ingester** を実行しても意味はありません。この場合、一部の **jaeger-ingester** はアイドル状態になります。
クライアント(トレーサー)設定
Jaeger クライアントは、計測対象のアプリケーションへの影響を最小限に抑えるように構築されています。そのため、すべてのケースに適しているとは限らない保守的なデフォルト値が設定されています。Jaeger クライアントは、プログラムで、または環境変数を介して構成できることに注意してください。
サンプリング設定の調整
`JAEGER_SAMPLER_TYPE` と `JAEGER_SAMPLER_PARAM` は、トレースを「サンプリング」する頻度、つまり Jaeger バックエンドに記録して送信する頻度を指定します。多くのスパンを生成するアプリケーションの場合、サンプリングタイプを `probabilistic` に、値を `0.001`(デフォルト)に設定すると、1/1000 の確率でトレースが報告されます。サンプリングの決定はルートスパンで行われ、すべての子スパンに伝播されることに注意してください。
トラフィックが少ないアプリケーションの場合、サンプリングタイプを `const` に、値を `1` に設定すると、すべてのスパンが報告されます。同様に、値を `0` に設定するとトレースを無効にできますが、コンテキストの伝播は引き続き機能します。
一部のクライアントは、JAEGER_DISABLED
設定を使用してJaeger Tracerを完全に無効にすることをサポートしています。これは、トレーサーがインストルメント化されたアプリケーションに問題を引き起こすような動作をしている場合にのみ推奨されます。なぜなら、コンテキストをダウンストリームサービスに伝播しなくなるためです。
remote
サンプリング戦略を使用することをお勧めします。インメモリキューサイズの増加
Java、Go、C#クライアントなどのほとんどのJaegerクライアントは、jaeger-agent/jaeger-collectorに送信する前に、スパンをメモリにバッファリングします。このバッファの最大サイズは、環境変数JAEGER_REPORTER_MAX_QUEUE_SIZE
(デフォルト値:約100
スパン)で定義されます。サイズが大きいほど、潜在的なメモリ消費量が高くなります。インストルメント化されたアプリケーションが大量のスパンを生成している場合、キューがいっぱいになり、クライアントが新しいスパンを破棄することがあります(メトリックjaeger_tracer_reporter_spans_total{result="dropped",}
)。
ほとんどの場合、スパンは定期的に、またはバッチの特定のサイズに達したときにjaeger-agentまたはjaeger-collectorにフラッシュされるため、キューはほぼ空になります(メトリック:jaeger_tracer_reporter_queue_length
)。このキューの詳細な動作については、このGitHub issue を参照してください。
Thriftクライアントも、破棄されたスパンをjaeger-agentに報告します。これらはその後、jaeger-agent自体によってjaeger_agent_client_stats_spans_dropped_total{cause="full-queue|send-failure|too-large",}
として公開されます。これは、何らかの理由でクライアントメトリックが利用できない場合に役立ちます。
バッチ処理されたスパンのフラッシュ間隔の変更
Java、Go、NodeJS、Python、C#クライアントでは、RemoteReporter
などのレポーターがflush
操作をトリガーして、すべてのインメモリのスパンをjaeger-agentまたはjaeger-collectorに送信するために使用されるフラッシュ間隔(デフォルト値:1000
ミリ秒または1秒)をカスタマイズできます。フラッシュ間隔を小さく設定するほど、フラッシュ操作の頻度が高くなります。ほとんどのレポーターは、キューに十分なデータがあるまで待機するため、この設定により定期的な間隔でフラッシュ操作が強制的に実行され、スパンがタイムリーにバックエンドに送信されます。
インストルメント化されたアプリケーションが大量のスパンを生成し、jaeger-agent/jaeger-collectorがアプリケーションに近接している場合、ネットワークオーバーヘッドは低くなる可能性があり、より多くのフラッシュ操作を正当化します。HttpSender
が使用されており、jaeger-collectorがアプリケーションに十分に近接していない場合、ネットワークオーバーヘッドが高すぎる可能性があり、このプロパティの値を高くすることが理にかなっています。
エージェント設定
jaeger-agentはクライアントからデータを受信し、バッチでjaeger-collectorに送信します。正しく構成されていない場合、ホストマシンに十分なリソースがあっても、データが破棄される可能性があります。
サーバーキューサイズの調整
「サーバーキューサイズ」プロパティのセット(processor.jaeger-binary.server-queue-size
、processor.jaeger-compact.server-queue-size
、processor.zipkin-compact.server-queue-size
)は、jaeger-agentがメモリに受け入れて保存できるスパンバッチの最大数を示します。JavaおよびGoクライアントなど、ほとんどのクライアントで使用できる唯一のプロセッサであるため、jaeger-compact
がjaeger-agent設定で最も重要なプロセッサであると仮定するのは安全です。
各キューのデフォルト値は1000
スパンバッチです。各スパンバッチには最大64KiBのスパンが含まれるため、各キューは最大64MiBのスパンを保持できます。
通常シナリオでは、スパンバッチはワーカーによって迅速に取得および処理されるため、キューはほぼ空になります(メトリックjaeger_agent_thrift_udp_server_queue_size
)。ただし、クライアントによって送信されるスパンバッチの数に急増が発生する可能性があり、バッチがキューに格納される原因となります。キューがいっぱいになると、古いバッチが上書きされ、スパンが破棄されます(メトリックjaeger_agent_thrift_udp_server_packets_dropped_total
)。
プロセッサワーカーの調整
「プロセッサワーカー」プロパティのセット(processor.jaeger-binary.workers
、processor.jaeger-compact.workers
、processor.zipkin-compact.workers
)は、開始する並列スパンバッチプロセッサの数を示します。各ワーカートタイプには、デフォルトサイズ10
があります。一般的に、スパンバッチはサーバーキューに配置されるとすぐに処理され、パケット全体がjaeger-collectorに送信されるまでワーカーをブロックします。複数のクライアントからデータ処理を行うjaeger-agentの場合、ワーカーの数を増やす必要があります。各ワーカーのコストは低いため、良い経験則としては、中程度のトラフィックを持つクライアントごとに10個のワーカーです。各スパンバッチには最大64KiBのスパンが含まれる可能性があるため、10個のワーカーはjaeger-collectorに約640KiBを同時に送信できます。
コレクタ設定
jaeger-collectorは、クライアントとjaeger-agentからデータを受信します。正しく構成されていない場合、同じホストで可能なデータよりも少ないデータを処理するか、許可されたメモリよりも多くのメモリを消費することでホストに過負荷をかける可能性があります。
キューサイズの調整
jaeger-agentと同様に、jaeger-collectorはスパンを受信し、内部キューに格納して処理することができます。これにより、jaeger-collectorは、スパンがストレージに到達するのを待つ代わりに、クライアント/jaeger-agentにすぐに返答できます。
設定collector.queue-size
(デフォルト:2000
)は、キューがサポートするスパン数を決定します。通常シナリオでは、十分なワーカーがキューからスパンを取得してストレージに送信するため、キューはほぼ空になります。キュー内のアイテムの数(メトリックjaeger_collector_queue_length
)が常に高い場合、ワーカーの数を増やすか、ストレージが受信しているデータ量に対応できないことを示しています。キューがいっぱいになると、キュー内の古いアイテムが上書きされ、スパンが破棄されます(メトリックjaeger_collector_spans_dropped_total
)。
キューサイズはほとんどの場合ほぼ空である必要があるため、突然のトラフィックのスパイクに対する最大の保護を提供するために、この設定はコレクターで使用可能なメモリと同じくらい高くする必要があります。ただし、ストレージレイヤーのリソースが不足しており、追いつけない場合、大きなキューでもすぐにいっぱいになり、データの破棄が始まります。
実験的:Jaeger 1.17以降、jaeger-collectorはメモリ要件と平均スパンサイズに基づいてキューサイズを自動的に調整できます。フラグcollector.queue-size-memory
をjaeger-collectorが使用する最大メモリサイズ(MiB)に設定すると、Jaegerは観測された平均スパンサイズに基づいて理想的なキューサイズを定期的に計算します。安全上の理由から、最大キューサイズは100万レコードにハードコードされています。この機能を使用している場合は、フィードバックをお寄せください !
プロセッサワーカーの調整
jaeger-collectorのスパンキューからのアイテムは、ワーカーによって取得されます。各ワーカーはキューから1つのスパンを取得し、ストレージに永続化します。ワーカーの数は設定collector.num-workers
(デフォルト:50
)で指定でき、キューをゼロに近づけるために必要な数にする必要があります。一般的な規則は、バックエンドストレージが速いほど、ワーカーの数を少なくできるということです。ワーカーは比較的安価であるため、この数は自由に増やすことができます。一般的な規則として、ストレージが高速な場合、キュー内のアイテム50個につき1つのワーカーで十分です。collector.queue-size
が2000
の場合、約40
個のワーカーで十分です。ストレージメカニズムが遅い場合は、この比率を調整し、キューアイテムごとに多くのワーカーを使用する必要があります。