Varnishの圧縮転送について調べた

varnish-logoVarnish 3.0 系列ではパイプラインのどこでオブジェクトが圧縮されるのか確認した。
基本的に次のオフィシャルドキュメントの ESI 以外の箇所を読みながら動作確認しただけ。

How GZIP, and GZIP+ESI works in Varnish
https://www.varnish-cache.org/docs/trunk/phk/gzip.html

まとめ

3行でまとめると

  • Varnish の圧縮は gzip のみに対応。
  • オリジンサーバにはリクエストヘッダーを Accept-Encoding:gzip に書き換えてコンテンツを要求し、できる限り gzip 化してキャッシュする。
  • クライアントの gzip 対応に応じて gzip のまま、または gunzip してコンテンツ配信する。

リクエストの流れ

vagrant-sequence

1. Send a Request

Client が Varnish にコンテンツをリクエスト。

2. Send the Request

varnish はリクエストされたコンテンツがキャッシュされていなければ、オリジンサーバにリクエスト。
ポイントになるのはリクエストヘッダーの "Accept-Encoding"
#1 のクライアントの Accept-Encoding によらず、オリジンサーバには "Accept-Encoding: gzip" に書き換えてリクエストする。

3. Send the Response

nginx はリクエストされたコンテンツの MIME タイプが gzip_types で指定したものに一致する場合、 gzip 圧縮して転送する。

4. Store Objects

VCL(Varnish Configuratin Language) ファイルの vcl_fetch ではオリジンサーバのレスポンスに対して明示的に gzip/gunzip してキャッシュ化することができる。
beresp.do_gzip が true になっていると、バックエンドサーバが gzip しなかったコンテンツを明示的に gzip しキャッシュ化する。
beresp.do_gunzip が true になっていると、バックエンドサーバが gzip したコンテンツを明示的に gunzip しキャッシュ化する。(機能としては提供されているが、Varnish のメモリ使用量が増える上、クライアントへのレスポンス時にも gzip エンコーディングされなくなるのでメリットなし。公式ドキュメントにも “I have no idea why/when you would use this…” と書かれている)

do_gzip/do_gunzip のコントロールがなければ、nginx のレスポンスオブジェクトのエンコーディングでキャッシュ化される

sub vcl_fetch {
     if (req.url ~ "gzip.txt") {
         set beresp.do_gzip = true;
     }
     elseif (req.url ~ "plain.txt") {
         set beresp.do_gzip = false;
     }
     elseif (req.url ~ "gunzip") {
         set beresp.do_gunzip = true;
     }
     return (deliver);
}

このような設定があった場合、オリジンサーバから取得した

  • gzip.txt が gzip されていなければ gzip してキャッシュ化され
  • plain.txt が gzip されていなければそのままキャッシュ化され
  • gunzip.html が gzip されていれば、 gunzip してキャッシュ化される。

5. Send the Response

Varnish がクライアントにコンテンツを返す。
#1 のリクエスト時の Accept-Encoding に gzip が含まれており、gzip 化してキャッシュ化されていれば、gzip 転送する。
#1 のリクエスト時の Accept-Encoding に gzip が含まれておらず、gzip 化してキャッシュ化されていれば、キャッシュオブジェクトを gunzip 後に転送する。(API サーバの前に Varnish がたっている場合に多そう)
上記以外のケースでは、エンコードせずに転送する。

実際の動作を確認

検証用構成は client <—> varnish(port:80) <—> nginx(port:8080)
リクエストヘッダーやリクエストコンテンツを変えながら、Varnish と nginx のリクエスト/レスポンスを確認

nginx の設定

nginx は htmlファイルのみ gzip 圧縮するように設定(nginx.conf の gzip_types には特に指定せず、デフォルトの text/html のみ圧縮されるようにする)

リクエストヘッダーの Accept-Encoding、レスポンスヘッダーの Content-Encoding, Content-Type などをログ出力させる

log_format gzip '$remote_addr - $remote_user [$time_local]  '
                '"$sent_http_content_type" '
                '"$sent_http_content_encoding" '
                '"$http_accept_encoding" '
                '"$http_user_agent"';
access_log /var/log/nginx/access.log gzip;

nginx が gzip するコンテンツ(text/html)

nginx には “Accept-Encoding: gzip” でリクエスト
text/html なので nginx は gzip 化
クライアントが gzip 対応の場合のみ gzip で返す

