遅いトレースまたはエンドポイントを調査する

本番でパフォーマンス問題が見られる場合、分散トレーシングをプロファイリングのスタック トレース ベンチマークと統合することは、ボトルネックを特定する強力な方法です。APM 分散トレーシングと Continuous Profiler の両方を有効化しているアプリケーション プロセスは、自動的にリンクされます。

Profiles タブでは、スパン情報からプロファイリング データへ直接移動し、パフォーマンス問題に関連する特定のコード行を特定できます。同様に、Profiling UI で、遅くてリソース を多く消費するエンドポイントのデバッグも直接行えます。

遅いトレースでコードのパフォーマンス問題を特定する

前提条件

Linux と macOS 上で Java サービスのプロファイリングを有効化 すると、Trace to Profiling の統合はデフォルトで有効になります。Windows では利用できません。

手動インスツルメントしたコードでは、Continuous Profiler がスパンと関連付けるために Scope のアクティベーションが必要です:

final Span span = tracer.buildSpan("ServicehandlerSpan").start();
try (final Scope scope = tracer.activateSpan(span)) { // Datadog Continuous Profiler がスパンに関連付けるために必須
    // ワーカー スレッドの実装
  } finally {
    // ステップ 3: 作業が完了したら Span を終了する
    span.finish();
  }
Java Flight Recorder (JFR) の代わりに、Datadog プロファイラを使用する ことを強く推奨します。

次の場合に Trace to Profiling の統合が有効になります:

  • dd-trace-py を 2.12.0+、2.11.4+、または 2.10.7+ にアップグレードする。
  • 環境変数 DD_PROFILING_TIMELINE_ENABLEDtrue に設定する。
Ruby サービスのプロファイリングを有効化 し、dd-trace-rb を 1.22.0+ に更新すると、Trace to Profiling の統合はデフォルトで有効になります。

Linux と macOS 上で Node.js サービスのプロファイリングを有効化 すると、Trace to Profiling の統合はデフォルトで有効になります。機能は Windows では利用できません。

dd-trace-js 5.11.0+、4.35.0+、および 3.56.0+ が必要です。

Go サービスのプロファイリングを有効化 し、以下の環境変数を設定すると、Trace to Profiling の統合が有効になります:

os.Setenv("DD_PROFILING_EXECUTION_TRACE_ENABLED", "true")
os.Setenv("DD_PROFILING_EXECUTION_TRACE_PERIOD", "15m")

これらの変数を設定すると、実行トレース データを最大 1 分 (または 5 MiB) まで、15 分ごと に記録します。

このデータは次の場所で確認できます:

  • Profile List で、検索クエリに go_execution_traced:yes を追加します。プロファイルをクリックして Profile Timeline を表示します。さらに深く調査するには、プロファイルをダウンロードして go tool trace または gotraceui を使い、含まれている go.trace ファイルを表示します。
  • Trace Explorer で、検索クエリに @go_execution_traced:yes を追加します ( @ に注意)。スパンをクリックし、Profiles タブを選択して Span Timeline を表示します。

実行トレースを記録している間、アプリケーションでガーベジ コレクションに似た CPU 使用率の増加が観測される場合があります。ほとんどのアプリケーションにとって重大な影響はないはずですが、Go 1.21 にはこのオーバーヘッドを解消するための パッチ が含まれています。

この機能には dd-trace-go バージョン 1.37.0+ (タイムライン ビューでは 1.52.0+) が必要で、Go バージョン 1.18 以降で最適に動作します (タイムライン ビューは 1.21 以降)。

.NET サービスのプロファイリングを有効化 すると、Trace to Profiling の統合はデフォルトで有効になります。

この機能には dd-trace-dotnet バージョン 2.30.0+ が必要です。

PHP サービスのプロファイリングを有効化 し、次の条件を満たすと、Trace to Profiling の統合が有効になります:

  • dd-trace-php バージョン 0.98+ を使用している。
  • 環境変数 DD_PROFILING_TIMELINE_ENABLED=1 または INI 設定 datadog.profiling.timeline_enabled=1 を設定している。

スパン実行タイムライン ビュー

Profiles タブには、スレッドと実行を時間経過で分解して表示するタイムライン ビューがあります

タイムライン ビューは、スパン期間にわたる時間ベースのパターンと作業分布を可視化します。スレッドがリクエストにどのように寄与したかを時間経過で視覚的に分解して表示します。

スパン タイムライン ビューを使うと、次のことができます:

  • 時間のかかるメソッドを特定する
  • スレッド間の複雑な相互作用を整理する
  • リクエストに影響したランタイム アクティビティを可視化する
  • ビューで直接 Automated Analysis を活用して、過大なスレッド プールや GC 競合などのパフォーマンス問題を強調表示する

ランタイムや言語によって、レーンは異なります:

各レーンは スレッド を表します。共通のプールからのスレッドはグループ化されます。プールを展開して各スレッドの詳細を表示できます。

上部のレーンは、追加のレイテンシーを引き起こす可能性のあるランタイム アクティビティです。

リクエスト自体とは無関係の場合があります。タイムラインを使って遅い p95 リクエストやタイムアウトをデバッグする方法の詳細は、ブログ記事 プロファイリングでリクエスト レイテンシを理解する を参照してください。

Python でこの機能を有効化する方法は、前提条件 を参照してください。

各レーンは スレッド を表します。共通のプールからのスレッドはグループ化されます。プールを展開して各スレッドの詳細を表示できます。

各レーンは ゴルーチン を表します。選択したスパンを開始したゴルーチン、およびそれが生成したものとその子孫が含まれます。同じ go 文で作成されたゴルーチンはまとめてグループ化されます。グループを展開して、各ゴルーチンの詳細を表示できます。

