TTFB (Time to First Byte) とは、クライアントのHTTPリクエストからサーバーが最初のバイトを返すまでの時間を測定するための指標です。
TTFBが低いほど、サーバーの応答が速く、ページの読み込み時間が短縮されていることを表します。近年のWeb開発業界では、Webサイトをサーバー側でレンダリングする潮流が強まっています。
この方法はSEOに有利で、性能の低いデバイスでも快適にWebページを表示させるためユーザ体験を損なうことがありません。
しかし、このアプローチでは TTFB を犠牲にすることになります。
ページをビルド時に静的にプリレンダリングするのではなく、リクエスト時にサーバーで動的にレンダリングするため、ブラウザはサーバーからの応答を待つ時間が長くなります。その結果、TTFBが高くなり、TTFBが高いと他のWebバイタル指標も悪化します。
この記事では、TTFBが高くなる原因を特定し、それを改善する方法について探っていきます。
TTFBの測定方法
ここでは、サーバーサイドでレンダリングされたNext.jsアプリケーションを使用していると仮定します。
一部のページの読み込みが他のページよりも明らかに遅いことが分かったら、Chrome DevToolsを使用してどこで遅延が発生しているのか確認します。
残念ながら、ブラウザがサーバーからの応答を待つのに2秒以上かかったことはわかるものの、DevToolsではページ読み込みのタイムライン内で何がそれほど時間を要したのかを正確に測れません。
そのため、WebPageTestでテストを実行することを検討し始めるかもしれません。
問題があることは間違いない、ということはわかりますが、その原因は依然として不明なままです。
これらのツールは、ブラウザが見て感じることしか提示してくれません。
サーバーでの遅延が高いTTFBを引き起こしているため、ページを読み込む際にサーバーで何が起こっているのかを確認するには、別の種類のツールが必要です。それがトレース(Tracing) です。
トレース(Tracing)とは何か?
トレースは、パフォーマンスの問題をデバッグする際によく使用されるツールで、競合状態(race condition)などの複雑で奇妙なバグを見つけるのにも役立ちます。トレースは「スパン(span)」と呼ばれる最小の作業単位を作成します。
これらのスパンは互いにリンクされており、開始時間と終了時間を持ち、すべてが同じ「トレース」に属します。
測定したい関数やコードブロックを囲む形でこれらのスパンを作成します。また、使用するライブラリによっては、スパンが自動的に作成される場合もあります。この記事では、Sentry を使用します。
SentryはNext.jsと直接統合し、高いTTFBをデバッグするために必要なスパンのほとんどを自動的に作成してくれます。
トレースは「分散型」にすることも可能です。つまり、クライアント側でトレースを開始し、そのままシームレスにサーバー側のトレースを続行できます。これにより、クライアントとサーバーの両方で何が起こっているのかを1つのタイムラインで把握することが可能になります。
Sentryでは、このトレースとすべてのスパンを「フレームグラフ(Flame Graph)」と呼ばれる形式で視覚化します。
トレースに関する詳しい内容については「分散トレース:アプリケーションのデバッグとモニタリングのための強力な仕組み」で解説していますので、こちらをご覧ください!
Next.jsでSentryを使用してトレースを設定する
Next.jsでSentryのトレースを設定するには、Sentryをインストールして構成するだけです。指示に従って設定を完了し、アプリケーションを実行すると、ページ読み込みのパフォーマンスデータがSentryに送信されるようになります。
このスクリーンショットから、ブラウザとサーバーの両方で何が起こったかを明確なタイムラインで確認できます。
getServerSideProps 関数が約500msかかっていることがわかります。この遅延の原因は、Cloudinaryへのリクエストであり、リソースが存在することを確認してからページをレンダリングするためのものです。
これを最適化できるでしょうか?
もちろん可能です。例えば、キャッシュを使用するか、リソースの存在を確認する別の(しかもさらに高速な!)方法を見つけることができます。
もし getServerSideProps 関数だけが原因であれば、最適化はこれで完了です!
しかし、今回はそれだけではありません。
getServerSideProps 関数が実行される前に、遅延の大部分が発生していることにお気づきでしょうか。
getServerSideProps 関数の前に、いったい何が実行されているのでしょうか?
正解は『ミドルウェア』です!
ミドルウェアは自動で計測されないため、以下に示すコードを書いて計測を行う必要があります。
カスタム計測
こちらがミドルウェアの計測を行うための関数です。
まず認証を確認し、その後リクエストがフォトページ用かどうかを確認します。もしそうであれば、画像が存在するかどうかをチェックする関数を呼び出します(聞き覚えがありませんか?)。
次に、ロケールが正しく設定されているかを確認し、リクエストに追加のデータとタグを補完し、next() メソッドを呼び出します。
カスタム計測を追加するためには、Sentry の startSpan メソッドでラップするだけで実装は完了します。
これはブラウザがトレースを開始する前に行われるため、別のトレースとして扱われます。そのため、先ほど見たページ読み込みのメイントレースの外を確認する必要があります。
もしこれを実行すると、1つのスパンしか得られませんが、これではどの関数が最も時間を要しているのかを特定するのに役立ちません。より詳細な結果を得るためには、それぞれの関数に入り、startSpanメソッドでラップする必要があります。
この状態でアプリを再実行して新しい「middleware」のトレースを開くと、次のようになります。
checkAuth 関数は171ms、checkImageExists は1.71ms、checkLocale は132ms、updateRequest は531msかかっていることがわかります。
これにより、ミドルウェア関数全体の詳細な内訳が表示され、各関数がどれだけの時間を要したかを正確に確認できます。
これをどのように解決するかというと、いくつかの方法が考えられます。
例えば、すでにページ内の getServerSideProps 関数で checkImageExists のチェックを行っているため、この関数を削除することができます。これにより、ミドルウェアの処理が大幅に高速化されます。他の関数については、それぞれに特定の実装があるため、個別に最適化方法を検討する必要がありますが、今回はその話題には触れません。
重要なのは、ページをサーバーサイドでレンダリングしている間に、ミドルウェア、サーバー上のページハンドラー、そしてブラウザで一体何が起こっているのかが正確かつ明確に把握できたことです!
SentryでTTFBを削減しましょう
TTFB(Time to First Byte)の測定は簡単ですが、それを実際に削減すること難しいです。現在、多くのWebサイトがサーバーサイドでレンダリングされているため、遅いTTFBをデバッグする能力は、Webサイトを遅くしたくない場合には重要なスキルです。
TTFBが高い原因を特定するには、Chrome DevTools や WebPageTest 以外のツールを使用する必要があります。これらのツールは、ページが高いTTFBによって遅いことを確認するのには役立ちますが、その理由を特定することはできません。トレースを実装する必要があります。
今回の記事では、Sentryのトレースの実装がいかに簡単だったか、そしてトレースビューがどの部分が最大の遅延を引き起こしているかをどのように示してくれるかをご紹介してきました。
Sentryの自動インストゥルメンテーションにより、getServerSideProps 関数での最適化の機会を特定することができました。また、実際の getServerSideProps 関数の前に長い待機時間があったことにも気付くことができ、ミドルウェアが最大の遅延の原因であることが分かりました。Sentry の startSpan 関数を使ってカスタムインストゥルメンテーションを追加し、どの関数が最も長くかかったかを確認しました。
トレースは、複数のサービス、プロジェクト、または環境にまたがる複雑な問題をデバッグするための重要なツールです。リクエストのフローをアプリケーション全体(フロントエンドからバックエンドまで)で追跡し、その結果、従来のログでは見逃しがちなパフォーマンスのボトルネックや障害を特定するのに役立ちます。
ぜひご活用ください!
トレースについてもっと学びたい、またはトレースがどのように他のタイプの問題を解決するのかについて知りたい場合は、以下の記事をご覧ください。
- 【必読】Webページを読み込む前に高速化する方法
- 【Sentry】TTFB(Time to First Byte)を減らし、ユーザ体験を改善する手法について
- Reactでフェッチのウォーターフォールを識別する方法
- Trace Viewを使用してAPIコールを22.3秒短縮した方法
- 遅いバックエンドによって引き起こされる遅いページのデバッグ
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。