7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

BEAR.SundayAdvent Calendar 2022

Day 20

キャッシュ設計(2) - 分散

Last updated at Posted at 2022-12-19

REST制約に従った分散キャッシュシステムは、計算資源だけでなくネットワーク資源も節約しします。

image.png
https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
(REST論文の図。キャッシュはサーバーサイドではなくクライアントサイドに保存されています)

この記事ではキャッシュをストレージの場所で考察します。

キャッシュが行われる場所

キャッシュは次の3つのいずれかに存在します。

  1. サーバーサイド
  2. CDN (共有キャッシュ)
  3. クライアント

image.png

理想的なキャッシュシステムを目指し、HTML、APIに関わらずこの分散型のキャッシュシステムを設計します。

キャッシュのTTLを知るのは誰か?

コンテンツがイベントドリブンではなく、正確なコンテンツの生存期間(TTL = Time to live)で制御する場合、サーバーサイドがTTLを決定します。例えば製品の発売日まで有効なキャンペーンサイトや、月曜の相場開始までの時間が正確に計算できる株価のデータなどです。

HTTPキャッシュはレスポンスヘッダーにCache-Controlヘッダーを付与することで、CDNやクライアントに対してキャッシュのTTLを伝えます。

キャッシュの無効化

キャッシュが無効化される理由は2つあります。TTLの指定で時間が切れたかよるものか、イベントによるものかです。

TTLによるCDNキャッシュの無効化

TTLによる無効化は容易で、CDNやクライアント双方に使う事ができます。コンテンツの有効期間を秒数で指定します。

イベントによるCDNキャッシュの無効化

一方、イベントによる無効化は注意が必要です。サーバーサイドのWebアプリケーションのイベントでサーバーサイドのキャッシュを無効化することは容易ですが、CDNに対して無効化するときは、インスタントパージに対応したCDNを利用する必要があります。FastlyやAkamaiなどです。そのときはイベントドリブンコンテンツはTTLでキャッシュが消去されないようにするために、キャッシュ時間を最大(1年間)にします。

インスタントパージが利用できないCDNでは、イベントドリブンコンテンツをCDNでキャッシュすることができません。キャッシュ時間をゼロにして、must-revalidateで都度確認するようにします。

ETag管理が最適されていると、最小限のネットワークおよびCPU資源の消費ですみますが、インスタントパージ可能なCDNのキャッシュの効率性には及びません。

クライアントキャッシュ

Cache-Control: max-age=3600

レスポンスディレクティブのmax-age=3600 は、レスポンスが生成されてから3600 秒後まで、レスポンスが新鮮なままであることを示します。このヘッダーはCDNでもキャッシュを作成しますが、クライアントでもキャッシュを作成します。最も強力なキャッシュで、ネットワークコストを節約します。

TTLが正確に予測できる場合にのみ使用します。この期間、イベントでコンテンツを変更する事はできません。

イベントドリブンコンテンツの場合は、クラアイントはコンテンツに変更があったかを条件付きリクエストで確認します。変更がなければHTTPステータスコード304が返されるのでクライアントはクライアントサイドで保存したキャッシュを再利用します。

また、パーソナライズされたページなど、クライアント間でキャッシュが共有できないときはprivateを使います。

Cache-Control: private, max-age=3600

CDNキャッシュ

クライアントにキャッシュを保存しないときは以下のどちらかのヘッダーで指定します。

Cache-Control: s-maxage=3600
Surrogate-Control: max-age=3600

サーバーサイドのキャッシュ

サーバーサイドは3つのレイヤーで構成します。

  • ETagリポジトリレイヤー
  • サーバーサイドキャッシュレイヤー
  • オリジンレイヤー
  1. CDNから到達したHTTPリクエストが、条件付きリクエストの場合には、コンテンツに変更がないかをETag リポジトリレイヤーが判定してなければ304を返します。ストレージに容量はあまり必要ないのでMemcachedのようなストレージが向いています。
  2. 対応するURLのサーバーサイドのキャッシュがあればそれを返却します。Redisなどを使います。
  3. キャッシュがなければ、オリジンレイヤーでレスポンスを返しますが、その時のキャッシュ可能なコンテンツはETagをETagレポジトリに格納してレスポンスデータをサーバーサイドキャッシュに格納します。

キャッシュが生成される順番

サーバーからクライアントまでキャッシュコンテンツが伝わる様子は以下のとおりです。

  1. オリジンサーバーがコンテンツを生成します。
  2. コンテンツのETagをETagレポジトリに格納します。
  3. コンテンツのキャッシュをサーバーサイドのキャッシュに保存します。
  4. オリジンはHTTPヘッダーでETagを返します。 ETag: ""
  5. CDNはそのETagとその内容をCDNキャッシュに保存します。
  6. クライアントはコンテンツをローカルにキャッシュします。

クライアントAのリクエストでこのキャッシュが生成された時に、別のクライアントBは4で保存されたCDNキャッシュの恩恵を受けます。

WebブラウザにはCache-Controlヘッダーを理解しその通りに振る舞いますが、APIクライアントの場合にはCache-Controlヘッダーを理解するためにRFC7234対応のクライアントを利用する必要があります。

RFC7234対応APIクライアント

キャッシュの強さ順

より強力なキャッシュの順番にリストします。

  • ネットワークコストの発生しないクライアントキャッシュ(TTL)
  • 都度確認をするクライアントキャッシュ(ETag)
  • 304を返すCDN(ETag)
  • キャッシュコンテンツを返すCDN
  • 304を返すサーバーサイド(Etag)
  • キャッシュコンテンツを返すサーバーサイド

キャッシュシステム設計

サーバーサイドのアプリケーションは、コンテンツの変更の際にキャッシュ管理処理をトリガーします。

  • サーバーサイドのキャッシュを保存 (Redisなど)
  • サーバーサイドでETagを保存 (memcacheなど)
  • CDNに対してのAPIでパージ操作

BEAR.Sundayは一般的なMVCフレームワークよりこれらの操作に適した特徴があります。

  • リソースはURIがあり、その操作はステートレス
  • リソースのメソッドにセマンティックがありどれが読み込みで(onGet)どれが更新か区別がある
  • AOP可能

ユーザーがアプリケーションで操作をすることなく、大部分のキャッシュ操作がフレームワークにより自動化されれます。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?