ページキャッシュ完全ガイド:OS(Linux)とWeb(CDN・プロキシ・WordPress)で押さえる仕組み・設計・無効化の実践

ページキャッシュとは――まずは用語の整理

「ページキャッシュ(page cache)」は文脈によって意味がやや異なります。大別すると次の2つの意味で使われます。

  • OSレベルのページキャッシュ:ファイルシステムのデータ(ファイルのページ)をメモリに保持し、ディスクI/Oを削減する仕組み(例:Linuxのpage cache)。
  • Web系のページキャッシュ:Webページ(HTMLレスポンス)をキャッシュして、バックエンド処理や生成コストを回避する仕組み(ブラウザキャッシュ、CDN、リバースプロキシ、アプリケーションの静的化など)。

以下では両者を分けて詳しく掘り下げ、実践上の注意点や運用・設計のポイントまで解説します。

OSレベルのページキャッシュ(ファイルページキャッシュ)の仕組みと挙動

OSのページキャッシュは、ディスク上のファイルデータを物理メモリ上のページ単位で保持することで、同一データへの後続アクセスを高速化します。Linuxでは「page cache」と呼ばれ、ファイル読み取り時にまずメモリを参照し、なければディスクから読み込んでメモリに置きます。

  • 利点:ディスクI/Oが減るため読み取り性能が大幅に改善され、アプリケーションのレスポンスが向上する。
  • 書き込み:変更は「dirty page」としてメモリに置かれ、後でまとめてディスクに書き出される(writeback)。これにより小さな書き込みのコストが隠蔽されるが、障害時の整合性や遅延書き込みの管理が課題になる。
  • 管理:メモリが不足するとページ回収(reclaim)でLRUに近い方式でページが追い出される。/proc/meminfo の Cached、Buffers フィールドなどで可視化できる。
  • 運用:root 権限で echo 3 > /proc/sys/vm/drop_caches を使ってページキャッシュをクリアできる(本番での安易なクリアは推奨されない)。

Web系ページキャッシュのレイヤーと代表的な手法

Webアプリケーションでは複数のキャッシュレイヤーがあり、それぞれ役割が違います。代表的なものをレイヤー別に整理します。

  • ブラウザキャッシュ:Cache-Control、ETag、Last-ModifiedなどのHTTPヘッダを受け、ユーザー側ブラウザがレスポンスを保持・再利用する。
  • CDN(Content Delivery Network):地理的に分散したエッジでコンテンツをキャッシュし、配信遅延を低減する。Cloudflare、Fastly など。
  • リバースプロキシ/HTTPキャッシュ:Varnish、Nginx(proxy_cache / fastcgi_cache)などがサーバーサイドでHTMLをキャッシュする。高速な静的配信が可能。
  • アプリケーション・レベルのページキャッシュ:WordPressのWP Super CacheやWP Rocketのように、動的ページを静的HTMLに焼いて配信する手法。
  • オブジェクトキャッシュ/データキャッシュ:MemcachedやRedisでDB結果やオブジェクトをキャッシュし、ページ生成コストを下げる(ページそのものをキャッシュするとは限らない)。

HTTPキャッシュの基本(重要なヘッダと挙動)

Webページキャッシュの設計で重要になるのがHTTPのキャッシュ制御です。代表的なヘッダを挙げます。

  • Cache-Control:max-age、public、private、no-cache、no-store、must-revalidate、s-maxage(共有キャッシュ向け)など。
  • Expires:古いが互換性のために使われることがある。
  • ETag / If-None-Match:エンティティタグにより条件付きGETを行い、変更がなければ304 Not Modifiedで済ませる。
  • Last-Modified / If-Modified-Since:更新日時を用いた再検証。
  • Vary:Accept-Encoding や Cookie など、レスポンスを分けてキャッシュする際に使う。Varyが広いとキャッシュ効率は下がる。

例:Cache-Control: public, max-age=3600 は、共有キャッシュ(CDN等)とブラウザが1時間キャッシュして良いことを示す。

キャッシュのキー設計とバリアビリティ(違いが生む難しさ)

キャッシュキー(どのリクエストを同じキャッシュエントリとして扱うか)は正しく設計しないと誤配信やキャッシュミスを招きます。典型的な要素は次の通りです。

  • リクエストURL(パス+クエリ)
  • ホストヘッダ(ドメイン)
  • Accept-Encoding(圧縮の有無)/Accept-Language(多言語対応)
  • Cookieや認証ヘッダ:ユーザー固有のレスポンスは共有キャッシュすべきでない

