昨年末からWordPressをVarnish+Nginx+PHP-FPMの環境で動作させるためのコラムを始めましたが、今回はVarnishのキャッシュの設定についてです。例によってUbuntu12.04にパッケージからインストールしたという前提で話をすすめます。
VarnishはVCLという独自の言語(概要はこちら)によって設定します。ちなみに”VCL”は文字通り”Varnish Configuration Language”の略です。
/etc/varnish/default.vclを覗いてみるとコメントアウトされたvcl_XXXXという名前のサブルーチンが並んでいるのが確認できます。この関数内にVarnishの各処理地点で実行させたい処理を記述します。このサブルーチンのうちほとんどの場合、vcl_recvもしくはvcl_fetchを編集することになります。
またそれぞれのサブルーチンで実行できる処理(action)が決まっていて”return(action)”の形で呼び出します。
(1) 主なフックとアクション
vcl_recv | リクエストを受け取ったときの処理
action: pass, pipe, lookup, error code |
---|---|
vcl_fetch | レスポンスをバックエンドサーバーから取り出したときの処理
action: deliver, hit_for_pass, restart, error code |
(2) vcl_recvの編集
WordPressの管理画面へのアクセスと管理画面へログインした状態(Cookieにwordpress_logged_in_XXXXという名前の変数がセットされている)でのアクセスはそのままバックエンドサーバーにリクエストを送ります。管理画面での編集やプレビューの場合キャッシュが邪魔するのを防ぐためです。
それ以外の場合はCookieヘッダを削除してキャッシュを利用するという処理を追加します。Cookieヘッダを削除するのはキャッシュのヒット率を上げるためです。
なお2〜9行のコメントを外しているのはNginx側でVarnishの稼動しているホストのIPではなく、クライアントのIPをNginxに伝えるための記述です。Nginx側でもこれを拾うための設定を記述する必要があります。(最後の補足を参照)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
sub vcl_recv { if (req.restarts == 0) { if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } } # # if (req.request != "GET" && # req.request != "HEAD" && # req.request != "PUT" && # req.request != "POST" && # req.request != "TRACE" && # req.request != "OPTIONS" && # req.request != "DELETE") { # /* Non-RFC2616 or CONNECT which is weird. */ # return (pipe); # } # if (req.request != "GET" && req.request != "HEAD") { # /* We only deal with GET and HEAD by default */ # return (pass); # } # if (req.http.Authorization || req.http.Cookie) { # /* Not cacheable by default */ # return (pass); # } if(req.url ~ "wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_") { return (pass); } unset req.http.Cookie; return (lookup); } |
(3) vcl_fetchの編集
クライアントへのレスポンスにキャッシュを利用する処理を追加(アンコメント)します。
1 2 3 4 5 6 7 8 9 10 11 12 |
sub vcl_fetch { # if (beresp.ttl <= 0s || # beresp.http.Set-Cookie || # beresp.http.Vary == "*") { # /* # * Mark as "Hit-For-Pass" for the next 2 minutes # */ # set beresp.ttl = 120 s; # return (hit_for_pass); # } return (deliver); } |
(4) Apache Bench
ここまでの設定をしてApache benchを実行してRequests per secondを変更前と比較すると50〜100倍程度のリクエストを処理できています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.atage.jp (be patient) Completed 5000 requests Finished 8331 requests Server Software: nginx/1.1.19 Server Hostname: www.atage.jp Server Port: 80 Document Path: / Document Length: 19821 bytes Concurrency Level: 10 Time taken for tests: 60.002 seconds Complete requests: 8331 Failed requests: 0 Write errors: 0 Total transferred: 169205729 bytes HTML transferred: 165197367 bytes Requests per second: 138.85 [#/sec] (mean) Time per request: 72.022 [ms] (mean) Time per request: 7.202 [ms] (mean, across all concurrent requests) Transfer rate: 2753.92 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 5 29 124.2 10 1321 Processing: 10 43 91.9 18 1630 Waiting: 5 14 41.7 9 1332 Total: 17 72 156.6 29 2031 Percentage of the requests served within a certain time (ms) 50% 29 66% 34 75% 37 80% 40 90% 232 95% 329 98% 567 99% 1024 100% 2031 (longest request) |
補足:NginxでクライアントのIPを拾う設定
Nginxの設定ファイルに以下の2行を追加。
1 2 3 4 5 6 7 8 |
server { #listen 80; ## listen for ipv4; this line is default and implied #listen [::]:80 default ipv6only=on; ## listen for ipv6 listen 8080; set_real_ip_from 127.0.0.1; real_ip_header X-Forwarded-For; (略) |