圧縮技術 · 1 min read · Sep 15, 2025
mod_gzip - Apacheウェブサーバーによる圧縮コンテンツの提供 - ページ9
著者: マイケル・シュレプル
交渉による圧縮
mod_gzipのような設定可能な圧縮機能を使用することは、最終的には常に何らかのコンテンツ交渉である必要があります。つまり、HTTPヘッダー内の特定の情報に応じて、同じ要求されたURLに対して条件付きで異なるコンテンツを提供することです。
一方で、HTTPは、特にプロキシサーバーを使用する場合に、HTTPリクエストに対する応答をキャッシュに一時保存することを許可します。もし今、
- HTTPクライアントがリクエストを送信し、
- 対応する応答が圧縮形式で提供され、いくつかのプロキシによって保存され、
- その後、別のHTTPクライアントが問題のURLに対してリクエストを送信した場合、
そのプロキシサーバーは、さらなる情報を持っていないため、問題を抱えます:
- この2番目のHTTPクライアントにもキャッシュされたコンテンツを提供する権利があるのか、または
- リクエストをHTTPサーバーに転送しなければならないのか?
最終的には、HTTPサーバーのみが(対応するフィルタールールを含む設定に基づいて)2番目のHTTPクライアントが圧縮応答データを受け取ることができるかどうかを判断できます。
ちなみに、これは単に圧縮手順を使用することによる効果ではなく、プロキシサーバーのキャッシュ内のURLによって明確に指定できないコンテンツのHTTPデータのキャッシングに関する一般的な問題です。これには、あらゆる種類の交渉手続きや、認証データやクッキーのようなHTTPヘッダー内の追加情報の提出が含まれます。
パフォーマンス要件
もちろん、クライアントとサーバーの間に存在するすべてのプロキシサーバーに対して、対応するHTTPヘッダーExpires:およびPragma:(HTTP/1.0)やCache-Control:(HTTP/1.1)を使用して、対応する応答データのキャッシュを明示的に拒否することで問題を回避しようとすることができます。
しかし、圧縮の目的はデータ転送を加速すること(データ量を削減すること)であり、データをキャッシュすることも同じ目的に役立ちます(HTTPサーバーへのアクセスを減らすこと)。したがって、一つのパフォーマンス最適化が、もう一つの最適化がもはや使用できなくなることにつながるべきではありません。特に、これら二つは互いに置き換えるのではなく、問題において効果的に補完し合うことができます。
交渉パラメータに関する情報
HTTP仕様には、HTTPサーバーがプロキシサーバーに対して次のことを通知できるVary HTTPヘッダーの定義が含まれています:
- 応答がURLリクエストの唯一の結果であったかどうか、または
- 同じURLに対するリクエストの他の属性が異なる結果をもたらす可能性があるかどうか。
その値には、リクエストに対してこの応答を提供するために関連する他のHTTPヘッダーの名前のリストが含まれる場合があります。したがって、HTTPサーバーは、提供されたコンテンツに関する決定に影響を与えたどのHTTPヘッダーがあったかをプロキシサーバーに通知できます。
プロキシサーバーがHTTPサーバーにリクエストを転送し、後でその応答をキャッシュに保存したい場合、HTTPサーバーの応答が到着する際に、元のリクエストのHTTPヘッダーを保持している必要があります。
さて、HTTPサーバーが応答の条件付きコンテンツを対応するVaryヘッダーでマークすると、
- プロキシサーバーはキャッシュ内にこの応答のコンテンツだけでなく、リクエストからの関連するすべてのHTTPヘッダー情報(Vary HTTPヘッダーの値リストに列挙された名前)を保存しなければならず、
- その後のリクエストに対してこのキャッシュされたコンテンツを応答として提供してはならず、少なくともそのような後続リクエストの対応するHTTPヘッダーの情報が元のリクエストの各ヘッダーの値と意味的に同一であることが必要です。
HTTPサーバーに対する制限
前述の説明は、プロキシサーバーがHTTP応答の条件付き配信(コンテンツ交渉の結果)を正しく処理し、同時にそのキャッシング効果を最大限に活用する方法を示しています - 前提条件として、
- HTTPサーバーがプロキシサーバーに交渉パラメータに関する十分な情報を提供し、
- プロキシサーバーが別のHTTPクライアントによる同じURLへの後続リクエストの場合に対応する情報を保持していること。
しかし、後者は交渉プロセスの自由度に制限をもたらします。プロキシサーバーがHTTPリクエスト内の情報に基づいてのみキャッシュコンテンツを提供できるかどうかを決定しなければならない場合、HTTPサーバーの交渉ルールはHTTPヘッダーの内容以外のものを参照してはなりません!
しかし、残念ながらこの前提条件はmod_gzipによって満たされていません。提供されるフィルタールールの6つのクラスのうち、
- 2つの「合法的」なもの(reqheaderおよびuri)はHTTPヘッダーの内容のみに関係しますが、
- 4つの「違法な」もの(rspheader、handler、fileおよびmime)は、HTTPサーバーによるリクエストの評価中にのみ利用可能な情報を参照します。
したがって、mod_gzipを強化したサーバーがこれらの「違法な」フィルタールールの1つを使用すると、プロキシサーバーはその後のリクエストに応じてキャッシュコンテンツの適用性を正しく判断できなくなります。
これにより、mod_gzipがプロキシサーバーに対して明らかに過負荷であることを通知しても、(Vary:ヘッダー内のこのリクエストに関連するフィルタールールクラスの完全なリストを提供することが合法であったとしても)プロキシサーバーにはあまり役立ちません。プロキシサーバーができることは、これらの4つの「違法な」フィルタールールクラスの1つの発生を基準として、応答の内容をキャッシュしないことだけです。
これだけではそれほど悪くはありません - HTTPサーバーが「合法的」なルールのみを使用する限り、プロキシサーバーと最適に協力できるでしょう。
しかし、残念ながらmod_gzip 1.3.19.1aではそれが不可能です。
mod_gzip 1.3.19.1aをApache 1.3アーキテクチャに組み込むのは比較的複雑な方法で行われます:
- 処理フェーズ1では、mod_gzipはこのリクエストの結果を処理することに興味があるかどうかを確認し、それに備えます - 4つのクラス(reqheader、uri、fileおよびhandler、つまり2つの「合法的」および2つの「違法な」ルールクラス)のルールに基づいて
- 処理フェーズ2では、mod_gzipは実際に(現在利用可能な)応答コンテンツを圧縮すべきかどうかを確認します - 2つのクラス(rspheaderおよびmime、両方とも「違法な」ルールクラス)のルールに基づいて。
圧縮のリクエストを成功裏に許可するためには、少なくともいずれかのフェーズから1つのincludeルールの満たしが必要です(およびすべてのexcludeルールの不満足)。
しかし、フェーズ2の両方のincludeルールクラスは「違法」であるため、現在のmod_gzip実装における成功した圧縮のための関連フィルタールールクラスのリストは、少なくとも1つの「違法な」ルールクラスをカバーしなければなりません。
したがって、プロキシサーバーにキャッシュコンテンツの適用性を判断するために使用できる情報を提供することは不可能です - 提出された情報は常にプロキシサーバーの理解を超えます。
mod_gzip 1.3.19.2a以降のVaryヘッダー
バージョン1.3.19.2a以降、mod_gzipはVary:ヘッダーを送信しています - モジュールが少なくとも1回関与したすべてのリクエストに対して(圧縮データが提供されたかどうかにかかわらず)。
このmod_gzipの研究の状態では、各リクエスト(実際に応答が圧縮形式で提供されたかどうかにかかわらず)は潜在的に交渉です:
- 少なくともAccept-Encoding HTTPヘッダーについて、
- おそらく他のHTTPヘッダーについても(すなわち、reqheaderクラスのフィルタールール内で発生するすべてのもの)
現在、mod_gzipはまだ最適な、すなわち必要なVary:ヘッダーの最小セットを生成することができません - これにはmod_gzipのルール評価手順を完全に書き直す必要があります。
最初のステップとして、モジュールはバージョン1.3.19.2a以降、Vary:ヘッダーを送信し、
- 値Accept-Encodingと
- reqheaderルール内で使用されるすべてのヘッダーの名前を含みます。
これらのルールのそれぞれが交渉の結果に影響を与える可能性があり、これらの各ケースでは結果が受信したHTTPヘッダーの値に依存します。特定のケースでは、これは過剰すぎる場合があり(その場合、コンテンツの効率的なキャッシングを大幅に妨げる可能性があります)、しかし少なくとも何かを始めるためのものです。
この戦略の改善として、mod_gzip 1.3.26.1aは、リクエストの圧縮がmod_gzip_item_excludeルールのために拒否された場合、Vary:ヘッダーを送信しません。
- file、
- uriおよび
- handlerタイプのルール - なぜなら、このルールの評価は受信したHTTPヘッダーに依存していないため、したがってこれらのケースでは実際には交渉が行われていないからです(異なるHTTPリクエストに対して異なる値を含む可能性のある次元について)。
圧縮形式で提供されることが絶対にないファイルに対してVary:ヘッダーを送信しないようにしたい場合は、これらの設定ルールのためにmod_gzipをオフにする必要があります。
プロキシのようなSquid 2.4によってキャッシュされる可能性のあるGIF画像に対してVary:ヘッダーを送信しない例は次のようになります:
mod_gzip_on No
今後のバージョンに向けて、次のタスクが残っています:
- すべての可能なケースで、現在のリクエストに対する反応が圧縮データを提供することが決してないことを認識すること - なぜなら、リクエストの属性とは無関係なmod_gzip_item_excludeルールが発動するからです。
- HTTPヘッダー名のリストで説明できない交渉が行われたことを認識すること - この場合、Vary: *を送信する必要があります(mod_gzipのドキュメントは、これらの指示が絶対に必要な場合にのみ使用されるべきであることを明示的に指摘すべきです。なぜなら、これらを使用するとキャッシングプロキシの作業に悪影響を及ぼすからです)。
- Vary:ヘッダー内でreqheaderルールのすべてのヘッダー名のサブセットのみが必要な構成が可能かどうかを再確認すること - 名前が少ないほど、プロキシキャッシュに並行して保存される必要のあるバリアントが少なくなります。
HTTPヘッダー以外の次元に関する交渉
非常に特別なケース、すなわち特定の設定指示を使用する場合、mod_gzipはHTTPヘッダー名で表現できない次元について交渉を行います。これは、
- mod_gzip_min_http(必要な最小HTTPバージョン)および
- mod_gzip_handle_methods(処理されるHTTPメソッド)
の指示に適用されます。
両方のケースで、mod_gzipはプロキシに対して何が行われたかをHTTPヘッダーの名前を伝えることで説明できません。HTTP/1.1仕様に従った適切な反応は、Vary: * HTTPヘッダーを送信することです。
mod_gzip 1.3.26.1aは、mod_gzip_min_http指示が使用された場合にVary: *ヘッダーを送信します。
mod_gzip_handle_methods指示については、同じURIに対する2つのHTTPリクエストが異なるHTTPメソッドを使用している場合、実際に同じHTTPエンティティを要求しているかどうかはまだ完全には明確ではないようです - これにより、この指示を使用する際にVary: *ヘッダーを送信する必要があるかどうかが決まります。
しかし、この場合、プロキシサーバーは実行された交渉のタイプを理解できないため、キャッシュ内にこのマークを持つ応答を保存する権利はありません。
したがって、これらの指示のいずれかを使用すると、このHTTPサーバーによって送信されるすべての応答のプロキシキャッシングが完全に無効になります。圧縮形式であろうと非圧縮形式であろうと。したがって、これらの指示のいずれかを使用しないことをお勧めします。
特殊ケースとしてのUserAgent
プロキシキャッシュに異なる交渉パラメータのバリアントを並行して保存することは、実際に発生する可能性のある値が少ない場合には合理的かもしれません - たとえばContent-Encodingの場合のように。可能な値が多数ある場合、バリアントの並行保存はもはや実行可能ではありません。
まさにこのことが、HTTPクライアントの識別としてのUserAgent名に当てはまります。各ブラウザのサブバージョンは、ブラウザの名前とバージョンだけでなく、さらなる情報(国の言語、オペレーティングシステムの名前とバージョンなど)を含む複雑なUserAgent文字列を送信します。知られているUserAgent文字列は数百種類あり、さらにこのUserAgent文字列を操作するためのいくつかのメカニズムがあります。一部のブラウザ(Operaなど)は、ユーザーが異なるブラウザとして振る舞うためにこのUserAgent文字列の内容を明示的に選択できるようにしています(なぜなら、多くの技術的に無知なウェブページ作成者がブラウザの名前に基づいてサイトを構築し、不要にいくつかのブラウザを除外するからです。または、単にユーザーが使用しているコンピュータ機器の詳細を不必要に表示したくないため、プライバシーを守るためです)。
HTTPクライアントの識別に基づいて圧縮ウェブページを条件付きで提供することがどれほど合理的であるかは、Netscape 4の多数のバグに関しては依然として疑問ですが、HTTP交渉の基盤としてUserAgent文字列を使用することの欠点は、一方でこのHTTPヘッダーの内容があまりにも変動しすぎて信頼できる結論を引き出すことができず、他方であまりにも多くの異なる値を含んでいるため、キャッシングプロキシがこれらの交渉バリアントのすべてに対して同じURLのリクエスト結果を並行して保持することができないことです。
バージョン1.3.19.2a以降、mod_gzipは、対応する指示が設定内で使用された場合、交渉のパラメータとしてHTTPヘッダーUser-Agent:を説明するVary:ヘッダーを送信しています。しかし、User-Agent:の値が完全に同一である(したがってこのクライアントがすでに保存されたコンテンツを受け取る可能性がある)次のリクエストが含まれる確率は非常に低いです。
実際、HTTPサーバーは、設定に基づいて機能的に同等であると見なされる大規模なUserAgentのセットを交渉中に同一に扱いますが、Vary:ヘッダーはHTTPサーバーがキャッシングプロキシに対して交渉中にHTTPサーバーによって重要なコンテンツとして評価されたUserAgent文字列のどの部分が評価されたかを伝えることを許可しません。プロキシサーバーは、UserAgentが何らかの役割を果たしたことを知ることができます - そしてこれを認識しているため、プロキシは個々のUserAgentsを異なるものとして扱わなければなりません。たとえHTTPサーバーがこのように行動しないとしても。
したがって、UserAgent HTTPヘッダーを評価するフィルタールールを使用すると、このように作成された応答パケットのキャッシングが完全に無効になります。mod_gzipのユーザーはこの効果を絶対に認識しておくべきです - したがって、可能であれば、同じタイプのHTTPクライアント間の差別化を提供するために、他のフィルターメソッド(可能な異なる値の数が少ないもの)を使用することをお勧めします。
この文書の元の場所:
新しい投稿を受信箱で受け取る
スパムはありません。いつでも購読を解除できます。