・リクエスト時に Accept-Encoding を指定せず

$ lwp-request -m HEAD http://localhost/gzip.html
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:47:30 GMT
Via: 1.1 varnish
Age: 0
Content-Type: text/html
Last-Modified: Mon, 07 Oct 2013 19:54:17 GMT
Client-Date: Wed, 09 Oct 2013 14:47:30 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690066

・リクエスト時に Accept-Encoding に gzip を指定

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip' http://localhost/gzip.html
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:47:33 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 3
Content-Encoding: gzip
Content-Length: 760103
Content-Type: text/html
Last-Modified: Mon, 07 Oct 2013 19:54:17 GMT
Client-Date: Wed, 09 Oct 2013 14:47:33 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690067 1901690066

・nginx ログ

127.0.0.1 - - [09/Oct/2013:14:47:30 +0000]  "GET /gzip.html HTTP/1.1" 200 760533 "text/html" "gzip" "gzip" "lwp-request/6.03 libwww-perl/6.03"

nginx が gzip しないコンテンツ(text/plain)

nginx には “Accept-Encoding: gzip” でリクエスト
text/plain なので nginx は gzip 化せず
キャッシュ時に gzip 化されないので、クライアントにもエンコードせずにかえす

$ lwp-request -m HEAD http://localhost/test.txt                200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:52:40 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 0
Content-Length: 5430
Content-Type: text/plain
Last-Modified: Wed, 09 Oct 2013 14:50:49 GMT
Client-Date: Wed, 09 Oct 2013 14:52:40 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690070

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip' http://localhost/test.txt
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:52:42 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 2
Content-Length: 5430
Content-Type: text/plain
Last-Modified: Wed, 09 Oct 2013 14:50:49 GMT
Client-Date: Wed, 09 Oct 2013 14:52:42 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690071 1901690070

・nginx ログ

127.0.0.1 - - [09/Oct/2013:14:52:40 +0000]  "GET /test.txt HTTP/1.1" 200 5648 "text/plain" "-" "gzip" "lwp-request/6.03 libwww-perl/6.03"

vcl_fetch で明示的に gzip/gunzip するケース

/etc/varnish/default.vcl 内の vcl_fetch の設定

sub vcl_fetch {
     if (req.url ~ "gzip.txt") {
         set beresp.do_gzip = true;
     }
     elseif (req.url ~ "plain.txt") {
         set beresp.do_gzip = false;
     }
     elseif (req.url ~ "gunzip") {
         set beresp.do_gunzip = true;
     }
     return (deliver);
}

nginx には “Accept-Encoding: gzip” でリクエスト(ここは同じ)
nginx は text/html の場合は gzip, text/plain はそのまま返す

~ "gzip.txt" のルールにマッチするので beresp.do_gzip = true となり、gzip 化される

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip' http://localhost/gzip.txt
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:54:46 GMT
Via: 1.1 varnish
Age: 0
Content-Encoding: gzip
Content-Type: text/plain
Last-Modified: Mon, 07 Oct 2013 19:52:32 GMT
Client-Date: Wed, 09 Oct 2013 14:54:46 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690072

nginx のログ

127.0.0.1 - - [09/Oct/2013:14:54:46 +0000]  "GET /gzip.txt HTTP/1.1" 200 1573371 "text/plain" "-" "gzip" "lwp-request/6.03 libwww-perl/6.03"

~ "plain.txt" のルールにマッチするので beresp.do_gzip = false となり、gzip 化されない

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip' http://localhost/plain.txt
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:54:50 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 0
Content-Length: 1573150
Content-Type: text/plain
Last-Modified: Mon, 07 Oct 2013 19:52:34 GMT
Client-Date: Wed, 09 Oct 2013 14:54:50 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690073

nginx のログ

127.0.0.1 - - [09/Oct/2013:14:54:50 +0000]  "GET /plain.txt HTTP/1.1" 200 1573371 "text/plain" "-" "gzip" "lwp-request/6.03 libwww-perl/6.03"