Varyヘッダやサロゲートキー(surrogate-key)によるタグ付けで、意図的な分割・パージを実現するのが実務でよく使われる手法です。

キャッシュの取り消し(無効化)と整合性

「キャッシュの無効化」はシステム設計で最も難しい問題の1つです。Phil Karlton の「コンピュータサイエンスで難しいものは2つしかない。名前付けとキャッシュの無効化だ(There are only two hard things in Computer Science: cache invalidation and naming things)」という格言があるほどです。

  • TTL(Time To Live):最も単純で安全な方法。短めにすると一貫性は高まるがキャッシュ効率が落ちる。
  • プログラム的パージ:特定のURLやタグに紐づくキャッシュをAPI経由で削除する(CDNやVarnishはAPIやPURGE/BAN機能を提供)。
  • キャッシュバスティング:リソースのURLにバージョンやハッシュを付けることで古いキャッシュを自然に使わせない(静的資産向けの典型手法)。
  • 再検証(conditional requests):ETag/Last-Modifiedで変更の有無だけ取得し、無駄な転送を抑える。

WordPress環境におけるページキャッシュの実務

WordPressではページ生成にPHP実行やDBアクセスが必要なため、ページキャッシュ導入効果が非常に高いです。代表的な方式と留意点:

  • 静的HTML生成(WP Super Cache、WP Fastest Cache):フルHTMLを保存して直接配信する。プラグイン側でログインユーザーやコメント直後などの除外設定が可能。
  • リバースプロキシ(Varnish / Nginx):高負荷サイトで多用。動的にキャッシュルールを書くことで柔軟な制御ができる。
  • オブジェクトキャッシュ(Redis / Memcached):DBクエリやオブジェクトをキャッシュしてページ生成自体を速くする。ログインユーザーなどの個別処理でも有効。
  • 注意点:ログイン状態やユーザー固有の情報を誤って共有キャッシュさせると個人情報漏洩のリスクがあるので、Cookieやヘッダによる条件分岐の実装が必須。

パフォーマンス測定と落とし穴

キャッシュ導入前後で必ずパフォーマンス計測を行います。代表的な指標はレスポンスタイム、TTLヒット率(cache hit ratio)、バックエンドのスループット、ディスクI/O、メモリ使用量などです。

  • キャッシュミスが多い原因:キー設計不備、Varyヘッダの意図しない設定、Cookieや認証の無条件利用。
  • Stale-while-revalidate / stale-if-error:最新の仕様を使うと、古い応答を返しつつバックグラウンドで更新するパターンが可能(CDNや近代的なプロキシが対応)。
  • ログ監視:パージ頻度やキャッシュ利用率は運用上重要。CI/CDでのデプロイ時に自動パージを組み込むことも一般的。

セキュリティ・プライバシーの注意点

共有キャッシュに個人情報が混入すると重大な問題になります。対策としては:

  • 認証済みユーザー向けレスポンスは private 指示かキャッシュしない。
  • Set-Cookie が付くレスポンスは共有キャッシュが扱わないようにする(多くのキャッシュはSet-Cookieを検出してキャッシュを避ける運用をする)。
  • Vary やキャッシュキーを正確に設計して、意図しないユーザー同士のレスポンス共有を防ぐ。

まとめと実践的なチェックリスト

ページキャッシュはシステム性能を大きく改善する強力な手段ですが、レイヤーごとに目的と制約が異なります。設計・運用で押さえるべきポイントは次の通りです。

  • どのレイヤーで何をキャッシュするのかを明確にする(ブラウザ、CDN、プロキシ、アプリ)。
  • キャッシュキーとVaryの設計を正確に。ユーザー固有コンテンツを共有キャッシュさせない。
  • TTLとパージ戦略を組み合わせ、整合性と効率のバランスを取る。
  • パフォーマンス指標(ヒット率、レスポンス時間、バックエンド負荷)を常時監視する。
  • OSレベルのpage cacheも理解しておくと、ディスクI/Oやメモリ運用の最適化につながる。

「キャッシュの無効化は難しい」という格言を念頭に、テストと運用を通じて安全で効率的なキャッシュ設計を目指してください。

参考文献