リバースプロキシ(Nginx)導入によるオリジン負荷の軽減

  • nginx
    nginx
  • cloudflare
    cloudflare
2023/11/21に公開

まとめ

観点 内容
課題 動的APIがアプリサーバーに集中し、CPU使用率の高止まりとレスポンスばらつきが発生していた。CDN→アプリの直結構成により、リクエスト負荷を吸収できない状態。
対応 CDN とアプリの間に Nginx 中継レイヤを配置し、短期TTLキャッシュと Keep-Alive接続再利用 を導入。
運用 段階的導入と即ロールバック可能な設計を採用。HIT / MISS を可視化し、TTL と除外対象パスを継続的にチューニング。
結果・成果 オリジン到達リクエストを大幅削減し、アプリのCPU負荷とレスポンスのばらつきが安定。ピーク時の耐性が向上。

背景・課題

サービス全体のトラフィックはCDN経由で配信していたものの、動的APIリクエストの集中によりバックエンド(アプリケーションサーバー)のCPU使用率が高止まりしていた。
特にログインユーザー向けダッシュボードやサジェストAPIなど、キャッシュが効きづらい動的エンドポイントで負荷が偏在。
ピーク時にはアプリサーバーのCPU使用率が高止まりし、レスポンスタイムの悪化が見られた。

当時の構成ではCDNが直接アプリケーションサーバーに到達しており、

  • 各リクエストごとにTCPコネクションが確立・破棄される
  • アプリケーション層がKeep-Aliveの維持と再利用を担う
  • 動的リクエストに対してもキャッシュ制御が全てアプリ側に依存

といった非効率な状態にあった。
結果として、コネクション確立のオーバーヘッドとアプリ層での無駄な再生成処理がCPU負荷を押し上げ、高負荷時にはスロークエリやタイムアウトが散発する状況となっていた。

対応方針

動的リクエストの特性を踏まえ、CDNとバックエンドの間にNginxを中継レイヤーとして挟み込む構成を採用。
目的は、アプリケーションサーバーへの直結を避け、以下の3点を同時に満たすことだった。

  1. 短期キャッシュによる再リクエスト抑制

    • 数秒〜数十秒単位で変化しないAPIレスポンスをNginxで一時的に保持。
    • 例:/api/dashboard/stats/api/search/suggest の結果をキャッシュ。
  2. Keep-Aliveとコネクション再利用によるオーバーヘッド削減

    • CDN→Nginx、Nginx→アプリ間で接続をプールし、再利用率を向上。
    • アプリサーバー側の接続確立回数を大幅に削減し、CPU負荷を安定化。
  3. バッファリングによるスパイク吸収

    • Nginx側でレスポンスをバッファリングし、瞬間的な同時アクセスを吸収。

これにより、キャッシュ可能領域の拡大とオリジン到達リクエストの抑制を同時に実現する方針を立てた。

比較検討フェーズ

Nginx導入以前にも、オリジン負荷を下げるための複数の選択肢を検討した。
それぞれの効果・コスト・リスクを整理した結果、キャッシュ制御の自由度と導入リードタイムの短さからNginxを採用した。

総合評価 オリジン負荷軽減 実装コスト 影響範囲 運用負荷 リスク
NginxをCDNとアプリ間に導入(短期キャッシュ+Keep-Alive)
アプリケーション側でキャッシュ制御実装(Redis等) ○(整合性・バグリスク)
Auto Scaling強化(CPU利用率閾値で水平スケール) △(スケール反応遅延)

Nginxは導入・調整コストが低く、短期キャッシュと接続再利用を併用できる選択肢だった。特に既存アプリケーションのコード改修が不要な点と、運用監視への統合が容易だった点が決め手となった。

  • アプリケーション側でのキャッシュ実装は柔軟だが、整合性管理や障害時の複雑化を避けるため見送った。

検証フェーズ

Nginx導入によるオリジン負荷軽減効果と副作用を正確に把握するため、段階的な負荷テストを実施した。
各ステージでキャッシュ設定・接続再利用・透過プロキシ動作の影響を定量的に評価した。

① コンポーネント単体

目的:Nginxレイヤーの基本性能と設定の健全性を確認(まずは透過プロキシとして動作させる)

アクセス先:

  • ALB(private)直 — アプリ単体の基準値を取得
  • ECS(Fargate)のNginx → ALB(private)— Nginx経由時のオーバーヘッドを測定

実施内容:

  • キャッシュOFFでベースラインを計測

移行判断基準:

  • Nginx透過時のレイテンシ増加が許容範囲内
  • 5xx発生率に変化がないこと

