3.15

View in English

3.15 キャッシュとコンテンツ配信

概要と動機

キャッシュとは、元のデータよりも速い、あるいは近い場所に保たれたデータのコピーで、完全で高価な仕事をもう一度行わずに、リクエストに答えられるようにするものです。速く感じられるほとんどすべてのシステムは、キャッシュのおかげで速いのです。40ミリ秒かかるはずのデータベースのクエリは、その結果がすでにメモリにあれば、1ミリ秒未満で返ります。海を越えるはずの画像は、同じ都市のマシンから提供されます。キャッシュは、持てる最もてこの効く単一の性能技法であり、また、微妙で気が狂いそうなバグを渡す可能性が最も高いものでもあります。

本章は、キャッシュ戦略に深く踏み込みます。3.4章(データアーキテクチャとストレージ)は、キャッシュとコンテンツ配信ネットワークを、多くの中の一つのストレージの関心事として紹介し、3.13章(ネットワーキングと接続性)は、それらが乗るネットワークの経路を扱います。ここでは決定を得ます。キャッシュをどこに置くか、どうキー付けするか、いつ無効化するか、負荷のもとでどう守るか、速度と引き換えにする古さをどう推論するか。キャッシュは、性能エンジニアリング(2.16章)、スケーラビリティとレジリエンス(3.5章)、分散システムの部分的な失敗の現実(3.3章)に触れ、毒されたキャッシュが数千のユーザーに攻撃を提供しえるので、アプリケーションセキュリティ(4.2章)にも触れます。

動機は三つのてこに帰着します。キャッシュはレイテンシを削るので、ユーザーの待ちが減ります。負荷を削るので、オリジンが同じハードウェアでより多くのトラフィックを扱えます。そしてコストを削ります。縁で答えられたリクエストは、データベース、コンピュート、エグレスの請求書に決して触れないからです。大きなチームにとって、共有のキャッシュ戦略は、予測可能にスケールするプラットフォームと、すべてのサービスが無効化を再発明して間違えるプラットフォームの違いです。申告の期限やローンチの日にトラフィックが急増する企業と政府のシステムでは、よく設計されたキャッシュが、動くポータルと公の失敗の間に立つものであることがよくあります。

主要原則

  • レイテンシ、負荷、コストを削るためにキャッシュし、どれを買っているかを知ります。
  • 階層の適切な層、最も助けになる場所に最も近い所にキャッシュを置きます。
  • 無効化を難しい部分として扱います。キャッシュする前にキーと寿命を設計します。
  • 合体、ジッター、スタンピードへの防御で、負荷のもとでキャッシュを守ります。
  • 書き込みのパターンを意図して選びます。一貫性と速度は互いに引き合います。
  • ヒット率、古さ、オリジンの負荷を測定します。測定されないキャッシュは負債です。
  • キャッシュされたコンテンツを攻撃面として扱います。毒されたキャッシュは全員に提供されます。

推奨事項

キャッシュの階層を理解する

キャッシュは、一つの場所にある一つのものではありません。それぞれが前のものよりユーザーに近い、コピーの階層で、そのすべてにわたって設計します。ユーザーに最も近いのはクライアントのキャッシュです。ブラウザのHTTPキャッシュ、モバイルアプリのローカルストア、プロセス内のメモリキャッシュ。次がコンテンツ配信ネットワーク(CDN)、世界中に分散した、ネットワークのエッジのユーザーの近くにコンテンツのコピーを保持するサーバーの群れです。その背後にリバースプロキシやゲートウェイのキャッシュ、サーバーの前の共有キャッシュがあります。それからアプリケーションのキャッシュ。計算結果、セッション、描画されたフラグメントを保持する、インメモリデータグリッドのような高速なキーバリューストア。最後にデータベース自身のクエリとバッファのキャッシュで、ホットなページをメモリに保って、ディスクに触れる回数を減らします。

各層は異なる仕事に仕えます。クライアントのキャッシュはリクエストを完全に排除し、CDNは世界的な読み取りトラフィックを吸収し、リバースプロキシはオリジンを繰り返される同一の仕事から守り、アプリケーションのキャッシュは再計算を節約し、データベースのキャッシュはストアの応答性を保ちます。すべての層を外してデータベースに届くリクエストは、持つ中で最も遅く最も高価な経路なので、階層の要点は、安全にできる限り上の、外の方で答えることです。システムとして設計してください。アプリケーション層のキャッシュされたフラグメントと、その上の古いCDNのコピーは、ユーザーを混乱させる形で食い違いうるからです。

無効化を難しい問題として扱う

