ブラウザはそれぞれ、どういったキャッシュ方式をサポートしているかサーバーに情報を送信します。モダンなブラウザの全ては”gzip”圧縮に対応しているが、それぞれ違った手法で対応しているという情報をサーバーに送るのです。
例えば、モダンなブラウザのヘッダは受け入れられるエンコーディング方式の種類を次のように報告します:
Firefox,IE: gzip, deflate
Chrome: gzip, deflate, sdch
Opera: deflate, gzip, x-gzip, identity, *;q=0
ブラウザから送信されたヘッダに加えて、Varnishはアパッチから送信されるヘッダにも注意せねばならず、通常次のような行が含まれます:
Vary: Accept-Encoding
これはつまり、Varnishは異なるブラウザから送られるそれぞれの”Accept-Encoding”のバージョンに応じて異なるキャッシュを保存する事を意味しています。即ち、それぞれのブラウザに応じて別々のキャッシュ・コピーを保持する事になるのであり、場合によっては同じブラウザに於いても違ったバージョンを保持する事になります。どのブラウザも”gzip”に対応していながら異なる方法で情報を送信しているだけであるので、これは容量の多大な無駄遣いです。こうした混乱を防止し、キャッシュの効率化を図る為、vcl_recvに次のスニペットを挿入します。
[[[# Handle compression correctly. Different browsers send different # "Accept-Encoding" headers, even though they mostly all support the same # compression mechanisms. By consolidating these compression headers into # a consistent format, we can reduce the size of the cache and get more # hits. if (req.http.Accept-Encoding) { if (req.url ~ "\.(ts|bootstrap)$" || req.url ~ "(\wSeg[0-9]*-Frag[0-9]*)"){ # No point in compressing these remove req.http.Accept-Encoding; } elsif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate" && req.http.user-agent !~ "MSIE") { set req.http.Accept-Encoding = "deflate"; } else { # unkown algorithm remove req.http.Accept-Encoding; } } ## if it passes all these tests, do a lookup anyway; return(lookup);
vcl_fetch:
次のスニペットは、vcl_fetchのサブルーチンを定義するものです。
## Called when the requested object has been retrieved from the backend, or the request to the backend has failed sub vcl_fetch { # fail-over to the next server when we receive a 503. # CUSTOMIZE the value of "503" for your deployment. # It should be the same as the unavailable Response code # set in httpd.conf at the server if (beresp.status == 503) { # CUSTOMIZE the value "1" for your deployment. # It should be the number of packagers - 1. if(req.restarts < 1) { return (restart); } else { # all servers failed, generate a cache-able 404 error. # NOTE: we have chosen not to use the varnish # "error" mechanism to generate our # error since those errors are not cached by varnish. # instead, we will transform our 503 error into a 404 error. set beresp.status = 404; set beresp.response = "Not found."; # CUSTOMIZE ttl to be 1/2 a fragment interval. set beresp.ttl = 2s; # CUSTOMIZE Cache-Control to be 1/2 a fragment interval. set beresp.http.Cache-Control = "maxage=2"; unset beresp.http.expires; } } # If the backend is unreachable, hold content for 10 mins set beresp.grace = 600s; if (req.backend.healthy) { # Blanket cache everything for 1 fragment interval. # CUSTOMIZE the value "4" for your deployment as the configured # fragment duration. set beresp.ttl = 4s; } else { # The backend is sick set ttl to 10 mins to serve stale content set beresp.ttl = 600s; } ## Do not cache 50x errors if (beresp.status >= 500) { set beresp.ttl = 0s; } set beresp.http.X-Cacheable = "YES"; return(deliver); }]]]
様々なファイルの種類に応じてTTL(Time To Live)値を設定する事の他に、更に2つここで紹介すべき機能が残っています。: リスタートとデリバーです。
vcl_fetchではデリバーを返す事で、もし可能な場合、Varnishにキャッシュを行うように指示できます。先のVCL機能(例: vcl_recv)で要求をパスする事を選んだ場合、vcl_fectのロジックはそのまま実行されるがたとえキャッシュ・タイムを入力した場合でもオブジェクトはキャッシュに入りません。
リスタートを返すと、リスタートのカウンターを1だけインクリメントしてVCL処理をvcl_recvの冒頭部分から再度繰り返します。
vcl_fetch では、503フェイルオーバーソリューションを実装します。
503フェイルオーバーは単純なフェイルオーバーのソリューションを提供するプロキシ構成技術です。この技術は次のように動作します。
更に、beresp.ttlはどのくらいの期間オブジェクトが保持されるか、beresp.graceは {{beresp.ttl }}時間からどれくらい経過するまでオブジェクトを保持するかをそれぞれ定義するものです。
注意: 細粒度のキャッシュ制御を行う為、アドビはアセットやストリームの種類に応じて異なるTTLを推奨している。TTL要件の記事の”アセット毎のキャッシュ要件”を参照。また、添付したサンプル・コードはvcl_fetch関数にTTL値の構成を行うコメント化された部分があります。
vcl_error、vcl_deliver、vcl_hitとvcl_missはデフォルトのvclファイルから手を加えず、原型のまま追加されたものです。
vcl_hit はキャッシュでオブジェクトが見つかった(ヒットした)直後に呼び出される。TTLの変更、またはパージの発行もここでできます。
vcl_missは、検索されたオブジェクトがキャッシュで発見されなかった直後に呼び出されます。
vcl_deliver は(vcl_pipeを除く)全てのコード・パスに共通な最後の出口点です。
vcl_errorは、ウェブサーバーに問い合わせずVarnishの内部からコンテンツを生成するのに使用されます。しばしばデバッグ・ヘッダを追加または除去するのに利用されます。
[[[## If no packager contains sub vcl_error { # Add your logic here } ## Called when an object is in the cache, its a hit. sub vcl_hit { if (obj.ttl == 0s) { return(pass); } return(deliver); } ## Called when the requested object was not found in the cache sub vcl_miss { # Add your logic here } ## Called before a cached object is delivered to the client sub vcl_deliver { set resp.http.X-Served-By = server.hostname; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; set resp.http.X-Cache-Hits = obj.hits; } else { set resp.http.X-Cache = "MISS"; } return(deliver); }]]]