Varnishはバックエンドが複数ある場合、そのうちひとつが死んでも残りのバックエンドを使うfailover機能がありますが
バックエンドに画像が何もなかったときはどうなるでしょうか?通常の場合はそのまま404を返します。
しかし、画像が投稿されてから非同期でサムネを作成したり、何らかの画像処理を行ったりで一時的にデフォルトの画像を出したいことがあります。
いわばファイル版のfailoverみたいなもんですね。方法がありますので書いてみます。
通常varnishがファイルに対して存在するかしないかを判定できるのはvcl_fetchですが
その段階からこのファイルをもう一回リクエストして!みたいなことはできません。
そこで利用するのがrestartです。
これを使うとvcl_pass,miss,hit,fetch,deliver,errorから再度vcl_recvへ処理を戻すことができます。
その際にreq.restrtsというカウンタが増えていきパラメータのmax_restarts(デフォルト4)を超えるとVarnishがエラーを返します。
これを上手く使うと404のときにデフォルトの画像を指定できます。
以下に例のVCLを記述します。
例1
sub vcl_fetch { if(beresp.status == 404 && req.restarts == 0){ return(restart); } } sub vcl_miss{ if(req.restarts == 1){ set bereq.url = "/noimage.jpg"; } }
例2
sub vcl_fetch { if(beresp.status == 404 && req.restarts == 0){ return(restart); } } sub vcl_recv{ if(req.restarts == 1){ set req.url = "/noimage.jpg"; } }
例1の場合URL毎にNOIMAGEの画像をキャッシュしますがそのURLへはキャッシュが有効な期間はバックエンドに問い合わせはしません。
例2の場合NOIMAGEの画像は複数キャッシュしませんが、そのURLに対しては毎回バックエンドに問い合わせを行います。
ちなみに値の引継ぎも可能なのでこのような記述も可能です。
sub vcl_fetch { if(beresp.status == 404 && req.restarts == 0){ set req.url = "/noimage.jpg"; return(restart); } }
一つ注意としてbereq.*のようにvcl_recv通過後req.*などから生成されるような値は当然上書きされるので注意が必要です。
ちなみに以下のようにすればオリジナルのURLもvcl_recvで処理できます。
sub vcl_fetch { if(beresp.status == 404 && req.restarts == 0){ set req.http.X-RESTART-ORIGIN = req.url; set req.url = "/noimage.jpg"; return(restart); } }
便利だと思うのでぜひ活用してみてください。
—
そういえばちょい前に言ってました夏コミにVarnishの薄い本だすぞーな件ですが、見事にサークル落ちしました。はい。
ただ委託してくださるところが見つかったので鋭意製作中です。
委託先は
京大マイコンクラブ 2日目 東地区 X-45a
です。
でも現在進行形でミスを直したり、勘違いしてるところ直したりとかかなり半泣き状態で書いてるので落ちる可能性も・・・
落ちてもぜひKMCさんのブースは立ち寄ってみてください><