コンピュータサイエンスで最も難しい問題は二つ、名付けること、キャッシュの無効化、そして一つずれの誤り、という古い冗談があります。その冗談が残るのは、無効化が本当に難しいからです。キャッシュはコピーで、元が変わった瞬間、すべてのコピーが潜在的な嘘になります。広く三つの戦略があります。生存時間(TTL)、つまりエントリが古いと見なされるまで有効な期間を伴う時間ベースの有効期限が最も単純です。限られた古さを受け入れ、エントリを時間で消えさせます。明示的な無効化は、元のデータが変わったときにエントリを消去または更新するもので、正確ですが、すべてのコピーがどこに住んでいるかを知る必要があります。イベント駆動の無効化は、キャッシュを変更イベントに購読させて自ら更新させるもので、多くのキャッシュにわたってよりよくスケールしますが、メッセージングへの依存を加えます。

実際のほとんどのシステムはこれらを混ぜます。頻繁に変わり数秒の古さを許容するデータには短いTTL、まれにしか変わらないが変わったときは正しくなければならないデータには長いTTLと明示的な消去、公開されたら不変のコンテンツにはバージョン付きのキー。バージョン付きキーの技は身につける価値があります。無効化する代わりに、キーを変えるのです。app.v187.cssとして提供されるスタイルシートは、新しいバージョンが新しいキーなので、古いものはただ要求されなくなり、消去を必要としません。無効化の問題を命名の問題に変えられるときは、そうしてください。

キャッシュのキーとTTLを意図して設計する

キャッシュは、そのキーの分だけ良いものです。キャッシュキーは値が保存され検索される識別子で、それを間違えると二つの正反対の失敗が起こります。粗すぎると、あるユーザーのデータを別のユーザーに提供します。ユーザーのアイデンティティを無視するURLの下にキャッシュされたパーソナライズされたページは、データの漏洩です。細かすぎると、二つのリクエストがキーを共有しないので、ヒット率が崩れます。何がキーに属するかを意図して決めてください。リソースのアイデンティティに加え、応答を正当に変えるもの(言語、通貨、デバイスのクラス)で、それ以外は何も入れません。クエリパラメータの順序のような些細な違いがキャッシュを断片化しないよう、キーを正規化します。

TTLにも同じ思慮が値します。TTLは、提供する最大の古さについての約束なので、誰かが推測した切りのいい数字ではなく、データの本当の許容度から設定します。株価の表示は数秒を許容し、商品カタログは数分、公布された規則は数時間、あるいはバージョン付きのキーで有効期限なし。小さなランダムな広がり、ジッターを加え、一緒に書き込まれたエントリの束が同じ瞬間に期限切れになってオリジンにスタンピードしないようにします。これらの選択を書き留めてください。根拠のないTTLは、次のエンジニアが変えるのを恐れる数字だからです。

スタンピードを防ぎ、リクエストを合体させる

人気のあるキャッシュされたエントリが期限切れになると、それを望んだすべてのリクエストが一度に外れ、一斉にオリジンに殺到します。これがキャッシュスタンピード、雷鳴の群れとも呼ばれるもので、キャッシュが守っていたまさにそのデータベースを倒しえます。防御を一度築いて、あらゆる所で再利用します。リクエストの合体(シングルフライト)は、欠けているキーの最初のリクエストだけが値を再計算し、他が結果を待つようにするので、千の同時のミスが一つのオリジン呼び出しを引き起こします。確率的な早期の再計算は、ホットなエントリを期限切れの少し前にランダムに更新するので、群衆がミスを見る前に、一つのバックグラウンドのリクエストがそれを更新します。stale-while-revalidateの方針は、わずかに古いコピーを即座に提供し、非同期に更新するので、ユーザーはミスで待つことがまったくありません。

これらのパターンが最も重要になるのは、まさにキャッシュが最も必要なピーク負荷のもとなので、現実的な規模で検証してください。10人のユーザーで機能する防御も、1万人では失敗しえます。3.5章のレジリエンスのパターン、特にタイムアウトとサーキットブレーカーと組み合わせ、オリジンが本当に遅いとき、キャッシュ層がそれを守り、積み上げることがないようにします。目標は、圧力のもとで最もよく振る舞うキャッシュで、急増を障害に増幅するものではありません。

書き込みのパターンを意図して選ぶ

書き込みをどう扱うかが、キャッシュがどれだけ新鮮に保たれ、失敗時にどれだけのリスクを負うかを決めます。四つの一般的なパターンがあります。キャッシュアサイド(遅延読み込み)では、アプリケーションがキャッシュを確認し、ミスのときはオリジンを読み、キャッシュに投入して値を返します。書き込みはオリジンに行き、エントリを無効化します。単純で、キャッシュは要求されたものだけを保持するので、もっともな理由で既定です。ライトスルーでは、すべての書き込みがキャッシュとオリジンに一緒に行くので、キャッシュは常に最新ですが、書き込みのレイテンシと、決して読まれないかもしれないデータをキャッシュするコストがかかります。ライトバック(ライトビハインド)では、書き込みが最初にキャッシュに当たり、非同期にオリジンにフラッシュされるので、書き込みは速いですが、フラッシュの前にキャッシュが死ぬと失うリスクがあります。ライトアラウンドでは、書き込みがキャッシュを飛ばしてオリジンに直接行き、めったに読まれない書き込みの多いデータによる入れ替わりを避けますが、最初の読み取りが必ずミスするというコストがかかります。