② ステージング環境 E2E

目的:実際のCDN経路(Cloudflare → ALB(public) → Nginx → ALB(private) → アプリ)での挙動を確認。

叩く先:

  • stgサブドメイン(例:stg.example.com)をCloudflare経由でリクエスト

実施内容:

  • コールド/ウォーム(キャッシュ済み)の2パターンを実験
  • ログでは キャッシュ状態、バックエンド応答時間、全体の処理時間を指標として、キャッシュヒット率と応答速度の改善を分析した。

成功基準(例):

  • ウォーム時のレスポンスが現行ステージング比で改善が見られること
  • MISS急増がデプロイ直後のコールド期間に限定されること

移行計画と再発防止

移行方針

  • 段階的デプロイ:まず低トラフィック帯テナントを対象に導入し、モニタリングで異常有無を確認。問題なければ全体へ段階拡大。
  • ロールアウト条件:Nginx レイヤでの 5xx 増加・キャッシュヒット率低下・CPU高止まりがないことを確認してから次段階へ進む。
  • ロールバック手順:異常検知時には即座に ALB 直通ルートへ切り戻し。Nginx 設定は immutable なテンプレート化により再展開可能。

リスク管理

  • 観測指標の自動収集:Nginx → アプリ間のリクエスト数、キャッシュヒット率、レイテンシ、5xx率を CloudWatch logs とCloudWatch Metricsで可視化。
  • 構成の一貫性維持:Terraformにより Nginx レイヤー構成をバージョン管理し、環境差異を排除。

継続的改善

  • 定期的にアクセスログを解析し、キャッシュTTLと除外パスの最適化を実施。
  • 新規APIの追加時にはキャッシュ方針をドキュメント化し、設計レビュー時に検討を必須化。
  • 定期的に「Nginx経由の負荷・直通時の負荷」を比較し、キャッシュ効果と再利用性を検証。

効果

Nginx を CDN とバックエンドのあいだに挟むことで、キャッシュ・接続の再利用・暗号処理・圧縮といった処理を中継層で肩代わりできるようになった。
その結果、アプリケーションサーバーの負荷が安定し、ピーク時でも処理が詰まりにくくなった。

キャッシュ(短いTTLでの一時保存)

  • アクセスの多い API の結果を短時間だけ Nginx に保存。
  • 同じ内容のリクエストはオリジンまで届かず、Nginx から即時に返せる。
  • オリジンの CPU・DB 負荷が下がり、応答が安定した。

コネクションの再利用(Keep-Alive)

  • Nginx とオリジン間の通信をつなぎ直さずに再利用。
  • 接続の確立・切断を繰り返す負担がなくなり、メモリやスレッドの消費を抑えられた。
  • 高トラフィック時でも接続数が急増せず、リソースの使い方が滑らかになった。

TLS終端(暗号処理の肩代わり)

  • 通信の暗号化・復号化を Nginx 側で実施。
  • オリジンは平文通信で済むため、CPU 負荷が軽くなる。
  • 証明書の管理も Nginx に集約され、更新や設定変更が容易になった。

圧縮(データ転送の効率化)

  • Nginx で gzip や brotli による圧縮を行い、オリジン側の処理を軽減。
  • 圧縮済みのデータをキャッシュできるため、同じリクエストでは再圧縮が不要。
  • データ量が減ることで、通信速度や体感レスポンスも改善した。

全体として、Nginx が「中継しながら処理を肩代わりする層」として機能し、サーバー負荷の平準化とレスポンス安定化を実現できた。

工夫した点・苦労した点

  • 二重キャッシュの不具合排除

    • CDNとNginxの両方にキャッシュ層があるため、TTLやCache-Controlの設定重複を精査。
    • オリジン変更時のキャッシュ事故(古いレスポンスの残留)を防ぐため、特定パスのみを短期TTLに分離。
  • ログ拡張(キャッシュステータスの可視化)

    • キャッシュステータス をログに出力し、HIT/MISS/EXPIRED/STALEを収集。
    • 可視化により、キャッシュ効率やTTLの最適化余地を定量的に分析できるようになった。

導入後の検討中施策

  • キャッシュ効率の高いリクエストの選択的キャッシュ

    • APIごとにキャッシュ効果をスコアリングし、コスト対効果の高い経路のみキャッシュ対象化。
  • ブラウザキャッシュの活用

    • CDNではキャッシュできない個別データを、ユーザー本人のブラウザ内だけで短時間キープして再取得を減らす。
    • セッション単位などの短期キャッシュで安全性を保ちながら、体感速度を改善する。