Datadog APM(DD Trace PHP)でパフォーマンス計測

Wataru SendoPosted by

この記事はGRIPHONE Advent Calendar 2020 15日目の記事です。

こんにちは、サーバーサイドエンジニアのsengokです。

アプリの開発/運用をしていると特定のAPIや処理が重い気がする…!計測して改善せねば…といった場面に直面することが少なくないですよね。

計測といえば、先日、Datadog APM(web-Application Performance Monitoring)ドキュメントにてPHP版のトレースライブラリであるDD Trace PHP(GitHub : DataDog / dd-trace-php)にオフィシャルマークが付きました。

今回は、こちらのDD Trace PHPを使って重い処理がいったいどこなのか計測する方法を書いていきたいと思います。

事前準備

※ 導入要件がプロジェクトによって大きく異なり、本旨に入るまでが非常に長くなってしまうため、この記事では導入について書かれた公式ドキュメントへのリンクを貼るだけに留めておきます。

Datadog APMはDatadog Agentに依存して計測したデータをDatadog Appへ送るため、事前にDatadog Agentを計測環境にインストールする必要があります。

https://docs.datadoghq.com/agent/

続いて、Datadog APMを利用できるようにします。

https://docs.datadoghq.com/ja/tracing/setup_overview/setup/php?tab=

ドキュメントに書かれてある通り、詳細はDatadog Appの「APM → セットアップと構成 → サービスのセットアップ」を参照してください。

また、autoloadなどを使用してアプリ開発者からの利用を簡単にするにはComposerを使用した導入もご検討ください。

https://packagist.org/packages/datadog/dd-trace

とりあえず計測してみる

さて、導入が終わったらひとまず対象サービスにアクセスしてみて、どのように計測されるか見てみましょう。

対象サービスにアクセスした後、Datadog Appの「APM → Services」を参照すると下記画像のように計測が行われたことが分かります。

Datadog APMを導入すると自動でWebリクエストやDBへアクセスしたSQLクエリなどのトレースが送信されます。

これだけだとよく分からないので、あるAPIの1リクエストを例として詳細を見てみます。
Datadog Appの「APM → Services → Taraces → 適当なWeb.Request」を参照すると下記画像のように実行時間の内訳を見ることができます。

どうやら、例として取り上げたAPIでは、DBのアクセスなどよりも他の部分に時間がかかっているようです。

しかし、この内訳からはこれ以上の情報は得られそうにありませんね…。

特定のメソッドを対象に計測してみる

特定のAPIが重い場合、なんとなーくこの辺の処理が重そうな気がする…といったアテがあるケースもあるかと思います。

Datadog APMでは、下記のようなコードを書くことで特定のクラス、メソッドを指定してトレースを行うことができます。

\DDTrace\trace_method(
    $class,
    $method,
    function (\DDTrace\SpanData $span, array $args, $retval, $exception) {
        $span->service = 'php';

        // 対象メソッドが呼ばれた後に自動で呼ばれます
        // 例えば何かログを吐きたい、メタデータを付けてDatadogに送信したいといった際はここに書くことが出きます
    }
);

Datadog App上では下記画像のように表示されます。

この例ではトレース対象としたメソッド(画像では紫色で表示)の割合が多く何度も呼び出されていることが分かるので、改善候補の一つとして考え始めることができそうですね。

特定のクラスを対象に計測してみる

なんとなくこのクラスが重い気がする…けどどこが重いのか一言で言えないといった場合は先ほどの例を応用して次のような実装をしてみるのも一つの手段かもしれません。

$methods = get_class_methods(HogeFuga::class);
foreach ($methods as $method) {
    \DDTrace\trace_method(
        $class,
        $method,
        function (\DDTrace\SpanData $span, array $args, $retval, $exception) {
            $span->service = 'php';
        }
    );
}

Datadog App上では下記画像のようにさらに細かく表示されます。

計測対象を少し工夫してみる

先ほどの例だとかなり大味なので、例えばサービス運用において重要度の高いAPIで使っているメソッドだけは一定の質を保てるようにいつでも計測可能にしておく!といった目的で次のような実装にしてみるのもいいかもしれません。

$traceTargets = [
    HogeFuga::class => [
        'methodA',
        'methodB',
    ],
    Piyo::class => [
        'methodC',
    ]
];

foreach ($traceTargets as $class) {
    foreach ($class as $method) {
        \DDTrace\trace_method(
            $class,
            $method,
            function (\DDTrace\SpanData $span, array $args, $retval, $exception) {
                $span->service = 'php';
            }
        );
    }
}

特に$traceTargetsの部分は次のような工夫をすることでより使い勝手が上がるかもしれません。

  • Configから引っ張ってみる
  • 環境(ローカル/ステージング/本番/負荷試験環境など)ごとに計測する/しないを制限してみる
  • 環境ごとにトレース対象を拡げる/絞ってみる
  • クラスやメソッドを指定するだけでなく、対象に応じて可変なメタデータも含めてみる
  • etc…

おわりに

この記事では、Datadog APMを利用した簡単な計測の例について書きました。

正直、導入や計測対象をどういったルールで決めるかといった周辺作業の方が大変ではありますが、計測自体はほんの少し既存のコードに足してあげるだけでできるよということを示せたかと思います。

それでは、明日の記事もお楽しみに!