システム全体で一度ではなく、ワークロードごとに選びます。読み取りの多いカタログは、キャッシュアサイドかライトスルーに合います。書き込みの多いログやメトリクスのストリームは、誰も再び読まないデータでキャッシュが入れ替わらないよう、ライトアラウンドに合います。ライトバックは、小さく理解されたリスクの損失が許容でき、耐久性が他で扱われる、高スループットの書き込みに合います。各キャッシュのパターンを明示的に述べてください。コードがライトバックをしているのにキャッシュアサイドを想定する読み手は、鮮度と失敗の振る舞いの両方を誤って判断するからです。

退避ポリシーをアクセスパターンに合わせる

キャッシュには固定されたサイズがあるので、満杯になったとき、何かが出なければなりません。退避ポリシーが何を決めます。最も最近使われていない(LRU)は、最も長く触れられていないエントリを退避し、最近の使用が将来の使用を予測するという賭けで、妥当な既定です。最も使用頻度の低い(LFU)は、ヒットが最も少ないエントリを退避し、少数の項目が常に人気のある安定したホットセットに合いますが、かつて熱かっただけのエントリにしがみつき、適応しないことがあります。セグメント化LRUや適応的なポリシーのような変種は、最近性と頻度を混ぜます。先入れ先出しと単純な時間ベースの期限切れは、より安く、より鈍いものです。

ポリシーをデータのアクセスのされ方に合わせます。めったに変わらない小さなホットセットにはLFUや頻度を考慮するポリシー、ニュースやトレンドのコンテンツのように、人気が時間とともに動く所にはLRU。何を選ぶにせよ、ホットセットが収まるようキャッシュのサイズを決めてください。作業セットを保持するには小さすぎるキャッシュは、エントリが再び必要になる直前に退避して、空回りするからです。退避率を第一級の指標として観察してください。急な上昇は、通常、キャッシュのサイズが足りないか、キーの爆発がそれを断片化していることを意味するからです。

HTTPのキャッシュの意味論を正しく使う

ウェブにはHTTPに組み込まれた成熟した標準化されたキャッシュのモデルがあり、それをうまく使えば、クライアントとCDNのキャッシュがただで得られます。Cache-Controlヘッダーが制御面です。max-ageは鮮度の寿命を設定し、publicとprivateは共有キャッシュが応答を保存してよいかを言い、no-storeはキャッシュを禁じ、stale-while-revalidateは更新する間に古いコピーを提供することを許します。検証により、キャッシュは本体を再取得せずに安く鮮度を確認できます。ETag(エンティティタグ)は、サーバーが応答に付ける不透明なバージョン識別子で、クライアントはIf-None-Matchヘッダーでそれを送り返し、何も変わっていなければ、サーバーは本体なしの304 Not Modifiedで応答します。Last-ModifiedとIf-Modified-Sinceは、タイムスタンプを使って同じことをします。

実用的な規律は、明示的であることです。キャッシュにヒューリスティクスで推測させるのではなく、すべての応答にCache-Controlを設定します。共有のプロキシがそれを決して保存しないよう、ユーザーごとのプライベートな応答をprivateかno-storeと印付けします。それは一般的で危険な間違いです。静的アセットには、長いmax-ageとimmutableディレクティブを伴うバージョン付きのURLを使い、予測できない形で変わるコンテンツには、ETagによる検証を使います。これらのヘッダーを正しくすれば、クライアントとCDNの層全体が、築く必要のなかった正しい標準ベースのキャッシュになります。

CDNとエッジコンピューティングで仕事をエッジに押しやる

CDNは、ユーザーの近くに静的なファイルをキャッシュする方法として始まり、今もそれを見事に行います。画像、スクリプト、動画、ダウンロードを、遠いオリジンではなく、数ミリ秒先のエッジの拠点から提供する。現代のCDNはさらに進みます。動的でパーソナライズされたコンテンツを細かなキーでキャッシュし、エッジでTLSを終端し、トラフィックの急増と分散型サービス拒否攻撃を吸収し、ますますあなたのコードを実行します。エッジコンピューティングは、エッジの拠点そのもので論理を実行するので、中央のリージョンへのラウンドトリップなしに、応答をパーソナライズし、認可を確認し、ページのフラグメントを組み立てられます。

ほとんどのシステムを支配する読み取りのために、これに頼ってください。静的アセットを、長寿命のバージョン付きURLでCDNの背後に置き、鮮度が許す所ではAPIの応答をエッジでキャッシュし(パーソナライズが漏れないよう慎重にキー付けして)、ユーザーの近くの、レイテンシに敏感で軽量なロジックにエッジの計算を使います。トレードオフは到達範囲と制御です。エッジは速く近いですが、データから遠く、デバッグしにくいので、強い一貫性や新鮮で権威ある状態を要するものはオリジンに保ち、エッジに、膨大でキャッシュ可能な読み取りトラフィックを扱わせます。

キャッシュを攻撃面として扱う

キャッシュは同じ保存された応答を多くのユーザーに提供するので、標的になります。キャッシュポイズニングは、キャッシュが有害な、あるいは攻撃者が制御する応答を保存して、その後に続く全員に提供するよう、リクエストが細工される攻撃です。通常はキー付けされない入力を悪用します。アプリケーションが応答に反映するが、キャッシュがキーを構築するときに無視するヘッダー。関連するウェブキャッシュ欺瞞の攻撃は、キャッシュをだまして、被害者の私的な応答を公開URLの下に保存させます。どちらもキー付けと入力の信頼の失敗であり、4.2章でより広く扱われます。

意図して防御します。応答を変えうるあらゆる入力をキャッシュキーに含め、キー付けされないヘッダーをキャッシュされた本体に反映することを拒否します。共有キャッシュに、認証されたユーザーごとの応答を共有のキーで保存させてはいけません。キャッシュする前にリクエストのパスとパラメータを正規化して検証します。Varyを正しく設定し、キャッシュが、コンテンツのエンコーディングや言語のような、実際に重要なヘッダーで応答を分割するようにします。毒されたエントリ一つが、下流のすべてのユーザーを傷つけるので、キャッシュの設定を、セキュリティに敏感なコードとして扱い、そのようにレビューしてください。

キャッシュの振る舞いを観察可能にする

見えないキャッシュは管理できません。見出しの指標はヒット率、つまりオリジンではなくキャッシュから提供されたリクエストの割合です。静かに95から70パーセントに落ちるヒット率は、オリジンの負荷を数倍にしえて、障害に先行しえ、それを見ていてこそ早期に捉えられます。各層を別々に計装してください。健全なCDNのヒット率は、その下で崩壊しているアプリケーションキャッシュのヒット率を隠しうるからです。これは、9.2章のオブザーバビリティの実践の、キャッシュ固有の顔です。

ヒット以上のものを追跡します。サイズ不足を捉える退避率とメモリの圧力、キャッシュが実際に速いことを確認する各層のレイテンシ、キャッシュが吸収する負荷の量を見るオリジンのリクエスト率、鮮度の約束を守っていることを確認する古さ(提供されたエントリがどれだけ古いか)。トラブルを予測する比率、特に下がるヒット率や上がる退避率にアラートを出し、劣化するキャッシュを、ユーザーからではなくダッシュボードから知るようにします。観察されたキャッシュは調整できる資産で、観察されないものは、驚かせるのを待っている隠れた依存先です。

トレードオフ: 長所と短所

キャッシュは、鮮度と複雑さを通貨に、速度とスケールを買います。すべてのキャッシュは、この特定のデータについて、古いが速いほうが、新鮮だが遅いより良いという賭けで、技芸はその賭けを既定ではなく意識して置くことです。以下の表は主な選択をまとめます。

選択長所短所
キャッシュアサイド単純。読まれたものだけをキャッシュする最初の読み取りは常にミスする。書き込み後に短い古さのリスク
ライトスルー書き込み時にキャッシュが常に最新書き込みが遅い。読まれないかもしれないデータをキャッシュする
ライトバック非常に速い書き込み。バーストを吸収するフラッシュ前にキャッシュが失敗するとデータ損失のリスク
ライトアラウンド書き込みの多いデータでキャッシュが入れ替わるのを避ける最初の読み取りが必ずミスする
短いTTL限られた小さな古さヒット率が低い。オリジンの負荷が多い
長いTTL / バージョン付きキー高いヒット率。低いオリジンの負荷無効化しないと古くなる。規律あるキーが必要
CDNとエッジ世界的な低レイテンシ。急増を吸収するデータから遠い。デバッグと無効化が難しい
LRUの退避変わる人気に適応するスキャンの多い負荷のもとで安定したホットセットを退避しうる
LFUの退避安定したホットセットを守る適応が遅い。かつて熱かったエントリにしがみつく

繰り返される緊張は、一貫性と性能です。長いTTLと高いヒット率を持つキャッシュは、速く安く、古いデータを提供しえます。短いTTLと積極的な無効化を持つキャッシュは、新鮮で正しく、オリジンをより酷使します。普遍的に正しい答えはなく、データごとの、古さへの本当の許容度で決まる正しい答えがあるだけです。二つ目の緊張は、単純さと到達範囲です。アプリケーションのキャッシュはデータに近く、推論しやすく、エッジは遠く、速く、無効化しにくい。データを鮮度のニーズと読み取りの量で分類し、それから各クラスを意図して置き、設定することで、両方を解決してください。