~ "gunzip"のルールにマッチするので beresp.do_gunzip = true となり、nginx が gzip でかえしているのにキャッシュ前に gunzip される。

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip' http://localhost/gunzip.html
200 OK
Connection: close
Date: Wed, 09 Oct 2013 14:54:56 GMT
Via: 1.1 varnish
Age: 0
Content-Type: text/html
Last-Modified: Mon, 07 Oct 2013 20:30:34 GMT
Client-Date: Wed, 09 Oct 2013 14:54:56 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690074

nginx のログ

127.0.0.1 - - [09/Oct/2013:14:54:56 +0000]  "GET /gunzip.html HTTP/1.1" 200 760533 "text/html" "gzip" "gzip" "lwp-request/6.03 libwww-perl/6.03"

http_gzip_support が off のときは?

これまで見てきたのはフラグ http_gzip_support が on(デフォルト)の時の挙動。
このフラグが有効になっているときは、Accept-Encoding を書き換えてオリジンサーバに gzip を要求する。
宗教上その他の理由により、このフラグを off にすることもできる。

このフラグが off の時は、クライアントの Accept-Encoding は書き換えずにそのままバックエンドサーバに渡す。

・クライアントがgzip,deflate の場合

$ lwp-request -m HEAD -H 'Accept-Encoding: gzip,deflate' http://localhost/test.html
200 OK
Connection: close
Date: Wed, 09 Oct 2013 15:05:23 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 0
Content-Encoding: gzip
Content-Length: 1092
Content-Type: text/html
Last-Modified: Wed, 09 Oct 2013 15:04:40 GMT
Client-Date: Wed, 09 Oct 2013 15:05:23 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690075

nginx にも gzip,deflate で要求

127.0.0.1 - - [09/Oct/2013:15:05:23 +0000]  "GET /test.html HTTP/1.1" 200 1329 "text/html" "gzip" "gzip,deflate" "lwp-request/6.03 libwww-perl/6.03"

クライアントが deflate のみの場合

$ lwp-request -m HEAD -H 'Accept-Encoding: deflate' http://localhost/test.txt
200 OK
Connection: close
Date: Wed, 09 Oct 2013 15:07:43 GMT
Via: 1.1 varnish
Accept-Ranges: bytes
Age: 0
Content-Length: 5430
Content-Type: text/plain
Last-Modified: Wed, 09 Oct 2013 14:50:49 GMT
Client-Date: Wed, 09 Oct 2013 15:07:43 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
X-Varnish: 1901690077

nginx にも deflate だけで要求

127.0.0.1 - - [09/Oct/2013:15:07:43 +0000]  "GET /test.txt HTTP/1.1" 200 5648 "text/plain" "-" "deflate" "lwp-request/6.03 libwww-perl/6.03"

http_gzip_support の設定変更

設定の確認

現在のフラグを確認するには CLI varnishadm を利用

$ sudo varnishadm param.show http_gzip_support
http_gzip_support           on [bool]
                            Default is on
                            Enable gzip support. When enabled Varnish will
                            compress uncompressed objects before they are
                            stored in the cache. If a client does not support
                            gzip encoding Varnish will uncompress compressed
                            objects on demand. Varnish will also rewrite the
                            Accept-Encoding header of clients indicating
                            support for gzip to:
                            Accept-Encoding: gzip

                            Clients that do not support gzip will have their
                            Accept-Encoding header removed. For more
                            information on how gzip is implemented please see
                            the chapter on gzip in the Varnish reference.

                            NB: We do not know yet if it is a good idea to
                            change this parameter, or if the default value is
                            even sensible.  Caution is advised, and feedback
                            is most welcome.

設定変更

検証目的で一時的にフラグを変える場合、 CLI(varnishadm) からやると簡単

$ sudo varnishadm param.set http_gzip_support off

起動時に指定する場合は /etc/default/varnish-p http_gzip_support=false を追加する。

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -p http_gzip_support=false \
             -s malloc,8m"

varnish の gzip/gunzip 操作の統計情報を取得

varnishstat コマンドを利用すると Varnish の gzip/gunzip の実行回数がわかる。

$ sudo varnishstat -f n_gzip,n_gunzip
0+00:25:32
Hitrate ratio:        1        1        1
Hitrate avg:     0.2500   0.2500   0.2500

           1         0.00         0.00 n_gzip - Gzip operations
           3         0.00         0.00 n_gunzip - Gunzip operations
Advertisements
Tagged with: , , , , ,
Posted in middleware

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 4 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 5 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 5 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 10 months ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: