- SSRでTTFBが遅くなるのはなぜか
- SPAとSSRの決定的な違い
- SSR内部で実際に起きている処理
- なぜユーザ体験が悪化するのか
- よくある誤った最適化
- ボトルネックの特定方法
- 改善のための設計
- 注意点
- 最後に
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問題を解決する本質になります。