チームで議論すべき問い

  1. キャッシュする各種類のデータの本当の古さの許容度は何で、TTLと無効化を習慣ではなくその許容度から設定しましたか。 ほとんどのチームは、誰かが一度選んで二度と見直さないTTLでキャッシュするので、一部のデータはビジネスが受け入れられるより古く提供され、他のデータはあまりに積極的に期限切れになってキャッシュがほとんど役立ちません。上位十のキャッシュされたリソースを持ち込み、それぞれについて、そのデータを所有する人々に、どれだけ古くても安全かを尋ねてください。数秒、数分、数時間、あるいは公開されたら決して。答えが大きく異なり、現在のTTLがそれに合っていないことが通常わかります。求める成果は、短い鮮度の分類で、各クラスがアプローチ(短いTTL、長いTTLと消去、バージョン付きの不変のキー)に対応づけられ、キャッシュの決定が推測ではなくデータの意味論に従うようにすることです。

  2. 最も人気のあるキャッシュのエントリが、ピークのトラフィックのもとで今期限切れになったら、オリジンはどうなりますか。 この問いは、本物のスタンピードへの防御があるのか、希望だけなのかを露わにします。多くのシステムは、ホットなキーがトラフィックのピークの間に期限切れになり、すべてのリクエストが一度にデータベースに殺到して、キャッシュを盾から引き金に変えるまで、うまく動きます。最も忙しいエンドポイントの経路を具体的にたどってください。一つのミスだけがオリジンに届くリクエストの合体はありますか。エントリが足並みを揃えて期限切れにならないジッターはありますか。ユーザーが再投入で待たないstale-while-revalidateの方針はありますか。直感ではなく負荷テストの証拠を持ち込んでください。10人のユーザーで保たれるスタンピードへの防御も、1万人で崩壊しえるからです。自信をもって答えられないなら、次のレジリエンスへの投資が見つかりました。

  3. 共有キャッシュが、別のユーザーが当てられるキーの下に、あるユーザーの私的なデータを保存することは決してないと確信できますか。 これは、セキュリティインシデントと見出しになるキャッシュの間違いです。パーソナライズされたり認証された応答が、ユーザーのアイデンティティを省いたキーの下にキャッシュされるとき、あるいは応答を私的に保つはずのCache-Controlヘッダーが欠けていて、共有のプロキシやCDNがそれを保存して次の人に提供するときに起こります。どの応答が共有の層でキャッシュ可能かを監査し、すべてのユーザーごとの応答がprivateかno-storeと印付けされていること、すべてのキャッシュキーが応答を変えるあらゆる入力を含んでいることを確認してください。影響範囲がすべての下流のユーザーなので、これをセキュリティレビューとして扱い、4.2章の実践に結びつけます。

  4. 各キャッシュは実際にどの書き込みのパターンを使っていて、誰かが意図してそれを選びましたか。 キャッシュアサイド、ライトスルー、ライトバック、ライトアラウンドは、鮮度についても、キャッシュが失敗したときに失うものについても、正反対の約束をしますが、ほとんどのコードベースでは、パターンは最初の作者がたまたまコピーしたものです。大きなチームにとって、これが重要なのは、あるサービスがキャッシュアサイドの鮮度を想定し、別のサービスが静かにライトバックを走らせていると、壊れて見えるが単に古いだけのデータを生み、オンコールのエンジニアが幽霊を追って何時間も無駄にしうるからです。キャッシュごとの一覧を持ち込んでください。書き込みのパターン、それが保証する鮮度、プロセスが死んだときにフラッシュされない書き込みがどうなるか。ライトバックを使うキャッシュがあるなら、それを裏付ける耐久性の話を持ち込んでください。財務や記録のデータを扱う企業と政府のシステムでは、裏付けとなる保証のないライトバックのキャッシュは、起こりかけている監査の指摘なので、議論は、各キャッシュのパターンが名指しされ、正当化され、書き留められて終わるべきです。

  5. デプロイやデータの変更のとき、すべての関連するキャッシュ層が正しく無効化されますか。それとも、誰かが消去を覚えていることに頼っていますか。 無効化は難しい部分で、失敗モードは静かです。階層の一つの層、CDN、リバースプロキシ、アプリケーションのキャッシュのいずれかがメッセージを受け取らなかったために、訂正された値が何時間も間違ったままになる。大きな組織はこのリスクを増幅します。一つの論理的な変更が、異なるチームが所有する多くのリージョンの多くのキャッシュに伝播する必要があるかもしれないからです。最近のデータの変更の具体的なトレースを持ち込み、すべてのキャッシュ層をたどって、それぞれで問ってください。ここで何が無効化を引き起こし、どれだけかかったか。無効化を命名(バージョン付きキー)やイベント(変更が消去を公開する)に変える設計を、手作業のランブックより好みます。公表された数字、税率や給付額の誤りが法的な重みを持ちうる公共部門のシステムでは、無効化のギャップは些細なことではなくコンプライアンス上のリスクなので、成果は、キャッシュされたデータのすべてのクラスの、マップされた無効化の経路であるべきです。

  6. キャッシュを共有のプラットフォームインフラとして扱っていますか。それとも、すべてのチームが自分でキー、無効化、スタンピードへの防御を再発明していますか。 うまく行われたキャッシュは、一度で解決される少数の難しい問題です。正規化されたキー、イベント駆動の無効化、リクエストの合体、正しいHTTPの意味論、層ごとのオブザーバビリティ。各チームがこれらを即興すると、大きな組織は同じ間違いに繰り返し払い、一つのサービスで直されたポイズニングのバグや私的なデータの漏洩が、他の十のサービスで静かに残り続けます。今日誰がキャッシュの規約を所有し、サービス間にどれだけの重複したキャッシュのコードがあるかについての誠実なマップを持ち込んでください。相反する考慮は自律です。チームは義務づけられた共有ライブラリに抵抗するので、採用しやすい舗装された道の既定と、徹底される厳格な標準を量ってください。企業や政府のプラットフォームグループにとって、共有のよくテストされたキャッシュ能力は、セキュリティと監査の要件が一様に成り立つようにする最も安い方法でもあるので、議論は、何が共有のインフラになり、誰が資金を出すかを決めるべきです。

