Varnish入門と仕組み
Agenda
- Varnishとは
- 仕組み
- 入門
- ベンチマーク
- Reference
Varnishとは
- 2005年に作成
- ライセンス BSD
- cache機能を持つリバースプロキシとして知られるOSSのHTTPアクセラレータの一つ(Squid cache等)
プロキシについて
-
フォワードプロキシ
- Clientの前段に配置して不特定多数のサイトに代理でアクセスしにいくこと
-
リバースプロキシ
- Serverの前段に配置して不特定多数のクライアントからアクセスしてきたのを代理レスポンス返す
-
WHY プロキシ?
- 負荷分散
- セキュリティ向上
- コンテンツキャッシュによる応答の高速化
どこで使われてる?
- Fastly
- Cookpad
- Hatena
大規模サービス技術入門より
- 某アイドルの投票
過負荷に耐えるWebの作り方より
仕組み
Varnishのキャッシュについて
- Varnishはキャッシュサーバであり、OSの性能を重複なく使うように設計されている。
- フロントエンドにVarnishを導入して静的なものをキャッシュ化、動的な処理が必要になる要求はNginxを通じてバックエンドのプログラムに投げられるといった使い方が多い。
- httpでのリクエストが前提のため、バックエンド側で利用されることもある。
- nginx proxy_cacheで同一 URLへ多数のリクエストが来ている状況でキャッシュのライフタイムが切れると、バックエンドへ同じ URL に対して複数のリクエストが飛んでしまい、アプリケーション側に負荷がかかるという現象の対策
(https)- Nginx -(http)- Varnish Cache - Application - DB
Varnishのシンプルさ
- ソフトウェアの動作が重くなる原因の一つに、カーネルが実装している機能をソフトウェアがさらに実装するというものがある。例えばディスクキャッシュやメモリキャッシュはカーネルが機能を実装している。
- 通常は一般のソフトウェアがそういった機能を実装するのは重複になる。
- Varnishは、こういった重複がなくカーネルディベロッパーの知識を活用した実装となっている。
- そのため、ディスクへのデータの書き込みをデフォルトでは実施しない。
- 再起動したタイミングでCacheはクリアされる。
入門
Varnishの特徴
- オブジェクトは、(デフォルトでは)mmap によるディスク上のファイルに保存される。また、プロセスの再起動でキャッシュはすべて失われる
- 基本的な設定(Listenするポート番号など)はコマンドラインオプションで与え、プロキシとしてのルールは設定ファイル(VCL)に記述する
- 単体ではログをファイルに書き出す機能を備えておらず、共有メモリ上に書き出す
doc
CLI
$ brew install varnish
- varnishd
- リバースプロキシ本体
- varnishadm
- 管理ツール
- varnishlog
- ロギング
- varnishncsa
- ロギング
- varnishstat
- 統計情報を表示
- varnishtop
- real-time情報を表示
varnishlog
Varnishは、マネージメントインスタンスと、チャイルドインスタンスから出来ている。varnishadminはvarnishを操作可能になる。(Banの発行も可能) varnishlogは現在のリクエストの状態を見る事ができる。どのリクエストでバックエンドに行ったかを見る事ができる
- varnishlogの例
$ varnishlog -b -o -i TxURL
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
varnishstat
varnishのヘルスチェックができるvarnishstatは下記の通り。詳細の見方はGettingStaredの記事を参照。
$ varnishstat
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
Varnish起動
$ varnished -f /etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:6082 -a 0.0.0.0:80
- -f 設定ファイル
- -s キャッシュのストレージタイプ
- -T 管理インターフェース(外からでもアクセス出来るようになる)
- -a 受付指定
# /etc/default/varnish
# service varnish restart
DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m"
Varnishのリクエスト処理フロー
- クライアントからVarnishにHTTPリクエストが来る
- リクエストの内容から判断してどういった振り分けをするか初期処理をする(vcl_recv)
- キャッシュの有無を確認する(vcl_hash)
- キャッシュがない場合にバックエンドに問い合わせて応答を待つ(vcl_miss)
4. バックエンドからの応答が返ってきた際に、そのコンテンツをキャッシュしてよいかどうかを判断する(vcl_fetch) - クライアントにコンテンツを返す(vcl_deliver)
ざっくりとした処理フロー
VCL(Varnish Configuration Language)
Varnishの設定はVCLという独自言語で記述する
- 次のフロー(VCL request flow)を参考にするとよい
- BackendとなるApplicationの設定
/etc/varnish/default.vcl
vcl 4.0;
backend default {
.host = "www.varnish-cache.org";
.port = "80";
}
- Varnishはデフォルトの設定ではクッキーが設定されているコンテンツに関してはcacheしない。
- 明示的にcacheするPathを記載するとcacheの対象になる
sub vcl_recv {
if (req.url ~ "^/パターン") {
unset req.http.Cookie;
}
}
- 全部Cacheさせて明示的にApplication側で
HTTP_HEADER "X-VAENISH-CACHE: PASS"
を入れることで動的コンテンツのみCacheしないようにすることも出来る
sub vcl_fetch {
if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*"){
set beresp.ttl = 120 s;
return (hit_for_pass);
}
if (beresp.http.X-VARNISH-CACHE == "PASS") {
set beresp.ttl = 0 s;
remove beresp.http.X-VERNISH-CACHE;
return (hit_for_pass);
}
return (deliver);
}
- その他にもHTTPのMethodでifを使うことも出来る
- 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);
}
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に文字を足す為のもの.
Varnishとプロセス
- Varnishは大きくわけると、Managementプロセスと、Child/cacheプロセスに分かれる。
- Child/cacheプロセスがキャッシュを行い、Managementプロセスがそれを管理する
- varnishadmコマンドで管理コマンドを発行できる。
- 反映は、Varnishを再起動する事無く行える。(尚、varnishadmはリモートからでも操作できるように設定可能)
アーキテクチャの図は次のURLのProcess Architectureの項を参考
キャッシュクリアの方法
Varnishのキャッシュをクリアする方法は次の4つがある
- ttlの設定時限設定
- purge オブジェクト1つに対するキャッシュクリア
- ban 正規表現を使ったキャッシュクリアの予約(SmartBan)
- set req_hash_always_miss = true あるURLに対するキャッシュのクリア
- purge method(varnish v4から)
- 一括でキャッシュをクリアできるのは、SmartBanのみ
- それ以外だと、ttlの時限設定(デフォルトでは、キャッシュがクリアされるのが2分の時限設定)
SmartBan方式
BANの方式はキャッシュをすぐにクリアするのではなく、対象のキャッシュをBANにしておき、次にそのURLがリクエストされた際に、バックエンドのサーバーに読みにいくといった挙動をする。
SmartBanの設定とテスト
BANというMethodのリクエストが送られてきた時に、/subディレクトリ以下の全てのhtmlと、/test.htmlのキャッシュをbanに入れる、つまり次回アクセスされたときに、バックエンドに取得するような設定になっている。
sub vcl_recv {
if (req.request == "BAN") {
ban("req.url ~ ^/sub/.*.html");
ban("req.url ~ ^/test.html");
error 200 "Banned.";
}
キャッシュの破棄のコマンド
キャッシュの廃棄はdefault.vclで設定可能。上記の書き方の場合、次のコマンドで、キャッシュが破棄される。(注:refresh.htmlは何でも良い)尚、banに関しては後で述べるvarnishadmで発行することも可能
$ curl -X BAN http://127.0.0.1:6081/refresh.html
ttlのデフォルト値の変更
キャッシュのデフォルト値の変更は、/etc/sysconfig/varnishの次の項目を設定すれば変更できる
# Default TTL used when the backend does not specify one
VARNISH_TTL=120
キャッシュ対象によるタイムアウトの変更
キャッシュの時間をコンテンツによって変化させたい場合は、default.vclを設定する。
- 次の例はjpgファイルを強制的に60sでタイムアウトさせる
sub vcl_fetch {
if (req.url ~ "\.jpg$") {
set beresp.ttl = 60s;
}
}
purge method(varnish v4)
v4から purge METHOD追加されてたようです!
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.55...
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}
}
サイジング
- Varnishは、キャッシュするオブジェクトにそれぞれ1kbのオーバーヘッドがかかる。
- スレッド数等の他のパラメータも掲載されている。
ログについて
- ログファイルはデフォルトでは書かれない。
次のURLのLog dataを参照
Getting started - The Varnish Book
ベンチマーク
Golang製のHTTP load testing tool
brew install vegeta
- localhostへ秒間100リクエストリクエストを5秒間行う
$ echo "GET http://localhost:3000/" | ./vegeta attack -rate=100 -duration=5s | ./vegeta report
簡単に試せます
Reference
- 過負荷に耐えるWebの作り方
- サーバ/インフラを支える技術
- 大規模サービス技術入門
- The benefits of using Varnish
- High Performance Rails long edition
Varnish本番運用に向けて
キャッシュの無効化の記事
Varnish Book: Cache invalidation
Purging and banning
Bans and purges in Varnish
Varnishの全体像
Varnish Command Line Interface
Varnish Book:VCL Basics
Varnish CLI