Time to First Byte が遅い理由と、その対処法
TTFB は単一のバグではありません。DNS、接続確立、CDN ルーティング、サーバー処理、キャッシュミス、そして時には遅いデータベースクエリによって表面化する遅延です。
目次
- まず TTFB が実際に測っているものを理解する
- どの程度なら TTFB が遅いと言えるのか?
- 複数の場所で測定する
- 1. ブラウザの開発者ツール
- 2. 複数地域からの合成テスト
- 3. Real user monitoring またはサーバーログ
- TTFB が遅くなる典型的な原因
- HTML がキャッシュされていない
- CDN がアセットしかキャッシュしていない
- サーバーがレスポンス前にやりすぎている
- データベースクエリが遅い、または予測しにくい
- アプリケーションにコールドスタートがある
- リダイレクトが最初のリクエストを浪費している
- 実践的なデバッグ手順
- Step 1: ページ全体ではなく、メインドキュメントをテストする
- Step 2: 地域を比較する
- Step 3: レスポンスヘッダーを確認する
- Step 4: origin のタイミングを確認する
- Step 5: 確認済みの最大遅延を修正する
- たいてい効果がある修正
- 公開 HTML をエッジでキャッシュする
- 重要でない作業をリクエストパスの外に出す
- バックエンド依存チェーンを減らす
- コンピュートをユーザーに近づける
- リダイレクトを退屈なものに保つ
- やってはいけないこと
- 落ち着いた計画
まず TTFB が実際に測っているものを理解する
Time to First Byte、通常 TTFB と略される指標は、ブラウザがリソースをリクエストしてから、レスポンスの最初の 1 バイトを受け取るまでの時間です。
これはサーバー指標のように聞こえますが、サーバーだけの指標ではありません。TTFB には複数のステップが含まれます。
- ホスト名がまだ解決されていない場合の DNS ルックアップ
- TCP 接続の確立
- HTTPS のための TLS ネゴシエーション
- サーバーまたは CDN エッジまでのリクエストの移動時間
- サーバー上でのキューイングと処理
- ブラウザへ戻るレスポンスの移動時間
つまり TTFB が高い場合、バックエンドが遅いことを意味する場合があります。一方で、ユーザーが origin から遠い、CDN の設定が不適切、キャッシュミスが絶えない、あるいはサーバーが送信内容を決めるのに時間をかけすぎている、という意味でもありえます。
これが重要なのは、TTFB が読み込みの連鎖のかなり早い段階に位置するためです。HTML ドキュメントの到着が遅れると、ブラウザが CSS、JavaScript、フォント、画像を発見するのも遅れます。フロントエンドの最適化が非常に優れていても、最初のドキュメントレスポンスに 1.5 秒かかれば、体感は遅くなります。
どの程度なら TTFB が遅いと言えるのか?
すべてのサイト、地域、アーキテクチャに当てはまる普遍的な数値はありません。それでも、実務上のしきい値は役に立ちます。
Google の web.dev のガイダンスでは、良好な TTFB は 800 ms 未満、800〜1800 ms は改善が必要、1800 ms を超えると不良と分類されています。ユーザーの近くから配信される、十分にキャッシュされたマーケティングページなら、多くの場合それよりかなり良い値を出せます。動的処理を行う複雑な認証済みダッシュボードでは許容値が高くなることもありますが、それでも説明可能であるべきです。
重要なのは、数値を分解して見る習慣です。グローバル平均 TTFB が 900 ms でも、CDN エッジに近いユーザーでは 150 ms、別地域のユーザーでは 2200 ms という状況が隠れているかもしれません。同様に、ホームページは問題なくても、検索、カテゴリ、ログイン後ページがひそかに苦痛になっていることがあります。
複数の場所で測定する
1 回の Lighthouse 実行だけで TTFB を診断しないでください。Lighthouse は有用ですが、1 つの環境からの 1 つのテストにすぎません。読み解きに慣れていない場合は、まず Lighthouse レポートを慌てずに読む方法を落ち着いて確認してください。主な教訓は、ラボのシグナルとフィールドの現実を切り分けることです。
TTFB については、少なくとも 3 つの視点が必要です。
1. ブラウザの開発者ツール
Network パネルを開き、キャッシュを無効にしてリロードし、メインのドキュメントリクエストを確認します。タイミングの内訳には、DNS、接続、TLS、待機、ダウンロードの各フェーズが表示されます。「waiting」フェーズは、多くの人がバックエンド時間と呼ぶものですが、上流のレイテンシが含まれる場合もあります。
2. 複数地域からの合成テスト
ユーザーに近い場所と遠い場所の両方からテストを実行します。ある地域では TTFB が低く、別の地域では高い場合、アプリケーションコードを書き直す前に、地理的距離、CDN ルーティング、origin の配置、キャッシュ範囲を疑ってください。
3. Real user monitoring またはサーバーログ
フィールドデータは、実際のユーザーがさまざまなデバイス、ネットワーク、セッションで何を体験しているかを示します。サーバーログは、origin がどれだけ速くレスポンスを生成したかを教えてくれます。クライアントが観測した TTFB と origin の処理時間の差に、CDN やネットワークの問題が現れることがよくあります。
TTFB が遅くなる典型的な原因
HTML がキャッシュされていない
これはコンテンツサイトや ecommerce サイトで最もよくある問題です。静的アセットは積極的にキャッシュされている一方で、ブラウザが最初に必要とする HTML ドキュメントが、リクエストのたびに生成されています。
それが必要な場合もあります。しかし、多くの場合は必要ではありません。
公開ページが 1 日に数回しか変わらないなら、匿名訪問者のすべてのリクエストで新たにデータベースからレンダリングする必要はおそらくありません。適切な場面では、フルページキャッシュ、エッジキャッシュ、静的生成、stale-while-revalidate パターンを使ってください。
レスポンスヘッダーで Cache-Control、CDN-Cache-Status、Age、Vary、Set-Cookie などのシグナルを確認します。すべての訪問者に一意の cookie を送るページは、意図せず自身をキャッシュ不能にしているかもしれません。この層について実践的に考える方法が必要なら、本番環境でリダイレクトと HTTP ヘッダーをデバッグするための小さなツールキットに関するガイドで扱っているデバッグ習慣は、TTFB の作業にもそのまま当てはまります。
CDN がアセットしかキャッシュしていない
多くのチームは CDN を追加すると、パフォーマンス対応が完了したと考えます。しかし CDN が画像、CSS、JavaScript だけを配信している場合、最初の HTML リクエストは依然として単一の origin サーバーまで到達しているかもしれません。
ローカルユーザー向けのローカルビジネスサイトなら、それで問題ないこともあります。国際的な利用者がいる場合は問題です。ユーザーが origin から遠いほど、バックエンド処理が始まる前に支払うレイテンシが増えます。
TTFB に対する良い CDN 設定とは、通常次のようなものです。
- 安全な場合は公開 HTML をキャッシュする
- 認証済みページやパーソナライズされたページに対する意図的なバイパスルールを尊重する
- キャッシュを細かく分割しすぎる不要な
Varyヘッダーを避ける - キャッシュを完全に無効化するのではなく、キャッシュパージや再検証を使う
- エッジロケーションがすべてのリクエストを転送しているのではなく、実際に hit を返していることを確認する
CDN は魔法ではありません。キャッシュとルーティングのレイヤーです。そのように扱ってください。
サーバーがレスポンス前にやりすぎている
遅いバックエンドパスは、多くの小さな遅延から生じます。データベースクエリ、API 呼び出し、テンプレートレンダリング、feature flag チェック、認証、パーソナライズ、ロギング、コールドスタートなどです。
最悪のパターンは、依存処理を直列に行うことです。たとえば次のような流れです。
- ページデータを取得する
- その後、関連商品を取得する
- その後、価格を取得する
- その後、レコメンデーションサービスを呼び出す
- その後、HTML をレンダリングする
各ステップが前のステップを待つと、TTFB は急速に増加します。独立した処理は並列化し、最初のレスポンスに不要な呼び出しは取り除き、高コストな結果はキャッシュしてください。
有用な原則があります。ユーザーがその結果をすぐに見たり使ったりできないなら、それはおそらく最初の 1 バイトをブロックすべきではありません。
データベースクエリが遅い、または予測しにくい
データベースは TTFB 問題の原因になりがちです。開発環境ではうまく動き、実際のトラフィックでは悪化するからです。インデックス不足、大きな join、N+1 クエリ、ロック競合、過大な結果セットはすべて「サーバーが遅い」として現れます。
ここで推測は禁物です。遅いリクエストのクエリ時間を取得してください。平均だけでなく p95 と p99 を見ます。通常は 120 ms で応答するページでも、たまに 4 秒ブロックするなら、依然として悪いユーザー体験を生みます。
一般的な修正には次のものがあります。
- インデックスを追加または修正する
- N+1 クエリパターンを取り除く
- 読み取りが多いデータをキャッシュする
- 大きなクエリをページネーションする
- レポートや分析クエリをリクエスト時の処理から切り離す
- 下流呼び出しに適切なタイムアウトを設定する
アプリケーションにコールドスタートがある
Serverless やコンテナ化されたプラットフォームは優れた選択肢になりえますが、トラフィックがバースト的だったり、リージョンのプロビジョニングが不足していたりすると、コールドスタートが TTFB を悪化させることがあります。
アイドル時間後の最初のリクエストが、その後のリクエストよりかなり遅い場合は、コールドスタートを調査してください。プロビジョンドコンカレンシー、小さなバンドル、起動時依存関係の削減、ウォームな関数、またはレイテンシに敏感なルート向けの別のデプロイ形態が必要かもしれません。
これは serverless への反論ではありません。ランタイムモデルが見えないものだと装うことへの反論です。
リダイレクトが最初のリクエストを浪費している
リダイレクトは、ブラウザが最終ドキュメントを受け取る前に、もう 1 回のリクエスト・レスポンスサイクルを追加します。古いリンクのために http:// から https:// への 1 回のリダイレクトは避けられないかもしれませんが、チェーンは無駄です。
よくあるチェーンには次のものがあります。
http://example.com→https://example.com→https://www.example.com- プロトコル正規化後の trailing slash 正規化
- キャッシュルックアップ前の地域または言語リダイレクト
- 複数の URL を経由する古いキャンペーンリンク
可能な限り元のリンクを修正し、リダイレクトルールをまとめ、canonical URL に直接到達できるようにします。リダイレクト時間は最終リクエストの TTFB として常に報告されるわけではありませんが、ユーザーはそれでも時間を支払っています。
実践的なデバッグ手順
TTFB が遅く見えるときは、この順序で進めてください。キャッシュとルーティングの挙動を確認する前にアプリケーションコードを最適化してしまう、よくある誤りを避けられます。
Step 1: ページ全体ではなく、メインドキュメントをテストする
HTML ドキュメントのリクエストを見つけます。総 TTFB とタイミングの内訳を記録します。ブラウザキャッシュあり・なしの両方で繰り返します。関連があれば、公開ページ、動的ページ、ログイン後ページをテストします。
Step 2: 地域を比較する
同じ URL を複数の地理的ロケーションから実行します。遅い地域が origin からの距離と相関するなら、CDN とエッジキャッシュを優先します。すべての地域で遅いなら、バックエンド処理と origin の容量を見ます。
Step 3: レスポンスヘッダーを確認する
キャッシュヘッダー、cookie、Age、CDN ステータス、Vary を確認します。Age ヘッダーがない、またはキャッシュミスが繰り返される場合は手がかりです。公開 HTML に対する広すぎる Vary: Cookie ヘッダーは、多くの場合キャッシュを破壊します。
Step 4: origin のタイミングを確認する
サーバータイミングの計測を追加します。Server-Timing ヘッダーは、データベース時間、レンダリング時間、上流 API 時間などのバックエンドフェーズを公開できます。単純なラベルでも有用です。
Server-Timing: db;dur=82, render;dur=41, api;dur=210
これにより、ブラウザのタイミングから、サーバーが実際の処理に 300 ms 使ったのか、それともリクエストがアプリケーションに到達する前に遅延が起きたのかを確認できます。
Step 5: 確認済みの最大遅延を修正する
これは当然に聞こえますが、チームは測定されたものではなく、慣れているものを直しがちです。キャッシュミスが支配的なら、キャッシュを修正します。データベースが支配的なら、クエリを修正します。グローバルユーザーに対して TLS と接続確立が支配的なら、ルーティング、CDN カバレッジ、origin の地理的位置を修正します。
フロントエンドの作業も依然として重要です。フォント、画像、JavaScript は HTML 到着後に起こることに影響します。しかし、それらは速い最初のレスポンスの代替にはなりません。レンダリング性能にも取り組んでいるなら、多くのサイトでは web fonts が今でも最も簡単なパフォーマンス改善策の 1 つです。ドキュメント到着後、テキストがどれだけ早く利用可能になるかに影響するためです。
たいてい効果がある修正
公開 HTML をエッジでキャッシュする
マーケティングページ、ドキュメント、ブログ、ランディングページ、カテゴリページでは、エッジキャッシュが TTFB を最も大きく改善することがよくあります。コンテンツが頻繁に変わるなら短い TTL を使います。キャッシュがバックグラウンドで更新される間、多少古いコンテンツを許容できるなら stale-while-revalidate を使います。
パーソナライズには注意してください。ページが通貨、言語、ログイン状態、実験グループによって変わる場合は、それらのバリアントを明示的に定義します。意図しないユーザーごとの変化は、キャッシュ効率を破壊します。
重要でない作業をリクエストパスの外に出す
メール送信、分析データの enrichment、レコメンデーション生成、webhook 呼び出し、重いロギングは、最初の 1 バイトをブロックするべき場面がほとんどありません。キューに入れるか、レスポンス開始後に実行してください。
バックエンド依存チェーンを減らす
独立した呼び出しを並列化します。遅い API のレスポンスをキャッシュします。タイムアウトを設定します。役に立つが必須ではないサービスにはフォールバックコンテンツを設計します。
遅いレコメンデーションウィジェットが、商品ページ全体を遅らせるべきではありません。
コンピュートをユーザーに近づける
ユーザーがグローバルで origin が 1 つのリージョンにある場合、レイテンシは構造的なものです。公開コンテンツでは CDN キャッシュがその多くを隠せます。動的コンテンツでは、リージョナルデプロイ、適したルートでのエッジレンダリング、またはオーディエンスに近い場所への API 移動を検討します。
リダイレクトを退屈なものに保つ
URL の正規化は 1 hop で行います。内部リンクを更新し、ユーザーとクローラーが最終 destination に直接向かうようにします。古いキャンペーン URL やプラットフォーム移行を監査します。リダイレクトは正常に動くと目に見えないため無視されがちですが、それでも時間を消費します。
やってはいけないこと
すべてのルートで完璧な TTFB 数値を追い求めないでください。実際の計算を行う認証済みレポートは、キャッシュされたブログ記事のようには振る舞いません。
平均 TTFB だけを唯一の指標にしないでください。パーセンタイルが重要です。地域が重要です。ページタイプが重要です。
CDN があるから HTML もキャッシュされている、とは仮定しないでください。確認してください。
そして、TTFB をプロダクト判断から切り離して扱わないでください。パーソナライズ、実験、リアルタイム在庫、サードパーティサービスはすべてレイテンシコストを持ちます。価値があるものもあります。ただの習慣にすぎないものもあります。
<!-- tool-cta:start -->
💡 お試しください: TTFBを診断する際、Get Headersはキャッシュの状態、サーバータイミング、リダイレクトを明らかにし、遅延がどこから生じているのかを説明してくれることがよくあります。
<!-- tool-cta:end -->
落ち着いた計画
遅い TTFB は、曖昧な「サーバー問題」として扱うのをやめれば、たいてい修正できます。ドキュメントリクエストを測定します。地域とページタイプで分解します。ヘッダーを確認します。クライアントタイミングと origin タイミングを比較します。そのうえで、確認済みの最大ボトルネックを修正します。
ほとんどのサイトに、奇抜なアーキテクチャは必要ありません。必要なのは、避けられるキャッシュミスを減らすこと、ブロックするバックエンド処理を減らすこと、リダイレクトを整理すること、そして最初の 1 バイトが送信される前に何が必ず起こるべきかを明確に理解することです。