セクター別の視点

スタートアップ。 キャッシュは、まだスケールのために負担できないトラフィックの急増を生き延びる、最も安い道なので、乏しい時間を少数のてこの効く配置に使ってください。静的アセットにバージョン付きURLを伴うCDNと、最もホットなクエリの前に短いTTLとジッターを伴う単一のキャッシュアサイド層。自前で動かすのではなく、マネージドなCDNとキャッシュのサービスに頼り、リクエストの合体を早期に加えます。小さなデータベースに対するローンチ日のスタンピードは、良い日を悪く終わらせる可能性が最も高い失敗だからです。重要だと教えるデータができるまで、凝った無効化の方式は省きます。

小規模事業者。 キャッシュの専門家はおらず予算も厳しいので、すでに動かしているツールの中で無料で得られるキャッシュを買うことを好みます。ホスティングに同梱されたCDN、ウェブフレームワークの応答の上のHTTP Cache-Controlヘッダー、データベースに組み込まれたクエリキャッシュ。作るか買うかの判断はほぼ常に買うに傾きます。あるお客様のデータを別の顧客に漏らす誤ったキーのキャッシュは、避けたマネージドサービスよりはるかにコストがかかるからです。二つの安い勝利を正しくしてください。正しいHTTPヘッダーと、共有の層で認証されたページを決してキャッシュしないこと。そして風変わりなパターンには手を出しません。

大企業。 多くのチームにわたる規模では、リスクは単一のキャッシュからそれらの間の不一致に移ります。分岐したキーの方式、不均一な無効化、一つのサービスに現れて他には現れない私的なデータの漏洩。キー、無効化、スタンピードへの防御、層ごとのオブザーバビリティの舗装された道の既定を伴う、共有のプラットフォームインフラとしてキャッシュを提供し、ヒット率、退避、古さが一か所で見え、一様に統治されるようにします。キャッシュの設定を、セキュリティに敏感なコードとしてレビュー可能にし、リージョンをまたぐ無効化を、チームごとのランブックではなく、第一級の設計の問題として扱います。

政府。 調達と透明性の制約が、何をキャッシュでき、それが安全だとどう証明するかを形づくります。公開コンテンツ(ガイダンス、書式、税率表)を、長いTTLを伴うCDNの背後で積極的にキャッシュし、申告の期限の急増がオリジンから遠くで吸収されるようにし、監査のためにその設定を文書化します。市民自身の記録を示す認証されたページは、共有キャッシュに決して触れてはならず、そのルールは単に主張されるのではなく、検証可能であるべきです。CDNやキャッシュのサービスがベンダーから調達される所では、契約が必要な制御(キー付け、消去、ログ)を公開するよう求め、公共のデータを独自のキャッシュ形式の背後に閉じ込めるロックインを避けます。

事例

スタートアップ。 小さな消費者向けアプリは、商品カタログを、インメモリストアに支えられたキャッシュアサイド層を通し、エントリが一緒に期限切れにならないよう60秒のTTLとジッターを使います。静的アセットは、バージョン付きファイル名と1年のmax-ageでCDNへ行くので、スタイルシートを変えるデプロイは新しいURLを提供し、消去を必要としません。人気のポッドキャストでのローンチがトラフィックの急増を送ったとき、シングルフライトの合体により、何千もの同時のホームページのミスが、何千ではなく一つのデータベースの読み取りを引き起こします。創業者はキャッシュにほとんどお金を使いませんが、いくつかのよく選ばれたキャッシュを意図して置いたので、小さなデータベースを溶かしたはずの急増を扱えます。

