はじめまして、開発部の熊谷です。
今回は弊社のサービスである求人飲食店ドットコムの性能改善をするため、Datadog の Application Performance Monitoring(以下APM)を導入した際の話をしたいと思います。
なぜAPMを導入したか
ここ数年、当チームでは開発・保守を担当している「求人飲食店ドットコム」の性能改善に対する関心が高まっていました。
主な動機は、Core Web Vitals の各指標を向上させることで検索順位やユーザー体験を改善したいという点にあります。
しかし、フロントエンドには PageSpeed Insights のような手軽な計測ツールがある一方、サーバーサイドのレスポンスタイムについては具体的なボトルネックを特定するためのモニタリング環境が整っていない状態でした。
そこで1年ほど前、開発プロセスの中で性能劣化を防ぐためローカル環境(各エンジニアの開発機)に rack-mini-profiler という Rails 用のプロファイラを導入しました。
github.com
このツールは Controller や View ごとに発行されたSQLのクエリ数や実行時間を可視化できるため、これを使い新規開発や機能改修を行った際のレビュー前に「意図せぬクエリ増加(N+1問題など)が起きていないか」や「意図して追加した処理の実行時間が許容範囲内か」を開発者自身がチェックするフローを確立しました。
この取り組みによって明らかなパフォーマンス劣化をリリース前に検知できるようにはなりましたが、運用を続ける中で新たな課題も見えてきました。
最大の課題は、ローカル環境での最適化が必ずしも本番環境のパフォーマンス改善に直結しないという点です。
ローカル環境はWebサーバー、アプリケーションサーバー、DBや全文検索エンジンなどの各種サービスが単一のマシン内で完結するオールインワン構成ですが、本番環境では各サービスがネットワークを通じて連携しており通信レイテンシが発生します。また、サーバーのスペック差に加えて Rails の設定(config.eager_load など)も異なるため、同一のコードであっても処理時間の内訳やボトルネックとなる箇所が本番とは異なる可能性が高いという状態にあります。
また、運用の手間という観点でも課題がありました。rack-mini-profiler は詳細なプロファイリングには適していますが、あくまで単発のリクエストを分析するためのツールです。サービス全体を俯瞰出来るようなサマライズ機能もなく、蓄積されたデータを使った時系列での傾向把握なども出来ないため継続的なパフォーマンス監視として使うには不向きで、そこを人手でカバーするのは工数的に現実的ではないというのが問題でした。
APM導入
上述の背景から、本番環境の実態を正確に把握し継続的な改善をしていくための仕組みとして Datadog APM の導入を決定しました。
弊社ではすでにSREチームが各種インフラリソースの監視目的で運用している実績があり、アカウントの作成や Datadog エージェントの導入は済んでいる状態だったため、求人飲食店ドットコムへの導入はスムーズに進みました。
導入に関して Web アプリケーション側で必要だったのは Datadog エージェントへトレース情報を送信するための gem のインストールと、それに伴う十数行程度の設定のみでした。
ただしトレース情報を採取する頻度(サンプリングレート)の設定には注意を払いました。APM のトレース情報はスパンと呼ばれる単位で採取されますが、採取したスパンはその数と容量が一定数を超えると基本料金+超過分の従量課金となる料金体系であるため、サイトに対するリクエストすべてのスパンを採取していると高額になる恐れがあります。
そのためサイトへの平均リクエスト数などを元に基本料金内に収まるスパン数を事前に試算し、まずはリクエスト全体のうち10%のみのスパンを保存するように設定しました。念の為保存しているスパンの量をモニタリングしながら運用していますが、今のところ超過の傾向はないうえ分析に十分なサンプル数は確保できているのでこのレートで運用を続ける予定です。
APMの活用
まず求人飲食店ドットコムの中で特に重要ないくつかのページを対象として、それらに対するリクエストのレイテンシを時系列の折れ線グラフで表示するダッシュボードを作成し、毎週末に実施している振り返りのミーティングで前週のグラフと比較して明らかな劣化がないかを確認するという時間を試験的に設けてみました。
それからしばらくしたある週のミーティングで、サイト上で掲載している求人の詳細情報を表示するページのレイテンシがある日の本番リリースの後から定常的に悪化していることに気づきました。
緑の線のタイミング(本番リリース)を境に、前週のレイテンシ(赤の点線)と比較して当該週のレイテンシ(青の実線)のベースラインが明確に増加していることが一目で分かるかと思います。

ここまでなら Datadog APM ほど高機能なツールを使わずとも「パフォーマンス監視を定期的に行う」というルールを決めるだけでも実現できたかもしれませんが、ここからさらに Datadog APM の別の機能を使うことで原因となった開発要件の特定まで迅速に行うことが出来ました。
Datadog APM にはサーバー側の処理の総実行時間を処理の種類ごとに可視化する機能があります。それを使用して下記のように実行時間の合計を積み上げ面グラフとして表示することで、本番リリースのタイミングから全文検索エンジンである OpenSearch の処理(一番下の水色の層)が新たに増えていることが一目で分かり、それが手がかりとなって原因となった開発要件を短時間で特定することが出来ました。

運用の工夫
しかしこの運用では目視によるチェックが必要かつ定量的で明確な基準がないので、運用コストと属人性の観点でもう少し改良が必要だと感じました。そこでAPMモニターという機能を使い、異常検知アラートを設定することを試みました。
異常検知アラートとは、蓄積された過去のメトリクスデータをもとに機械学習アルゴリズムが「予測される変動幅」を動的に算出し、その範囲を逸脱した場合にアラートを上げる機能です。
固定の閾値を設定する方式とは異なり時間帯や曜日ごとの傾向も考慮されるため、例えば「夜間はアクセスが減るが、日中は増える」といったサイト毎の特性も加味した柔軟な検知が出来る点が強力です。
下記の画像は動作確認時に発生させたときの通知内容ですが、現在ではこのように自動でSlackに通知が来るように設定をしているため即時に異常に気付けるような状態になっています。

今後について
本記事では、APM の導入からダッシュボードによる可視化、そして APM モニターによる異常の自動通知までを紹介しました。これにより、チームメンバー全員がフロントエンド・バックエンド問わずシステムの性能を定量的に把握出来る状態になったので、実際に性能改善活動を進めるための準備が整ったと言えます。
次のステップとして、Datadog Continuous Profiler の活用を進めています。
APM がリクエストの流れを追うのに対し、Continuous Profiler はプログラム実行中の CPU やメモリの使用状況をメソッドや行単位で記録する機能です。これらを可視化したフレームグラフを読み解くことで、処理遅延の原因であるコード箇所をピンポイントで特定できるようになります。
現在は、実際にフレームグラフの分析手法を学習しながら、特定のエンドポイントのボトルネック改善にトライしている最中です。具体的な改善事例や成果を出すことが出来たら、また別の記事として共有したいと思います。