HN 日本語サマリー

← 一覧へ戻る
Web開発

HTTPの最も厄介な部分であるVaryヘッダーのサポートをリリースしました – Cloudflare Blog

We just shipped support for the ugliest part of HTTP: Vary – Cloudflare Blog (blog.cloudflare.com)

41 pointsby thisisfatih4 コメント

要約

Cloudflareは、HTTPレスポンスヘッダーのVaryのサポートをCache Rulesで提供開始しました。Varyヘッダーは、キャッシュがリクエストフィールドの違いに基づいて適切なレスポンスを選択するために重要ですが、その複雑さがキャッシュ効率を低下させる問題がありました。今回のアップデートにより、CloudflareはVaryヘッダーの値を正規化、パススルー、またはバイパスするオプションを提供し、キャッシュの効率と正確性のバランスを取れるようになります。

全文翻訳

レスポンスヘッダーのVaryは、「まだ改善されていないHTTPの最も厄介な部分」と呼ばれてきました。同じ記事では、「ひどく、ぎこちないメカニズム」であり、中間キャッシュでの「相互運用性はかなりひどい」と評されています。通常、賢明なエンジニアであれば、手を挙げてゆっくりと後ずさりするところです。それはVaryを必ずしも推奨するものではありませんが、厄介だからといって役に立たないわけではありません。1つのURLは、複数の正しいレスポンスを持つことができます。例えば、サーバーは異なるブラウザに異なる画像フォーマットを提供するかもしれません。キャッシュがVaryを無視すると、間違ったバイトをリクエストに提供するリスクがあります。しかし、生のヘッダー値をすべて別個のものとして扱うと、少数の類似したリクエストが数千ものほとんど再利用できないキャッシュエントリに広がる可能性があります。Varyは、キャッシュにどのリクエストフィールドがレスポンスに影響を与えるかを伝えますが、どの違いが実際に重要であるかをキャッシュに伝えるわけではありません。 Varyのサポートは、現在すべてのプランのCache Rulesで利用可能です。オリジンは依然としてレスポンスに影響を与える可能性のあるリクエストヘッダーを指定しますが、Cloudflareがそれぞれをどのように処理するかはユーザーが決定します。既知のネゴシエーションヘッダーを正規化したり、その小さな違いが重要である場合に正確な値を渡したり、バリエーションが予測不可能すぎる場合にキャッシュをバイパスしたりできます。オリジンは変化する可能性のあるものを宣言し、ユーザーはどの程度の変化がキャッシュにとって実際に意味があるかを決定します。 Varyの仕組み Varyは、オリジンによって送信されるレスポンスに影響を与える可能性のあるリクエストフィールドを中間キャッシュ(Cloudflareなど)に伝える標準的なHTTPレスポンスヘッダーです。サイトはVaryを使用して、同じURLから異なる言語、画像フォーマット、圧縮方式、または地域コンテンツを提供します。 2つの有効な表現を生成する1つのURLを例に取ります。ブラウザがウェブページをリクエストします。 GET /catalog HTTP/1.1 Host: example.com Accept: text/html オリジンはHTMLを返し、Acceptをレスポンスに影響を与える可能性のあるフィールドとして識別します。 HTTP/1.1 200 OK Content-Type: text/html Cache-Control: public, max-age=3600 Vary: Accept APIクライアントは、異なるプリファレンスで同じURLをリクエストできます。 GET /catalog HTTP/1.1 Host: example.com Accept: application/json 今回は、正しいレスポンスはJSONです。Vary: Acceptヘッダーは、URLだけではレスポンス間の選択には不十分であることをキャッシュに伝えます。リクエストのAccept値も考慮する必要があります。 Varyがない場合、最初にキャッシュに入ったレスポンスが両方のクライアントに提供される可能性があります。HTMLが勝った場合、APIクライアントはマークアップを受け取り、JSONパーサーは失敗します。JSONが勝った場合、ウェブページを期待していたブラウザはAPIレスポンスを受け取ります。 Varyは、キャッシュがリクエストクライアントに間違ったレスポンスを提供するのを防ぎます。しかし、それはより難しい質問を提起します。2つのリクエストが異なるヘッダー値を含む場合、それらは実際に異なるレスポンスを必要とするのでしょうか? 正しいキャッシュが無駄になる場合 Varyは、キャッシュにどのリクエストフィールドがレスポンスに影響を与えるかを伝えることができます。それは、レスポンスが何を表すかをキャッシュに伝えるわけではありません。例えば、英語、フランス語、ドイツ語のいずれかのコンテンツのみを提供するオリジンを考えてみましょう。クライアントは以下を送信するかもしれません。 Accept-Language: en-US, fr;q=0.8 別のクライアントは以下をリクエストするかもしれません。 Accept-Language: fr;q=0.8, en-GB どちらのリクエストも、ここでは英語を優先しています。オリジンのレスポンスは、両方のリクエストをまったく同じ英語のレスポンスにマッピングする可能性があります。しかし、生の値を比較するキャッシュは、それらが同等であると安全に仮定することはできません。それらは異なる順序と言語タグ(オリジンが区別しないもの)を持っています。そのため、レスポンスボディが同一のバイトを含んでいても、キャッシュはそれらを別々のバリアントとして保存する可能性があります。 これがVaryの中心的な問題です。アプリケーションは、しばしば膨大な数の可能なリクエスト値から、小さく有限なセットの表現を生成します。オリジンは、数千もの言語プリファレンスが3つのサポートされている言語に収束することを理解していますが、キャッシュは通常それを理解しません。 この問題は、レスポンスが複数のフィールドで変化する場合に増幅されます。1つのフィールドにおける10の可能な値は、10のバリアントを作成します。3つのフィールドにおける10の値は、1,000の組み合わせを作成する可能性があります。実際のヘッダーははるかに大きなカーディナリティを持つ可能性があります。User-Agentの値は多数あり、Cookieは個々の訪問者に固有である可能性があり、プリファレンスヘッダーは順序、フォーマット(スペースとタブが重要!)、および品質値が異なる場合があります。 結果として、キャッシュは完全に正確でありながら、ほぼ永久にコールド(エントリが再利用されない)になる可能性があります。同一のレスポンスは、トラフィックが少なすぎてホットな状態を維持できないエントリに散らばる可能性があります。それらは容量を消費し、互いを追い出し、キャッシュヒット率を低下させ、オリジンサーバーへのリクエストを増やします。エントリの追い出しはコールドエントリを削除できますが、レスポンスが同一であるという理由だけでそれらをマージすることはできません。ほぼ50,000の人気サイトからの1億2000万以上のレスポンスの分析により、ほぼ3,000サイトが4つ以上のフィールドで変化していることがわかりました。一部は10、23、あるいは47のフィールドで変化していました。私たちは、顧客が必要なツールを適切に使用できるようにしたいと考えていますが、それがあまりにも無駄なキャッシュを作成するほどにならないようにしたいと考えています。一部の高カーディナリティのバリエーションは意図的です。CDNやリバースプロキシは、コンテンツを予測可能にパーティション化するために、地理的領域などの値を注入する場合があります。これは、可能な値が制御されており、すべてのコンポーネントがその意味に同意する場合に機能します。それらの制約がない場合、キャッシュは再利用されない可能性のあるバリアントに断片化します。 それが、私たちがVaryをサポートするために解決する必要があった設計上の問題でした。私たちは、正しいレスポンスを提供するために十分なバリエーションを維持する必要がありましたが、リクエスト間の偶発的な違いがキャッシュ効率を破壊することを許容しないようにする必要がありました。 Cache RulesがVaryを制御する方法 Cloudflareの顧客は、すでにVaryに似たネゴシエートされたコンテンツを処理するためのいくつかの方法を持っていました。キャッシュをバイパスしてオリジンに処理させる、カスタムキャッシュキーまたは他のルールでオリジンのネゴシエーションロジックを再現する、Workerを使用する、または画像用のVaryのような機能を使用することができます。これらのオプションは依然として有用ですが、キャッシュを諦めるか、アプリケーションロジックを複製するか、追加コードを書く必要があるか、またはより狭いユースケースに対処するかのいずれかです。Cache RulesのVaryは、サポートを2つの決定に分割することで、これらの既存の機能の間のギャップを埋める可能性があります。 オリジンはVaryを使用して、レスポンスに影響を与える可能性のあるリクエストヘッダーを識別します。 Cache Ruleは、Cloudflareが各ヘッダーの値をどのように処理するかを決定します。 A Cache Ruleは、すべてのレスポンスにバリエーションを強制するわけではありません。オリジンがVaryを返さない場合、Cloudflareは通常通りレスポンスをキャッシュしますが、ルールはオリジンにリクエストを転送する前にAcceptおよびAccept-Languageを書き換える可能性があります。オリジンがVaryを返す場合、Cloudflareは各ヘッダーに対して設定されたアクションを使用します。個別の設定がないヘッダーは、ルールのデフォルトアクションを使用します。利用可能な3つのアクションは次のとおりです。 アクション Cloudflareが行うこと 最適な用途 正規化 同等のリクエストがキャッシュされたレスポンスを共有できるように、キャッシュされたバリアントを選択する前にリクエストヘッダーを正規化します。Accept、Accept-Language、およびAccept-Encodingにヘッダー固有のルールを適用します。他のヘッダーについては、オプションの空白をトリミングし、元の順序で繰り返しヘッダー行を結合し、大文字小文字と内部の空白を保持します。 レスポンスのセットが小さいセットにマッピングされる多くのリクエスト値を持つネゴシエーションヘッダーの推奨開始点。 パススルー キャッシュマッチングのためにリクエストヘッダーの生のバイトを使用し、大文字小文字、空白、順序、および重複する値を保持します。ヘッダーが複数の行に表示される場合、Cloudflareはキャッシュマッチングのためにそれらの行をカンマで結合して結合します。パススルーは、送信ヘッダー行を変更しません。Respect Strong ETagsが無効になっている場合、CloudflareはAccept-Encodingを書き換えることができます。 値の正確な値がレスポンスを変更する場合、値のセットが制御されているヘッダー。 バイパス オリジンがそのヘッダーをVaryで指定した場合、レスポンスを保存しません。既存のキャッシュエントリは削除されないため、クリアする必要がある場合はパージしてください。 CookieまたはUser-Agentのような、パーソナル、高カーディナリティ、または予期しないヘッダーに使用します。 デフォルトとして正規化を推奨します。個人または無制限の値を持つ個々のヘッダーには、バイパスを使用します。正確な値がレスポンスを変更する場合は、パススルーを使用します。 例えば、パススルーは