大企業。 世界的な小売業者は、層をなすキャッシュを通じて何百万もの買い物客に提供しています。画像とキャッシュ可能なAPI応答のためのCDN、各リージョンの共有のリバースプロキシキャッシュ、計算された価格と在庫のフラグメントのためのアプリケーションキャッシュ。キャッシュキーは正規化され、通貨、言語、デバイスのクラスを含むので、パーソナライズは漏れず、ヒット率は高いままです。商品データは、イベント駆動の無効化を伴う短いTTLを使うので、価格の変更がメッセージバスに公開され、数秒のうちにリージョンをまたいで影響するキーを消去します。すべての層が、ヒット率、退避率、古さを9.2章のオブザーバビリティのプラットフォームに報告し、ヒット率の低下へのアラートが一度、サイズ不足のキャッシュを、チェックアウトの障害になる前に捉えました。

政府。 国の税務当局は、一年のほとんどは静かで、期限の近くに圧倒される申告ポータルを運用しています。チームは安全な所では積極的に、そうでない所では決してキャッシュしません。公開コンテンツ(ガイダンスのページ、書式、税率表)は、長いTTLとバージョン付きURLを伴うCDNから提供され、期限日の読み取りの急増をオリジンから遠くで吸収します。市民自身の申告を示す認証されたページはno-storeと印付けされ、共有キャッシュに決して触れないので、どの納税者も他人のデータを提供されることはありません。キャッシュの設定は、4.2章の実践に照らして、セキュリティに敏感なコードとしてレビューされ、スタンピードへの防御は、何か月も前に期限の規模で負荷テストされるので、かつて一年で最も忙しい日に崩れたポータルが、今は耐えます。

ビジネスケース: 動機、ROI、TCO

キャッシュの見返りは、並外れて直接的で、定量化しやすいものです。ヒット率を80から95パーセントに上げるキャッシュは、オリジンのトラフィックを4分の3削り、それはデータベースのアップグレードの延期、より少ないアプリケーションサーバーの運用、そうでなければ緊急のスケーリングを要したであろうトラフィックの急増の生き延びを意味しえます。レイテンシの改善は、商取引では収益に、公共サービスでは満足と完了率に変わります。そこでは、より速いページがより高いコンバージョンとより低い離脱に結びつくことが、長く研究されています。エッジから提供されたリクエストは、オリジンの帯域や処理に決して払わないので、エグレスとコンピュートのコストは下がります。読み取りの多いシステム、つまりほとんどのシステムにとって、キャッシュはしばしば買える最も安い性能です。

総所有コストを誠実に量ってください。直接のコストはささやかです。CDNとキャッシュのインフラは、それが節約するオリジンの容量に比べて安い。本当のコストはエンジニアリングの規律です。間違ったキャッシュは、キャッシュがないより悪いからです。古さのバグ、無効化の間違い、キャッシュポイズニングの脆弱性はすべて本物のコストを伴い、キャッシュが共有のよくテストされた能力として提供されるのではなく、チームごとに即興されるときに増えます。最も強いビジネスケースは、少量の共有のキャッシュのインフラと規約(標準のキー、無効化、スタンピードへの防御、オブザーバビリティ)に資金を出し、すべてのチームが、間違いを繰り返さずに利益を得られるようにします。リーダーシップのために枠づけると、キャッシュは彼らがすでに追跡している指標に結びつきます。インフラのコスト、ページのレイテンシ、コンバージョンと完了率、ピークのイベント中のインシデントの頻度。

アンチパターンと落とし穴

  • 無効化のないキャッシュ: 消去する方法のない長いTTLを設定し、訂正された値が何時間も間違ったままになること。
  • 粗すぎるキー: パーソナライズされた応答を共有のキーでキャッシュし、あるユーザーのデータを別のユーザーに漏らすこと。
  • 細かすぎるキー: 変動する入力をキーに含め、二つのリクエストが決して一致せず、ヒット率が崩れること。
  • スタンピードへの防御がない: ホットなキーが負荷のもとで期限切れになり、すべてのリクエストが一度にオリジンに殺到すること。
  • 同期した期限切れ: 一緒に書き込まれたエントリの束が、ジッターなしに同じ瞬間に期限切れになり、周期的な雷鳴の群れを引き起こすこと。
  • 共有の層で私的なデータをキャッシュする: Cache-Control: privateやno-storeが欠けていて、プロキシやCDNが認証された応答を保存すること。
  • キー付けされない入力の無視: ヘッダーを応答の本体に反映しながらキーから省き、キャッシュポイズニングへの扉を開くこと。
  • サイズ不足のキャッシュ: 作業セットを保持するには小さすぎるキャッシュが、エントリが再び必要になる直前に退避して空回りすること。
  • 測定されないキャッシュ: ヒット率も退避の指標もなく、劣化するキャッシュが障害になるまで見えないこと。
  • 耐久性のないライトバック: フラッシュの前にキャッシュが死ぬと消えてしまう速い書き込みで、裏付けとなる保証がないこと。