上部のレーンは、追加のレイテンシーを引き起こす可能性のあるランタイム アクティビティです。リクエスト自体とは無関係の場合があります。

タイムラインを使って遅い p95 リクエストやタイムアウトをデバッグする方法の詳細は、ブログ記事 Datadog の Profiling Timeline で Go リクエスト レイテンシをデバッグする を参照してください。

この機能を Ruby で有効化する方法は、前提条件 を参照してください。

各レーンは スレッド を表します。共通のプールからのスレッドはグループ化されます。プールを展開して各スレッドの詳細を表示できます。

各レーンは スレッド を表します。同じ名前のスレッドはグループ化されます。グループを展開して各スレッドの詳細を表示できます。コードで明示的に作成されたスレッドは Managed Threads の下にグループ化されます。

上部のレーンは、追加のレイテンシーを引き起こす可能性のあるランタイム アクティビティです。リクエスト自体とは無関係の場合があります。

この機能を Node.js で有効化する方法は、前提条件 を参照してください。

JavaScript スレッド は 1 つのレーンです。

上部のレーンは、リクエストに追加のレイテンシーをもたらす可能性のあるガーベジ コレクタの ランタイム アクティビティ です。

この機能を PHP で有効化する方法は、前提条件 を参照してください。

各 PHP スレッド に対して 1 つのレーンがあります (PHP NTS では 1 つのみ)。この スレッド 内で実行される Fiber は同じレーンに表示されます。

上部のレーンは、ファイル コンパイルやガーベジ コレクションに起因して、リクエストに追加のレイテンシーをもたらす可能性のあるランタイム アクティビティです。

トレースからプロファイルを表示する

フレーム グラフでプロファイルのビューを開く

タイムラインから Open in Profiling をクリックすると、同じデータを新しいページで表示できます。そこから、可視化をフレーム グラフに変更できます。 データのスコープを定義するには、Focus On セレクタをクリックします:

  • Span & Children: 選択したスパンと同じサービス内のすべての子孫スパンに、プロファイリング データの範囲を限定します。
  • Span only: 直前に選択したスパンのみに、プロファイリング データの範囲を限定します。
  • Span time period: スパンがアクティブだった時間帯のすべてのスレッドに、プロファイリング データの範囲を限定します。
  • Full profile: 直前に選択したスパンを実行したサービス プロセス全体の 60 秒間に、データの範囲を限定します。

API エンドポイントごとにコードのパフォーマンスを分解する

前提条件

Java サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

Datadog プロファイラの使用 が必要です。JFR はサポートされません。

Python サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

dd-trace-py バージョン 0.54.0+ が必要です。

Go サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

dd-trace-go バージョン 1.37.0+ が必要で、Go バージョン 1.18 以上で最適に動作します。

Ruby サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

Linux と macOS 上で Node.js サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。この機能は Windows では利用できません。

dd-trace-js バージョン 5.0.0+、4.24.0+、または 3.45.0+ が必要です。

.NET サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

dd-trace-dotnet バージョン 2.15.0+ が必要です。

PHP サービスのプロファイリングを有効化 すると、エンドポイント プロファイリングはデフォルトで有効になります。

dd-trace-php バージョン 0.79.0+ が必要です。

エンドポイント プロファイリング

エンドポイント プロファイリングは、Web サービスの任意のエンドポイントでフレーム グラフのスコープを絞り込み、遅い・レイテンシが大きい・エンドユーザー体験を損なっているエンドポイントを見つけるのに役立ちます。これらのエンドポイントはデバッグが難しく、なぜ遅いのか理解しづらいことがあります。遅さは、CPU サイクルを大量に消費するなど、意図しない大きなリソース消費によって引き起こされる場合があります。

エンドポイント プロファイリングによって、次のことが可能になります:

  • エンドポイント全体の応答時間を遅くしているボトルネック メソッドを特定する。
  • CPU、メモリ、例外などの貴重なリソースを消費している上位エンドポイントを分離する。これは、サービスをパフォーマンス向上のために最適化している場合に特に有用です。
  • サード パーティ コードやランタイム ライブラリが、エンドポイントの遅延や過剰なリソース消費の原因かどうかを把握する。
エンドポイントの集約を使って遅いエンドポイントをトラブルシュートする

本番のレイテンシに影響したコードを可視化する

APM Service ページで Profiling タブの情報を使い、レイテンシやスループットの変化をコード パフォーマンスの変化と相関付けます。

この例では、/GET train におけるロック競合の増加が次のコード行によって引き起こされ、それがレイテンシに結び付いていることがわかります:

Thread.sleep(DELAY_BY.minus(elapsed).toMillis());

最もリソースを消費しているエンドポイントを追跡する

CPU やウォール タイムなどの重要なリソースを消費している上位エンドポイントを追跡することは有用です。リストは、エンドポイントがリグレッションしていないか、あるいは新しく導入したエンドポイントが著しく多くのリソースを消費してサービス全体を遅くしていないかを把握するのに役立ちます。

次の画像は、GET /store_history が定期的にこのサービスへ影響し、CPU の 20% と割り当てメモリの 50% を消費していることを示しています:

リソース消費の観点で上位エンドポイントをグラフ化する

リクエストあたりの平均リソース消費を追跡する

トラフィックが時間とともに変動しても動作の変化を確認するには、Per endpoint call を選択します。これは、段階的ロールアウトの健全性チェックや日々のトラフィック パターン分析に役立ちます。

次の例は、/GET train のリクエストあたりの CPU が増加したことを示しています:

参考資料