Varnishに関していろいろ調べて試してみた

1. Varnishとは
---

Varnishはリバースプロキシを提供するためのミドルウェアである。Varnishを導入することで、Readが多いアプリケーションサーバーの前に設置することで、レスポンスの向上や、アプリケーションサーバーの負荷軽減が見込まれる。また、キャッシュの破棄等も明確に設定できるのが嬉しい。

[Varnish](https://www.varnish-cache.org)


2.Varnishサーバーの構築
---

### 2.1.Varnishのインストール

CentOS系のAmazonLinuxを使ってVanish環境を構築してみる

Red Hat Enterprise Linux 6.4 - ami-5769f956 (64-bit) / ami-bb68f8ba (32-bit)
Red Hat Enterprise Linux version 6.4, EBS-boot.

```
$ sudo rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release/varnish-release-3.0-1.el6.noarch.rpm

$ sudo yum install varnish
```
[Varnishインストール手順](https://www.varnish-cache.org/installation/redhat)

### 2.2.転送先ホストの設定

```
$ sudo vim /etc/varnish/default.vcl
```

転送先を例えばyahooに設定してみた例は次の通り

```
backend default {
  .host = "www.yahoo.co.jp";
  .port = "80";
}
```

### 2.3.Varnishのポートの設定

```
$ sudo vim /etc/sysconfig/varnish
```

```
VARNISH_LISTEN_PORT=80
```

### 2.4.サービスの起動

```
$ sudo service varnish start
```

ちなみに、AmazonEC2のRedHatの場合、セキュリティグループを設定しても、自前でiptablesを設定する必要がある

```
$ curl http://localhost:80 (Webブラウザからはアクセス不可だが、サーバー内から可能)
$ sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
$ sudo sudo iptables --list
$ sudo /sbin/service iptable save
```

これで動作する事を確認した。 


3.キャッシュクリアの方法
---

[Cash Invalidation](https://www.varnish-software.com/static/book/Cache_invalidation.html)

Varnishのキャッシュをクリアする方法は次の4つがある

+ ttlの設定時限設定
+ purge オブジェクト１つに対するキャッシュクリア
+ ban 正規表現を使ったキャッシュクリアの予約(SmartBan)
+ set req_hash_always_miss = true あるURLに対するキャッシュのクリア

今回の実験では、キャッシュミスの方法、SmartBan(Banの正規表現)、ttlの時限設定を試してみた。

 結論としては、一括でキャッシュをクリアできるのは、SmartBanのみであり、実施するとすればそれになる。それ以外の可能性だと、ttlの時限設定も良い。元々Varnishのデフォルトでは、キャッシュがクリアされるのが2分の時限設定がもうけられている。2分のタイムラグが許容されるなら、方式がカンタンになるのでよいと思われる。

### 3.1.キャッシュミスの設定

最初にテストした方式は、キャッシュされているオブジェクトをその場でキャッシュクリアする方法である。ただし、この方法では、URLで指定したオブジェクトしか、キャッシュミスにすることができない。

/etc/varnish/default.vcl

```
backend default {
.host = "127.0.0.1";
.port = "80";
}


acl backend_apps { "127.0.0.1";}

sub vcl_recv {
   if (client.ip ~ backend_apps && req.http.X-REFRESH) {
     set req.hash_always_miss = true;
   }
}

```

実行イメージ

※この時は、ローカルのvagrant環境に、CentOS64をぶち込んでテストしています。

```
[vagrant@vagrant-centos64 www]$ cat index.html 
hello 9
[vagrant@vagrant-centos64 www]$ cat test.html 
test 7
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081
hello 8
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081/test.html
test 6
[vagrant@vagrant-centos64 www]$ curl -H 'X-REFRESH: DOIT' http://127.0.0.1:6081/
hello 9
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081
hello 9
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081/test.html
test 6
[vagrant@vagrant-centos64 www]$ curl -H 'X-REFRESH: DOIT' http://127.0.0.1:6081/test.html
test 7
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081
hello 9
[vagrant@vagrant-centos64 www]$ curl http://127.0.0.1:6081/test.html
test 7
```

この方式では今回の要求（サブディレクトリの下を一括してキャッシュクリア）を満たせない。対象の数が少ない場合はこれでもいいかもしれない

### 3.2.SmartBan方式

通常のBANや、Purge、キャッシュミスの方式は、ある特定のオブジェクトに対応するため、一括でキャッシュをクリアしたい用途には向いていない。そのような場合は、Smart Banを用いるのが良い

  BANの方式はキャッシュをすぐにクリアするのではなく、対象のキャッシュをBANにしておき、次にそのURLがリクエストされた際に、バックエンドのサーバーに読みにいくといった挙動をする。
  
#### 3.2.1. SmartBanの設定とテスト

次のファイルをApacheのwwwルートに配置する。そのファイルを取得した後に、キャッシュがかかっているのを確認したのち、キャッシュを破棄するコマンドをhttpで発行する

次のシェルで４つのファイルの取得をVarnishに依頼している

```
#!/bin/bash
curl http://127.0.0.1:6081/index.html
curl http://127.0.0.1:6081/test.html
curl http://127.0.0.1:6081/sub/1.html
curl http://127.0.0.1:6081/sub/2.html
```

最初に、リクエストを送った後に、ファイルをの中身を書き換えるが、キャッシュされて、新しいものに反映されない（これは期待通りの動作）

```
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.6
test.html
ver 1.6
1.html
ver 1.6
2.html
ver 1.6
[vagrant@vagrant-centos64 www]$ sudo vi index.html 
[vagrant@vagrant-centos64 www]$ sudo vi test.html 
[vagrant@vagrant-centos64 www]$ sudo vi sub/1.html 
[vagrant@vagrant-centos64 www]$ sudo vi sub/2.html 
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.6
test.html
ver 1.6
1.html
ver 1.6
2.html
ver 1.6
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.6
test.html
ver 1.6
1.html
ver 1.6
2.html
ver 1.6

```


varnishの設定ファイルには次のように記述されている。これは、BANというMethodのリクエストが送られてきた時に、/subディレクトリ以下の全てのhtmlと、/test.htmlのキャッシュをbanに入れる、つまり次回アクセスされたときに、バックエンドに取得するような設定になっている。

```
$ cat /etc/varnish/default.vcl

backend default {
.host = "127.0.0.1";
.port = "80";
}


sub vcl_recv {
if (req.request == "BAN") {
  ban("req.url ~ ^/sub/.*.html");
  ban("req.url ~ ^/test.html");
  error 200 "Banned.";
}

}

```

#### 3.2.2.キャッシュの破棄のコマンド

キャッシュの廃棄はdefault.vclの書き方次第だが、上記の書き方の場合、次のコマンドで、キャッシュが破棄される。（注：refresh.htmlは何でも良い）尚、banに関しては後で述べるvarnishadmで発行することも可能

```
$ curl -X BAN http://127.0.0.1:6081/refresh.html
```

#### 3.2.3.キャッシュ破棄の確認

その後、アクセスすると、無事キャッシュが破棄されて、内容が反映される

```
[vagrant@vagrant-centos64 www]$ curl -X BAN http://127.0.0.1:6081/refresh.html

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title>200 Banned.</title>
  </head>
  <body>
    <h1>Error 200 Banned.</h1>
    <p>Banned.</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 666764559</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>

```

この様子は、varnishadmコマンドを実行していると、バックエンドのサーバーにBanが設定されているのが確認できる。（説明書には、varnishadminは、varnishdに-Tを設定しないとダメと書いてあったが、実際はデフォルトで使えた）

最初はbanのリストを表示しても、何も表示されない

```
$ sudo varnishadm  
varnish> ban.list
200        
Present bans:
```

curlでコマンドを送ると次のようになる

```
varnish> ban.list
200        
Present bans:
1394437574.186510     0 	req.url ~ ^/test.html
1394437574.186499     0 	req.url ~ ^/sub/.*.html
```

実際にシェルで確認すると、ファイルの中身が最新になっていることが確認できた

```
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.7
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
```


### 3.3.キャッシュオブジェクトのタイムアウト
キャッシュミスを設定する方法、SmartBanを設定する方法を解説したが、その他にも、キャッシュしたオブジェクトのタイムアウトを設定する方法がある。Varnishのデフォルトのタイムアウトは、120秒なので、それを利用して、キャッシュのタイムアウトが有効である事を確認する。

#### 3.3.1.デフォルトタイムアウトの挙動

```
[vagrant@vagrant-centos64 www]$ date
Mon Mar 10 09:07:11 UTC 2014
vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.7
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
[vagrant@vagrant-centos64 www]$ sudo vi index.html 
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.7
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
```

途中で、ファイルを更新しているのだが、キャッシュヒットして、反映されない。２分待ってみる。何もしなくても、キャッシュが破棄されている。キャッシュのタイムアウトは別途設定可能である。

```
vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.8
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
[vagrant@vagrant-centos64 www]$ date
Mon Mar 10 09:10:02 UTC 2014

```
#### 3.3.2.ttlのデフォルト値の変更

キャッシュのデフォルト値の変更は、/etc/sysconfig/varnishの次の項目を設定すれば変更できる。実際にテストしてみたが、ちゃんと動作した。

```
# Default TTL used when the backend does not specify one
VARNISH_TTL=120
```

下の例では、VARNISH_TTLを300(5分)に設定し、元々のデフォルトの2分ではキャッシュクリアされていないが、5分後にはキャッシュがクリアされている事を確認できる。

```
[vagrant@vagrant-centos64 www]$ ./request.sh
index.html
ver 1.8
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
[vagrant@vagrant-centos64 www]$ date
Tue Mar 11 03:51:59 UTC 2014
[vagrant@vagrant-centos64 www]$ sudo vi index.html 
[vagrant@vagrant-centos64 www]$ sudo vi test.html 
[vagrant@vagrant-centos64 www]$ sudo vi sub/1.html 
[vagrant@vagrant-centos64 www]$ sudo vi sub/2.html 
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.8
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.8
test.html
ver 1.7
1.html
ver 1.7
2.html
ver 1.7
[vagrant@vagrant-centos64 www]$ date
Tue Mar 11 03:54:21 UTC 2014
[vagrant@vagrant-centos64 www]$ ./request.sh 
index.html
ver 1.9
test.html
ver 1.9
1.html
ver 1.9
2.html
ver 1.9
[vagrant@vagrant-centos64 www]$ date
Tue Mar 11 03:58:52 UTC 2014
```

#### 3.2.3.キャッシュ対象によるタイムアウトの変更

また、キャッシュの時間をコンテンツによって変化させたい場合も対応できる。この場合は、default.vclに記述すればよい。

詳細は、[Varnish Book:VCL Basics](https://www.varnish-software.com/static/book/VCL_Basics.html)を参考にすればよい。例えばこんな例が載っている.次の例は,jpgファイルを強制的に60sでタイムアウトさせる例。

```
sub vcl_fetch {
        if (req.url ~ "\.jpg$") {
                set beresp.ttl = 60s;
        }
}
```


### 3.4. varnishlog

Varnishは、マネージメントインスタンスと、チャイルドインスタンスから出来ている。コマンドには、varnishadmin, varnishlog, varnish… の３つがある。varnishadminはvarnishを操作可能になる。(Banの発行も可能) varnishlogは現在のリクエストの状態を見る事ができる。どのリクエストでバックエンドに行ったかを見る事ができる

varnishlogの例

```
[vagrant@vagrant-centos64 varnish]$ varnishlog -b -o -i TxURL
   14 BackendOpen  b default 127.0.0.1 60909 127.0.0.1 80
   14 TxURL        b /sub/1.html
   14 BackendReuse b default
   14 TxURL        b /sub/2.html
   14 BackendReuse b default
   14 BackendClose b default
   14 BackendOpen  b default 127.0.0.1 60912 127.0.0.1 80
   14 TxURL        b /index.html
   14 BackendReuse b default
   14 TxURL        b /test.html
   14 BackendReuse b default
   14 TxURL        b /sub/1.html
   14 BackendReuse b default
   14 TxURL        b /sub/2.html
   14 BackendReuse b default
   14 BackendClose b default
   14 BackendOpen  b default 127.0.0.1 60936 127.0.0.1 80
   14 TxURL        b /sub/1.html
   14 BackendReuse b default
   14 TxURL        b /sub/2.html
   14 BackendReuse b default
   14 BackendClose b default
   14 BackendOpen  b default 127.0.0.1 60939 127.0.0.1 80
   14 TxURL        b /index.html
   14 BackendReuse b default
   14 TxURL        b /test.html
   14 BackendReuse b default
```

### 3.5. varnishstat

varnishのヘルスチェックができるvarnishstatは下記の通り。詳細の見方はGettingStaredの記事を参照。

```
$ sudo varnishstat

0+01:54:13
Hitrate ratio:        6        6        6
Hitrate avg:     0.7500   0.7500   0.7500

          36         0.00         0.01 client_conn - Client connections accepted
          36         0.00         0.01 client_req - Client requests received
          24         0.00         0.00 cache_hit - Cache hits
          12         0.00         0.00 cache_miss - Cache misses
           3         0.00         0.00 backend_conn - Backend conn. success
           9         0.00         0.00 backend_reuse - Backend conn. reuses
           2         0.00         0.00 backend_toolate - Backend conn. was closed
          12         0.00         0.00 backend_recycle - Backend conn. recycles
          12         0.00         0.00 fetch_length - Fetch with Length
          10          .            .   n_sess_mem - N struct sess_mem
           4          .            .   n_object - N struct object
           6          .            .   n_objectcore - N struct objectcore
           6          .            .   n_objecthead - N struct objecthead
           
```

4.設計のTipsとアーキテクチャ
---
### 4.1.Varnishのアーキテクチャ

### 4.1.1.Varnishとプロセス

Varnishは大きくわけると、Managementプロセスと、Child/cacheプロセスに分かれる。Child/cacheプロセスがキャッシュを行い、Managementプロセスがそれを管理する。varnishadmコマンドで管理コマンドを発行できる。反映は、Varnishを再起動する事無く行える。（尚、varnishadmはリモートからでも操作できるように設定可能）

アーキテクチャの図は次のURLのProcess Architectureの項を参考にすると良い

[Tuning The Varnish Book](https://www.varnish-software.com/static/book/Tuning.html)

### 4.1.1.VCL(Varnish Configuration Language)

Varnishは、VCL(Varnish Configuration Language)というステートマシンがあり、それがコンセプトの中心になっている。それを操作するのは、defalt.vclだったりvarnishadmだったりする。

次のフロー(VCL request flow)を参考にするとよい
  
[VCL Basics - The Varnish Book](https://www.varnish-software.com/static/book/VCL_Basics.html)

このURLを参考にすると、default.vclの書き方は全て理解できる。基本的なラインとしては、リクエストされると、vcl_recvの状態に遷移する。例えば次のvcl_recvと比較してみよう。次のvcl_recvはVarnishのデフォルト実装である。上のURLの状態がメソッド名(vcl_recv)等で、return句で返却しているのが、次の状態(pipe/pass/lookup)である。returnで返すのは-1等の値ではなく、次の状態への状態遷移を記述する。

ループは書けないが、if文を書く事ができる。ifの中身は、次のような比較や正規表現もサポートされている
このif文の分岐によって、クライアントから送られてきたHTTPヘッダ、デバイス種類、Methodを用いで分岐し、キャッシュをさけたり、キャッシュのタイムアウトを調整したり、BANにしたり等の様々の操作を行うことができる。

```
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);
    }
    return (lookup);
}
```

### 4.1.3. VCLで使えるfunction 

VCLで使えるfunctionは次の通り

+ regsub(str, regex, sub)
+ regsuball(str, regex, sub)
+ ban_url(regex)
+ ban(expression)
+ purge;
+ return(restart)
+ return()
+ hash_data()

regsub/regsuballがURLの書き換え系、ban_url, ban, purgeがキャッシュのクリア系, return 次の状態遷移の為のfuntion. hash_dataはhash inputに文字を足す為のもの.

次のURLは、VCLのリファレンス

[VCL](https://www.varnish-cache.org/docs/trunk/reference/vcl.html)


### 4.2. サイジング

Varnishのサイジングとしては、キャッシュするオブジェクトにそれぞれ1kbのオーバーヘッドがかかる。例えば1,000,000オブジェクトあるとすると、1GBのメモリが必要になる。それ以外に100MB程度のメモリを消費する詳細は同じく次のURLに

[Tuning The Varnish Book](https://www.varnish-software.com/static/book/Tuning.html)

ちなみに上記のURLには、スレッド数等の他のパラメータも掲載されている。


### 4.3. ログについて

ログファイルはデフォルトでは書かれない。これは、ログのサイズがすぐふくれあがってしまうため。
次のURLのLog dataを参照

[Getting started - The Varnish Book](https://www.varnish-software.com/static/book/Getting_started.html)

5.参考資料
---

Varnish Bookというリソースが特に良いが、他の物も記述する

### 5.1.キャッシュの無効化の記事


これは一番詳しい記述
[Varnish Book: Cache invalidation](https://www.varnish-software.com/static/book/Cache_invalidation.html)

公式資料 [Purging and banning](https://www.varnish-cache.org/docs/3.0/tutorial/purging.html)

[Bans and purges in Varnish](https://www.varnish-software.com/blog/bans-and-purges-varnish-30)

curlのオプション解説

[curl the man page](http://curl.haxx.se/docs/manpage.html)

### 5.2.Varnishの全体像 

一番まとまっているGetting Startedこれを見れば全貌がわかる。

◎[Getting started](https://www.varnish-software.com/static/book/Getting_started.html)

Varnish Command Line Interface

コマンドラインインターフェイスは、varnishadmで使えるコマンド群

◎VCLの解説。コレを読めばdefault.vclの意味が分かる
[Varnish Book:VCL Basics](https://www.varnish-software.com/static/book/VCL_Basics.html)

公式資料 [Varnish CLI](https://www.varnish-cache.org/docs/trunk/reference/varnish-cli.html)




### 4.3.Varnishの設定

◎チューニングの決定版。アーキテクチャも説明されている
[Varnish Book: Tuning](https://www.varnish-software.com/static/book/Tuning.html)

公式のサイジング資料だが、上記のTuningに全て載っている[Sizing your cache](https://www.varnish-cache.org/docs/3.0/tutorial/sizing_your_cache.html)

◎varnishdの公式説明でフォルト値が見れるのがポイント。全部よまなくていいけど、デフォルト値がわかるのがよい
[varnishd](https://www.varnish-cache.org/docs/3.0/reference/varnishd.html)


設定ファイルのサンプル
[/etc/default/varnish](https://gist.github.com/reifman/4651558)