成熟度モデル

  • レベル1、開始: キャッシュは場当たり的で開発者ごとで、何かが遅く感じられたときに反応的に加えられます。TTLは推測され、キーは一貫せず、無効化は手作業か不在で、古いデータと謎のバグが一般的です。誰もヒット率を追跡せず、キャッシュが吸収するはずだったトラフィックの急増が、代わりに障害を引き起こします。
  • レベル2、発展: チームは明らかな場所でキャッシュし、静的アセットにCDNを使います。基本的なTTLとキャッシュアサイドが現れますが、規約はサービスごとに異なり、無効化は一貫せず、スタンピードへの防御はなく、私的対共有のキャッシュのルールは非公式で、オブザーバビリティはときどきの抜き打ち確認に限られます。
  • レベル3、標準化: キャッシュ戦略が文書化され、組織全体で徹底されています。キャッシュキーは正規化され、TTLは共有の鮮度の分類に従い、無効化は重要な所でイベント駆動で、スタンピードへの防御と正しいHTTPの意味論は標準で、私的なデータは共有の層で決してキャッシュされず、すべての層がヒット率と退避を共通のオブザーバビリティのパイプラインに報告します。
  • レベル4、管理: キャッシュがベースラインに対して測定され、制御されています。各層には目標のヒット率、古さの予算、退避の閾値があり、ダッシュボードは、ヒット率が下がったり退避率がベースラインを超えて上がったりしたときにアラートを出します。スタンピードへの防御はピークの規模で負荷テストされ、オリジンの負荷の削減はキャッシュごとに定量化され、TTLと退避ポリシーは測定されたアクセスパターンから調整され、キャッシュの設定はリリース前にセキュリティに敏感なコードとしてレビューされます。
  • レベル5、オーケストレーション: キャッシュは継続的に改善され、組織全体に統合されています。配置、キー、TTLは変わるトラフィックに適応し、エッジの計算は価値を稼ぐ所で使われ、キャパシティ計画とコストモデルはキャッシュの指標に基づき、一つのチームのインシデントからの教訓は共有の規約に反映されます。組織は、キャッシュを、局所的な手口の寄せ集めではなく、設計され、測定され、適応的な能力として扱います。

議論のためのアイデア

  1. システムのどの単一のキャッシュが、今冷えたら最もオリジンを危険にさらし、何がそれを守っていますか。
  2. キャッシュの階層の各層について、現在のヒット率を記憶から言えますか。言えないなら、それは何を語りますか。
  3. 無効化の問題を、バージョン付きキーで命名の問題に変えたのはどこで、まだ変えられるのはどこですか。
  4. 書き込みの経路のうち、キャッシュアサイド、ライトスルー、ライトバック、ライトアラウンドのどれを使っているものがあり、それぞれ意図して選ばれましたか。
  5. 攻撃者がリクエストヘッダーを一つ制御できたら、ユーザーが共有するキャッシュされた応答を毒せますか。
  6. ヒット率が静かに20ポイント下がったことを、数分以内にどうやって知りますか。

要点

  • キャッシュはレイテンシ、負荷、コストを削り、キャッシュの階層(クライアント、CDNとエッジ、リバースプロキシ、アプリケーション、データベース)により、安全にできる限り上の、外の方で答えられます。
  • 無効化が難しい部分です。キャッシュキーとTTLを意図して設計し、できる所では、バージョン付きキーで無効化の問題を命名の問題に変えます。
  • リクエストの合体、ジッター、stale-while-revalidateで、負荷のもとでキャッシュを守ります。キャッシュは、スタンピードがそれを壊しうるまさにそのときに最も必要だからです。
  • 書き込みのパターンと退避ポリシーをワークロードごとに選び、キャッシュに推測させるのではなく、HTTPのキャッシュの意味論(Cache-Control、ETag、検証)を明示的に使います。
  • キャッシュされたコンテンツを攻撃面として扱い、ヒット率、退避、古さを測定します。観察されない、あるいはキー付けを誤ったキャッシュは、資産ではなく隠れた負債だからです。

参考文献とさらなる読み物

  • Martin Kleppmann, Designing Data-Intensive Applications
  • Andrew S. Tanenbaum and Herbert Bos, Modern Operating Systems
  • John L. Hennessy and David A. Patterson, Computer Architecture: A Quantitative Approach
  • Roy T. Fielding and Julian Reschke, “Hypertext Transfer Protocol (HTTP/1.1): Caching,” RFC 7234, IETF
  • Mark Nottingham, “Caching Tutorial for Web Authors and Webmasters”
  • James Kettle, “Practical Web Cache Poisoning,” PortSwigger Research
  • Betsy Beyer, Chris Jones, Jennifer Petoff, and Niall Richard Murphy (eds.), Site Reliability Engineering: How Google Runs Production Systems
  • Michael T. Nygard, Release It! Design and Deploy Production-Ready Software