たまごかける日報

ここにAA貼りたい

varnishのTransfer-Encodingとのお付き合い的なナニカ

これはVarnish Cache Advent Calendar 2015の21日目の記事です。
ナンカ書こう、と軽い気持ちで参加したらいつの間にか当日になっていました。

何を書くか直前まで迷っていたのですが、最近varnishのAccept-Encodingの扱いでチョト困ったのでその備忘録的なことを書きます。versionは4.1.0-1です。

TL;DR

  • vcl_recvでpipe,passを使っている場合を除き、varnishはdefaultでbackendにAccept-Encoding:gzipを投げる。
    • なんなら、Accept-Encoding:kakeruとか適当にリクエストを投げても、Accept-Encoding:gzipで上書きしてbackendに投げてくれる
  • 奇特な理由があってgzipをoffりたい場合は以下どれかの対応で逃げられる。
    • 起動オプションで、-p http_gzip_support=false
    • vcl_backend_fetchでunset bereq.http.Accept-Encoding;
    • vcl_backend_responseでset beresp.do_gunzip = true;

現象

会社の画像配信基盤のcache層としてvarnishを使わせてもらってるのですが、
とある日にjson fileやcssや画像を配信しているごった煮Backendのみvarnishにcacheさせていなかった所を、他の画像が乗っているbackend達と同様にcacheさせるように変更を行いました。 後日そこの特定Backendへの一部リクエストでエラーがちょろちょろ出るようになっていたので、そこを調べていったよという話。

config変更はこんな感じ

急に出てきたエラーとしては、アプリがTransfer-Encoding: chunkedに対応してないよという感じのエラー。

原因

先に原因を書いてしまうと、以下になる

  • varnishはdefaultでbackendにAccept-Encoding:gzip を送りつけるが、今までpassで設定していたため付与されていなかった。
  • passを外してcachesさせるようにしたので、Accept-Encoding:gzip を付けて対象のbackendへのリクエストを生成するようになった。
  • その対象backendのみ Accept-Encoding:gzip を解釈出来たため、chunked responseを返しアプリであぼんしてしまった。

調査過程

恥ずかしい話、varnishがdefaultでAccept-Encoding:gzip を送りつけるのを把握していなかったので、 誰がAccept-Encoding:gzip を送りつけ始めたのかを調べるところから始まった。

調査方法はみんな大好きtcpdump

passを抜いたことが明らかに原因だったので、
今回はその前後のconfigでの動作の差異を調べる。

ので、varnishが付与してると断定。varnishのgzip回避の設定を調べることに。

ちなみに、
Headerを見たいだけならvarnishlogでも可能。

こっちの方が簡単ですね。

対応

今回の対象backendのみcssjsonなどの圧縮の恩恵を預かりやすいfileの配信を行っているbackendだったが、画像配信基盤全体としての配信内容はほぼほぼ画像コンテンツだったということもあり、画像にgzipは無意味ということでvarnishとしてgzipをサポートしなくても良いかなという結論に至った。

上記を踏まえた対応方法としては以下の3つぐらいかな。

  • varnishのgzipサポートをそもそも切る
    • varnishdの設定で、-p http_gzip_support=false にする
  • varnishがbackendにAccept-Encoding:gzipを送らないようにする
    • vcl_backend_fetchでunset bereq.http.Accept-Encoding;の記述を追加
  • gzipでbackendからgetしてきたコンテンツを解凍してキャッシュとして保存する
    • vcl_backend_responseでset beresp.do_gunzip = true;の記述を追加

今回は vcl_backend_fetchでunset bereq.http.Accept-Encoding;を追加して対応した。
ちなみに、 do_gunzipは本家でも、なんでそんな事すんの?と書かれるぐらいなので、流石にやらなかった。明らかにナンカ無駄感ありますしね。。

http_gzip_supportをoffに関しては、結局はAccept-Encoding:gzipをbackendに送らないようにするだけなので、そっちでもよかったかも

おまけ

varnishはgzip supportをしている & pipe or passを使っていない場合、
どんなリクエストが来てもAccept-Encodingの中身をgzipで上書きしてリクエストを処理するらしい。

されてた。
Accept-Encoding:kakeruとかのアホなリクエストを投げてもちゃんと上書きされてた。
なるほどです。

といった

ただの備忘録ですが、
こんなアホみたいな所で困ってる人の役に立てれば幸いです

おしまい

参考document
https://www.varnish-cache.org/docs/trunk/users-guide/compression.html
https://www.varnish-cache.org/docs/trunk/reference/varnishd.html#varnishd-1
https://www.varnish-cache.org/docs/trunk/phk/gzip.html