SSRでTTFBが遅くなる原因と対策

SSRでTTFBが遅くなるのはなぜか

SSR(Server Side Rendering)を導入すると、初回表示が速くなるはずなのに「ページが開き始めるまでが遅い」と言われることがあります。LighthouseではFirst Contentful Paintは良好なのに、ユーザ体験は悪い。このとき問題になっているのがTTFB(Time To First Byte)です。

TTFBとは、ブラウザがリクエストを送ってから最初の1バイトを受信するまでの時間です。つまり、ブラウザが描画を開始できるまでの待ち時間です。

結論から言うと、SSRでTTFBが遅くなる理由は「レンダリングをしているから」ではありません。リクエストごとにアプリケーションを実行しているからです。

SPAとSSRの決定的な違い

SPAでは最初に返るのは静的ファイルです。

GET /
→ index.html を返す

これはCDNキャッシュできます。サーバはほぼ処理を行いません。そのためTTFBは短くなります。

一方SSRでは、リクエストのたびに処理が発生します。

GET /products/1
→ 認証確認
→ DBアクセス
→ API呼び出し
→ テンプレート生成
→ HTML返却

ブラウザは、この処理が終わるまで何も受信できません。この待ち時間がTTFBです。

SSR内部で実際に起きている処理

TTFBを増大させる要因は複数あります。

データ取得の直列化**

const user = await getUser();
const cart = await getCart();
const recommend = await getRecommend();

awaitを直列に書くと、その合計時間がTTFBに加算されます。APIが200msでも、3回呼ぶと600msになります。

テンプレートレンダリング**

コンポーネント数が増えると、サーバ側でも仮想DOM構築が発生します。SSRフレームワークでは、ここでCPU時間を消費します。

認証処理**

セッション検証、JWT検証、権限確認が毎回走ります。とくに外部認証サーバがあると遅延が大きくなります。

DBアクセス**

N+1クエリが存在すると、TTFBが秒単位になります。SSRでは「表示前に全部取得」が必要になるため、API設計の影響を強く受けます。

なぜユーザ体験が悪化するのか

ブラウザは最初のバイトを受け取るまで何もできません。HTMLが1文字も届かないからです。

つまりSSRでは、

速く表示される = TTFBが短い

です。レンダリング速度ではありません。

よくある誤った最適化

サーバCPUを増やしても改善しない場合があります。ボトルネックがI/O(APIやDB)にあるためです。またHTTP/2やCDNを導入しても、HTML生成前の待ち時間は短縮されません。

ボトルネックの特定方法

TTFB問題は感覚ではなく計測が必要です。ブラウザのNetworkタブを見ると、Waiting(TTFB)が長くなります。

確認すべきポイント:

  • DBクエリ時間
  • 外部API時間
  • 認証サーバ応答
  • サーバレンダリングCPU時間

APM(NewRelic等)を導入すると、どの処理で止まっているか可視化できます。

改善のための設計

SSRのTTFB改善は「高速化」ではなく待ち時間の分離です。

並列取得**

const [user, cart, recommend] = await Promise.all([
  getUser(),
  getCart(),
  getRecommend()
]);

これだけで数百ms改善することがあります。

ストリーミングレンダリング**

HTMLを完成させてから送るのではなく、部分的に送信します。ブラウザは受信しながら描画できます。

キャッシュ**

  • HTMLキャッシュ
  • フラグメントキャッシュ
  • APIレスポンスキャッシュ

特に商品詳細などは、短時間キャッシュするだけでTTFBが大きく下がります。

ISR(Incremental Static Regeneration)**

毎回SSRするのではなく、一定時間ごとに静的生成します。実務では最も効果が大きい改善になることが多いです。

注意点

キャッシュを導入すると、ユーザごとの表示差異(ログイン状態、カート情報)が問題になります。ここを考慮せずキャッシュすると、他人の情報が表示される事故が起きます。

SSR最適化はパフォーマンスチューニングではなく、キャッシュ境界の設計です。

最後に

SSRは「常に速い」わけではありません。正確には「表示開始が速くできる構造」です。ただし、その前提はTTFBが短いことです。

SPAはダウンロード後に待たされ、SSRはダウンロード前に待たされます。違いは待ち時間の位置です。

SSRを採用するなら、レンダリングを速くするのではなく、ユーザが待つ場所をどこに置くかを設計する必要があります。HTML生成を最適化するというより、「いつ結果を返すか」を決めることが、TTFB問題を解決する本質になります。