1月 252015
 

小ネタです
Varnishを使う上で冗長化をどうしようと悩むことが多々有ります。
単純に横に並べてLBでバランシングしてもキャッシュの同期をどうしようという問題にぶち当たります。
VarnishSoftwareがサブスクリプションで提供しているVarnishPlusでは同一階層のVarnishにおいてキャッシュオブジェクトのレプリケーションを行うVarnish High Availabilityという機能が存在しますがコミュニティ版のVarnishでは存在しません。
(VarnishPlusについてはそのうち記事書こうと思います)
強引にVCLでSquidのsiblingのような動きをするように書くことも出来なくないのですが個人的にはオススメできません。
幾つか理由があるのですが一番大きい理由がRace conditionに陥るからです。
VarnishはこれはThundering Herd問題に対処するために同時に同じリクエストが来た場合でもバックエンド/オリジンに行くリクエストはひとつです。
簡単にいうとロックしています。これは単体サーバではうまく動きますが同一階層においてキャッシュを同期しようとすると問題が起きます。
hib
図のように同時に同じリクエストが来て、どちらもオブジェクトを持っていない場合にRace conditionになります。
これを防ぐためにreq.hash_ignore_busyをtrueにするという手もありますが台数が増えた時にどうするかとか運用が手間ですし、VCLをミスったら破綻するような危険を持つべきではないと考えています。
つまり同一階層においてキャッシュを安全かつ簡単に同期する方法はVarnishPlus以外に存在しません。
また、Varnishはrestartすると基本的にキャッシュがすべて吹き飛びます。
persistentもあるじゃないかという話もありますが非推奨になったうえ運用上ケアすべき問題が多く癖が強過ぎて普通の人には使いづらいです。

これらも含めて様々な問題に対処するために多段構成を組むことがあります。

  • 全体でのキャッシュ同期
  • 重複リクエストによるオリジン負荷
  • サーバダウン時のオリジン負荷
  • 効率的なキャッシュの保持

上記は問題の一部ですが1つずつ解説します。

全体でのキャッシュ同期
全体でキャッシュが同期されているということはどういうことでしょうか?
あくまで個人的な考えですが、全体でTTLの整合性がとれていることだと考えています。
例えばTTLが60秒のオブジェクトとVarnish2台で考えてみましょう

  1. Varnish-1にアクセスしてキャッシュされる(TTL=60s)
  2. 30秒まつ
  3. Varnish-2にアクセスしてキャッシュされる(TTL=30s)
  4. さらに30秒後
  5. Varnish-1/2両方でキャッシュがexpireする

こんなかんじです。
つまり最初にアクセスされた時間を全体で把握していて、TTL内であればキャッシュを保持していないインスタンスでも経過時間を減算しておくということです。
これは静的コンテンツで上書きをしないのであればさほど考える必要はありませんが(消されたらbanすればOK)動的コンテンツの場合は注意を払う必要があります。
こんなケースを考えてみましょう

  • 10分毎に更新されるランキングページがある
  • しかし実際はアクセスされる度に集計されてVarnish側でTTLを10分としている

この場合で同期がとれていない場合アクセスの度に最新のランキングだったり、少し前のランキングだったりと目まぐるしく変わる可能性が高いです。
そこで多段構成です。
tiv
Varnishの標準で用意されているdirectorはランダムやハッシュ等で振り分けが可能です。
Varnishがキャッシュオブジェクトを特定するのはHostとURLを使っています。(server.ipも使っては居ますがここでは一旦置いておきます)
そこで同じキーを使ってハッシュ振り分けを行うことで同じHostとURLを保つ場合は常に同じ2段目のVarnishにアクセスします。


vcl 4.0;
import directors;
probe healthcheck {
    .request =
            "GET /healthcheck/check.html HTTP/1.1"
            "Host: xxxx.xxxx"
            "Connection: close";
    .timeout           = 2s;
    .window            = 5;
    .threshold         = 3;
    .interval          = 1s;
}

backend ws01 {.probe=healthcheck;.host = "192.168.1.1";.port = "80";}
backend ws02 {.probe=healthcheck;.host = "192.168.1.2";.port = "80";}

sub vcl_init{
  new ws_hash = directors.hash();
  ws_hash.add_backend(ws01, 1.0);
  ws_hash.add_backend(ws02, 1.0);
}
sub vcl_recv{
  set req.backend_hint = ws_hash.backend(req.url + ":" + req.http.host);
}

Varnishはキャッシュしてからの経過時間であるAgeヘッダをレスポンスし、またこれを解釈してTTLから減算します。
つまり図のような構成でHash振り分けを行った場合(TTLは60秒とします)

  1. (黒線)/hogeにアクセスする。
  2. 1Aにキャッシュがないので2Aにリクエスト
    1. 2Aにキャッシュがないのでオリジンにリクエスト
    2. 2Aでキャッシュする(TTL=60s/Age=0s)
    3. 1Aでキャッシュする(TTL=60s/Age=0s)
  3. 10秒待つ
  4. (赤線)/hogeにアクセスする。
  5. 1Bにキャッシュがないので2Aにリクエスト
    1. 2Aがレスポンス(Age=10s)
    2. 1Bでキャッシュする(TTL=60s/Age=10s)
  6. 10秒待つ
  7. (青線)/hogeにアクセスする。
  8. 1Cにキャッシュがないので2Aにリクエスト
    1. 2Aがレスポンス(Age=20s)
    2. 1cでキャッシュする(TTL=60s/Age=20s)
  9. 40秒後
  10. 1A/1B/1C/2AにおいてTTL=AgeとなりキャッシュがExpireする

(Expire周辺の計算は変数が多くわりかし複雑なんですがここでは単純化しています)
このようにすべてのオブジェクトが同時に消えることがある程度期待できます。
ここである程度としているのはexpire前にnukeしてしまったり、1段目に行き渡ってない状態で2段目が死んだりした時のことは考えていないからです。
これも考慮に入れる必要がある場合は動的コンテンツ側で適切なヘッダをつける必要があるでしょう。

重複リクエストによるオリジン負荷
Varnishを複数並べる理由はいくつかあります。冗長構成を取るためにだったり、トラフィックが増えてきたのでそれを捌くための増設だったりです。
dup
単純に横に並べてしまうと最悪、同じリクエストで最大並べた台数分のリクエストが来る可能性があります。
これも多段構成にすることで解決できます。
tiv
同一リクエストは2段目で必ず同一サーバを経由するために1段目がいくら増えようともオリジンに行くリクエストは1つです。

サーバダウン時のオリジン負荷
キャッシュサーバが落ちれば当然ですがキャッシュが無くなるので再度オリジンに取得しに行きます。
fail
キャッシュに依存しているシステムほどキャッシュが吹き飛んだ時にオリジンの負荷が一気に上がり負荷が増え、最悪の場合連鎖障害になることが有ります。
しかし多段構成を組んでいる場合は余り影響を受けない、もしくは影響を小さくすることが出来ます。
1段目が死亡しても2段目がキャッシュを保持しているのでオリジンの負荷はそこまで増えません。
同じように2段目が死亡しても1段目がキャッシュを保持しているのでオリジンの負荷の上がり方はある程度抑えられます。

効率的なキャッシュの保持
1段目はクライアントからの激しいリクエストを受けるため、高速なstorage(mallocやSSD/PCIeSSDなどのfile)が必要です。
ここはいくらサーバを増やしてもキャッシュの保持容量は単一サーバでのstorageサイズとなります。ランダムにそれぞれのサーバにリクエストされるためです。
もちろん現金で殴るという手段も取れなくはないのですが(僕を現金で殴ってくれる人募集しています)、1台落ちるとわりかし被害が大きくなりやすいのでそこはバランスをみてやるべきでしょう。
多段構成の場合で2段目は多少遅いstorageでも問題がありません。(とはいってもSSDはほしいです)
理由は既に1段目である程度のリクエストをシェーブしているのと、よくアクセスされるオブジェクト(=ホットデータ)はほぼほぼ1段目に集中することが期待できるため全体で高速にレスポンスすることが可能です。
また、ハッシュ振り分けを行う場合は当然ですが2段目で重複オブジェクトを持ちません。
そのためキャッシュの保持容量は単純に足したサイズとなり、よりオリジンの負荷軽減に役に立ちます。

ここまで多段構成イイヨーイイヨーという話をしましたが多段構成でも注意すべきところがあります。

  • AppとVarnishが同居している多段構成においての振り分けについて

AppとVarnishが同居している多段構成においての振り分けについて
sep
例えば上図のようにOrigin(App)が分離しているケースは問題ありませんが
nsep
このように2段目のVarnishがAppと同居しているケースを考えてみましょう。(2段目のVarnishは必ずlocalのappにリクエストを行う)
当然ながら1段目はハッシュで振り分けを行っています。
そして動的コンテンツの場合はすべてのリクエストをキャッシュ出来ないことが多いです。
むしろキャッシュ出来ないものが多いケースのほうが多いと思います。
当然ながらキャッシュ出来ないリクエストはオリジンに直撃します。
そしてたいていの場合キャッシュ出来ないリクエストは

  • 会員情報を扱っていてユーザ毎に内容が異なる
  • POSTやPUTなどそもそもオリジンに確実にリクエストを通さないと行けない
  • などなど

だったりでだいたい同じURLだったりします。
URLが同じということはハッシュが同一ということなので負荷が寄ります。
せっかく負荷を減らすために多段にしたのに本末転倒といえるでしょう。
じゃぁどうするかというとキャッシュするリクエストとキャッシュしないリクエストで振り分けを変えることです。


vcl 4.0;
import directors;
probe healthcheck {
    .request =
            "GET /healthcheck/check.html HTTP/1.1"
            "Host: xxxx.xxxx"
            "Connection: close";
    .timeout           = 2s;
    .window            = 5;
    .threshold         = 3;
    .interval          = 1s;
}

backend ws01 {.probe=healthcheck;.host = "192.168.1.1";.port = "80";}
backend ws02 {.probe=healthcheck;.host = "192.168.1.2";.port = "80";}
backend ws03 {.probe=healthcheck;.host = "192.168.1.3";.port = "80";}
backend ws04 {.probe=healthcheck;.host = "192.168.1.4";.port = "80";}

sub vcl_init{
  new ws_hash = directors.hash();
  ws_hash.add_backend(ws01, 1.0);
  ws_hash.add_backend(ws02, 1.0);
  ws_hash.add_backend(ws03, 1.0);
  ws_hash.add_backend(ws04, 1.0);

  new ws_rand  = directors.random();
  ws_rand.add_backend(ws01, 1.0);
  ws_rand.add_backend(ws02, 1.0);
  ws_rand.add_backend(ws03, 1.0);
  ws_rand.add_backend(ws04, 1.0);
}
sub vcl_recv{
  ...
  if(キャッシュするリクエストの場合){
    //キャッシュする
    set req.backend_hint = ws_hash.backend(req.url + ":" + req.http.host);
    return(hash);
  }else{
    //キャッシュしない
    set req.backend_hint = ws_rand.backend();
    return(pass);
  }
}

hr
こうすることでキャッシュも効率的に行なえますし、負荷も適切に割り振り出来ます。

まとめ
多段構成を行うことで幸せになれるポイントを示せたんじゃないかなと思います。
もちろんデメリットがゼロかというとそうではなく、多段にすることで経由するサーバが増えるためその分latencyは悪化しますが、大抵の場合はそれを補う効果が得られます。
これらのメリットや考えるポイントはごく一部で他にも地域を考慮したりとか3段目つくったりとか、ホットデータ専用の隔離を作ったりとかいろいろ行うことによっていろいろ違います。
これらの階層構造は何も自社環境だけで留まるわけではなく、各CDNもまたひとつの層と考えて最適な構造を考えるのも面白いと思います。

※注意事項
現在(4.0.2)のVarnishですがヘルスチェックで引っかかって振り分け落とされた負荷がそのまま特定のバックエンドに寄るというバグが有ります。
masterでは修正されていますが4.0.3に適用されるか微妙なので注意が必要です。
また修正後についてもハッシュ振り分けについてはfail時の振り分けで全体で再計算が走るので同様に注意が必要です。
本家ではデフォルトで提供するのはシンプルにしたいということでいわゆるconsistent hashingはサポートしないと言っているので
そのような機能があるvmod(vslp)を使うと良いと思います


1月 192015
 

このブログを見てる人だとご存知だとは思うのですが、Varnishはいろんな機能があるリバースプロキシです。
VCL、ヘルスチェック、強力なログ機能、そしてESIなどの機能が存在します。
ESI以外の記事は偶に見かけるのですがESIはあまりみないなーというのと


こんな乗りで去年の10月あたりから知り合いのサイト(一般的には大規模にあたるぐらいのPV)にESIを入れたので
(特定できてもそっとしておいてください)
その時に効果や注意したことをメモ的に残そうと思います。

まずESIって何かというとESIタグをページ中に挿入することでVarnish側でそのURLの内容で置換してくれる技術です。
詳しくは以下のスライドを参照してください、Ver3時の資料ですが大幅には変わっていません。

最初にそのサイトでのESIの効果を説明します。
ESIを入れる動機は主に速度改善と負荷軽減だと思いますが、非常に良い結果がでました。
esi02
導入自体は10月中~末あたりから始めたのですがそれ以前は割りとグラフが上下していたのが入れ始めてからガクッと落ちて安定的になっているのがわかると思います。
esi03
esi04
サーバ応答時間とページダウンロード時間のグラフは非常に面白い変化をしています。
応答時間はESIで改善し、逆にダウンロード時間は悪化しています。
これの理由は単純で、ESIを行っていない時はページの内容を全部準備してからresponseしていたところが、
ESIによって内容があるところまでVarnishがresponseし、無ければ取りに行く(そこでwait)ようになったからです。
わかりづらいのでコードを交えて解説します


<html>
<head>
<link rel='stylesheet' id='dashicons-css'  href='/css/hoge.css' type='text/css' media='all' />
<script type='text/javascript' src='/js/mage.js'></script>
</head>
<body>
...
<esi:include src="slow.php">
...
</body>
</html>

上記の場合だとesi:includeで指定したslow.phpを読むようになっています。
仮にslow.phpが3秒かかったとしても、ESIタグの前まではVarnishがレスポンスします。
そのため応答時間は速くなり、ダウンロード時間が遅くなりました。
ここで一つポイントなのが、ESIタグまで先にレスポンスできることです。
大体headにcssやjs読み込みがあるのでブラウザは先にそれらリソースを読み込み、更に途中までレンダリングすることが出来るため表示速度の改善も期待できます。
仮にページの表示に同じ時間かかるとしても、最初の1秒ぐらいでなんとなくコンテンツが出始めるのと、3秒ぐらいたってから初めて出るのだと前者のほうがよいと感じると思います。(少なくとも僕はそうです)

esi01
これはとあるページの情報ですが、やはり速くなっているのがわかります。
僕の場合は、適用前2~3秒ぐらいだったのが今さっき見たら0.2秒を切っていました。

そしてサーバコストも全体で30%程度の減、ESIだけだと内5~10%程度の寄与があったのではと考えています。
(並行で幾つかの改善を行ったため全部がESIの効果ではないです。。)
他にもツールによる大量のダウンロードに対する負荷耐性もよくなりました。

このように非常に効果が高いESIですが、銀の弾丸なんてどんなものにもあるわけではなく非常に注意が必要です。
例えば以下のケースを考えてみましょう

ヒットレートが低く子要素を多く含む
現在のVarnishでは子要素の取得を逐次処理で行うため、例えば子要素が10ありそれぞれで0.5秒かかりヒットレートが50%だとすると平均で子要素の取得だけで2.5秒かかります。
つまり速度改善を目論んで入れたのに逆に遅くなってしまうケースもあるということです。
ちなみに現在開発中のVarnish4.1には子要素を並列で取得する改善(Parallel ESI)が行われる可能性があるため(wishlist)将来は改善する可能性があります。

ヒットレートが低く使用しているフレームワーク等のオーバーヘッドが大きい場合
1ページをレスポンスするために複数のページを使用するため当然ながらリクエスト数が増えます。
そのためフレームワーク等のオーバーヘッドが大きい場合は当然負荷が上る可能性があります。

じゃぁヒットレートが低いとそもそもアウトなのかというとそうでもなく
ベースページはヘッダとフッタのみが記述して、実コンテンツを1つのESIで読み込む。(そのままラップする感じ)
こうすることでヒットレートが低くてもCSSやJSなどが含まれるヘッダ部分は先にブラウザにレスポンスできるためレンダリング速度の改善が見込めます。

さて、上記のような注意事項はそもそもESIを適用するかしないかの判断になるので今回は置いておいて
今回は実際にESIを行う上でこうやっておくと楽だったり、意識しないとハマる可能性があるポイントを紹介します。

  • キャッシュのスコープ管理
  • キャッシュするステータスコードを意識する
  • 直アクセスの禁止
  • ストレージについて
  • set-cookieの扱い
  • ログについて
  • 1つずつ解説します。

    キャッシュのスコープ管理
    どんなキャッシュを行う上でも一番重要なことは何をキーにキャッシュするかです。
    例えば、Aさん向けのキャッシュがBさんに表示されてしまう事は絶対に避けないといけないことです。
    このことを防ぐために例えばユーザの情報を含むものはキャッシュしないというのも手です。
    しかしそのようなデータ(常に表示されるようなようこそ○○さんみたいなバーとか)もキャッシュしたいものです。
    わかりやすくミスっても漏洩などの最悪のパタンにならないようにと考えて僕はパスで管理するようにしています。

    /esi/[ルール]/foo/…/bar.php

    このルールはVaryみたいなものです。
    例えばuserと入ってればuser毎にキャッシュするみたいな感じです。
    あくまで例ですが以下のような感じです。

    /esi/user/ ユーザー毎にキャッシュ、非ログインユーザはキャッシュしない
    /esi/browser/ UA判定を行いPC/SPで別々のキャッシュを持つ
    /esi/その他(common等)/ 特に判定せずに共通のキャッシュを持つ

    他にも毎時0分にキャッシュがクリアされるようなルールがあっても良いと思います。(TTLの管理をテンプレート/アプリのどちらでやるかという話もありますが)

    実際にそのサイトで使ってるVCLは流石に出せないのでサンプルでVCLを書いてみました。
    動作確認はしていないのでこんな感じと考えてもらえれば嬉しいです。

    
    sub vcl_recv{
      unset req.http.x-varnish-hash;
      ...
      if(req.url ~"^/esi/"){
        if(req.url ~"^/esi/user/"){
          if(req.http.cookie && req.http.cookie~"(.* )?user="){
            set req.http.x-varnish-hash = regsub(req.http.cookie, "^(.* )?(user=[^;]+)(;.*)?$","\2");
          }else{
            unset req.http.cookie;
            return(pass);
          }
        }else{
          unset req.http.cookie;
          if(req.url ~"^/esi/browser/"){
            if(req.http.user-agent ~"(iPhone|iPad|iPod|Android)"){
              set req.http.x-varnish-hash = "sp";
            }else{
              set req.http.x-varnish-hash = "pc";
            }
          }
          return(hash);
        }
      }
      ...
    }
    sub vcl_backend_response {
      ...
      set beresp.do_esi = true;
      ...
    }
    sub vcl_hash {
      if(req.http.x-varnish-hash){
        hash_data(req.http.x-varnish-hash);
      }
    }
    
    

    ここで重要なのは/user/以外の場合はクッキー等ユーザーの識別情報を削除することです。
    こうすることで万が一/common/にユーザーごとの出し分けが必要な物が混じってもユーザーを識別できないので重大な事故には至りません。
    またvcl_hashで追加しているのがreq.http.x-varnish-hashだけでreq.url等が含まれていない理由はここを参照してください(同じVCLアクション(vcl_recvなど)を複数定義する)

    パスで分けるのはそのパスにコントローラーを放り込んでおけばその通りにルールが適用される気軽さです。
    わざわざコード側でこのコントローラーはuserのキャッシュを行ってうんぬん・・・と書いてレスポンスヘッダなどでVarnish側にどう動かすか渡してもいいんですが
    テンプレートから見てこれどんな動きするっけ?みたいにわからなくなりがちなのでこうしています。
    ESIのパフォーマンス以外の良い所は部品を組み合わせるように要素を自由に配置してページを作れるところだと僕は考えています。
    いわばテンプレートが主役といった感じです。

    キャッシュするステータスコードを意識する
    ページのレスポンスコードは当然ながらベースページに依存します。
    子要素が503を返そうが302を返そうがベースページが200を返していればクライアントでは200で見えます。
    そこでキャッシュすべきステータスコードを注意深く意識する必要があります。
    50Xをキャッシュしないのは当然として、302なんてものもキャッシュしないほうがよいでしょう、というか200だけキャッシュするぐらいに絞ったほうが良いです。

    直アクセスの禁止
    /esi/以下に直アクセスされても弾く場合はreq.esi_levelを利用します。

    
    sub vcl_recv{
      if(req.esi_level == 0 && req.url ~"^/esi/"){
        return(synth(403));
      }
    ...
    }
    
    

    req.esi_levelはリクエストがどれだけネストしているかを示します。
    0はベースページで1以上は子要素になります。(2以上は子要素からincludeされた要素)
    ちなみにネストはデフォルトでは5になっており、これ以上ネストしたい場合はパラメータのmax_esi_depthを変更する必要があります。

    ストレージについて
    ESIのストレージはmallocやSSD/PCIeSSDを使った高速なfileストレージに入れるのをおすすめします。
    HDDなfileストレージに入れるのは余程の理由があるかつチューニングに自信がない限り辞めたほうがよいです。
    これは遅延が直接ページのレスポンス速度に関係するからです。
    ページのレスポンスが遅れれば、その遅れた部分に含まれてるimgタグ等による読み込みが遅れて全体のレンダリング速度に影響してきます。

    また、同一インスタンスで画像などの大きめな静的ファイルも配信している場合はESI専用のストレージ定義を作るのも有効です。
    VarnishのストレージはPersistentを除いてLRUで管理しているのでTTL前に容量不足でキャッシュがnukeしても問題ないかと思うこともあると思いますが、それだとgraceが効かなくなってしまいます。
    なぜならいくらキャッシュヒットしていて優先度が高いオブジェクトでも容量が足りない状態でexpireしたら当然すぐに回収されるからです。
    graceの動きはこの記事を参考にしてほしいですが
    簡単にいうとexpireしてgrace期間中にアクセスがあった場合は期限切れオブジェクトをレスポンスしてバックグラウンドでフェッチすることでexpireしても高速にレスポンスできます。

    今回のサイトでは3種類のストレージに分けました。

  • ほぼすべてのページで利用され、nukeすると多くのページで速度が落ちるようなもの
  • 自由文で入力が出来るなど総数がわからなく、ヒットするものそうでないものの差が極端なもの
  • 上記以外のもの
  • 分けることで例えば自由文のものに押し出されてgraceが効かなくなるということもなくなります。

    ちなみにストレージを分けるにはberesp.storage_hintを使います。
    起動パラメータ

    
    -s esi_memory=malloc,1G -s esi_file=file,/var/lib/varnish/varnish_storage_esi.bin,7G -s default=file,/var/lib/varnish/varnish_storage_default.bin,7G
    
    

    VCL

    
    sub vcl_backend_response {
      set beresp.storage_hint = "default";
      ...
      if(req.url ~"^/esi/"){
        if(req.url ~"^/esi/xxxxx/"){
          set beresp.storage_hint = "esi_memory";
        }elsif(req.url ~"^/esi/yyyy/"){
          set beresp.storage_hint = "esi_file";
        }
      }
    }
    
    

    起動パラメータの-s esi_memory=malloc,1Gとberesp.storage_hintで指定する値と一致しているのがわかります。

    set-cookieの扱い
    子要素でset-cookieを発行しても当然ながらブラウザ側には届かないので注意が必要です。
    ESIを使う場合はベースページでのみset-cookieを発行して子要素では決して発行しないようにしてください。

    ログについて
    キャッシュを行うため当然ながらws側にはすべてのログがいきません。
    完全なログを取る必要がある場合は当然varnish側で取得する必要がありますが
    割り切りでベースページはキャッシュしないとするだけでもだいぶ楽になると思います。

    まとめ
    ESIは結構楽しいので使ってみようと考えてみる一助になれば幸いです。
    あと、当然ですがすでにあるサイトに全適用するのは割と辛いので効果高いところをつまみ食いしてみてどうなるか見てみるのも面白いと思います


    10月 182014
     

    Varnish4.0.2がリリースされました。
    多くのバグフィックスと機能追加・改善・修正、ドキュメント改善などを含むためバージョンアップを強く薦めます。
    ちなみにvarnishstatのヒットレート表示も復活しています。

    Changes
    ダウンロード

    変更内容から幾つか抜粋して紹介します。


    バグフィックス

    ESIのメモリリークを修正

    deliver時に競合状態陥る可能性があるバグを修正
    チケット報告はされていないのできわめて稀なケースだとは思います。

    再利用を行う変数の初期化不足で落ちるケースがあるのを修正しました(#1553)

    purge時にworkspaceを使いきって落ちるのを修正しました(#1551)

    varnishtopで正しくグループ化されないのを修正しました(#1591)

    VMOD_ABIのバージョン要件が4.0.1で緩和されたはずなのにされていなかったのを修正しました(#1538)

    varnishncsaでHTTPでない壊れたリクエストが来た場合に出力しないようにしました(#1584)

    max-ageとageが存在する場合でTTL計算時にageが二重で効いていたのを修正しました(#1578)
    例えばmax-ageが10でageが2だった場合、期待されるttlは8ですがageが二重で効いて6になってました。

    director.hashでバックエンドを取得する際に存在しない変数を指定すると落ちるのを修正しました(#1568)
    hashディレクターで取得する際にreq.http.cookieのようにリクエストによっては存在しないものを指定すると落ちましたがそれを修正。

    vcl_backend_responseからretryするとbereqの変更内容が消えるのを修正しました(#1512)
    この修正と一緒にbackendスレッドでロールバックを行うと落ちる問題も修正されました。

    リクエストのbodyを読みきれなかった場合で落ちるケースが有るのを修正しました(#1562)

    shm_reclenを増やすと落ちるケースが有るのを修正しました(#1547)

    random/hashディレクターでsickなbackendにリクエストを投げるケースがあるのを修正しました(#1575)

    varnishtest実行時にバッファ不足でassertが出るのを改善しました
    varnishtestのログのバッファサイズは256KB持っているのですが
    出力されるログが多すぎると以下の様なエラーがでるので512KBまで拡張しました。


    パラメータ追加・変更

    追加:group_cc
    vclをコンパイルする際に利用するcc_commandを実行するグループを指定できます。

    名前変更:vsl_reclen(旧名shm_reclen)
    まだshm_reclenは残っていますがそのうち消えると思うので使っている場合は変えましょう。

    値変更:workspace_client
    最小値が3KBから9KBに増えました。


    機能追加・改善・修正

    vmod_std:querysortでのキー数制限(32)がなくなりました
    workspaceを使うようになっていますのですごく大きなキーを変更する可能性がある場合は大きめにすると良いです。

    vclにHTTP型が追加されました
    reqやbereqなどをまるごとvmodに渡すようなことが出来るようになりました。

    vmodにBYTES型が追加されました
    もともとvclではあったBYTESですが、型変換無しでvmodに渡せるようになりました。

    rollbackがstd.rollbackに移動しました
    rollbackは非推奨になります。

    vcl_deliverでsynthが使えるようになりました

    varnishstatのhitrate表示が復活しました
    よかった・・・

    組み込みのエラーページがvalid HTML5になりました

    server.(hostname|identity)がすべてのファンクションで使えるようになりました
    4.0.1まではclientスレッドのファンクションでしか使えませんでした。

    vmod_std:文字列検索をするstrstrが追加
    使い方は通常のstrstrと同じです。
    大文字小文字は区別されますので必要に応じてstd.tolowerを使うなどで揃えると良いです。

    
    //STRING strstr([検索対象文字列], [検索文字列])
    
    //req.url中に/admin/が含まれているかをチェック
    if(std.strstr(req.url, "/admin/")){
      //found
      ...
    }else{
      //notfound
      ...
    }
    
    

    varnishlog:-kオプションが復活
    指定個数のトランザクションを表示したらexitするオプションです

    varnishadm:vcl.showでincludeされているすべてが表示できる-vオプションが追加
    varnishadmで現在loadされているvclのリストを出力するvcl.showというコマンドがあるのですが
    一つ困ったところにinclude先が表示されないという問題がありました。
    しかし今回サポートされた-vオプションでその名前でloadされているvclの全情報(builtin.vcl含む)が表示されるようになりました。

    
    [root@cache01 ~]# varnishadm vcl.show -v boot
    
    // VCL.SHOW 0 110 input
    vcl 4.0;
    import std;
    import directors;
    include "/etc/varnish/backend.vcl";
    include "/etc/varnish/main.vcl";
    
    // VCL.SHOW 1 5479 Builtin
    ...中略...
    
    // VCL.SHOW 2 1180 /etc/varnish/backend.vcl
    probe healthcheck {
    ...中略...
    
    // VCL.SHOW 3 3179 /etc/varnish/main.vcl
    sub vcl_synth{
    ...中略...
    
    

    といった感じです。
    コメントのVCL.SHOWは以下の情報を示します
    // VCL.SHOW [srcbodyのインデックス番号] [文字列長] [srcname]
    まずVCLはDSLで実行前にCのコードに変換されるのですが、その際にVCL_confという構造体に各種の情報が突っ込まれていてインデックス番号とsrcnameはそこの情報になります。

    
    varnishd -d -f /etc/varnish/default.vcl -C
    の出力から抜粋
    const char *srcname[4] = {
            "input",
            "Builtin",
            "/etc/varnish/backend.vcl",
            "/etc/varnish/main.vcl",
    };
    const char *srcbody[4] = {
        /* "input"*/
            "vcl 4.0;\n"
            "import std;\n"
    ...
            "",
        /* "Builtin"*/
            "/*-\n"
            " * Copyright (c) 2006 Verdens Gang AS\n"
    ...
            "}\n"
            "",
        /* "/etc/varnish/backend.vcl"*/
            "probe healthcheck {\n"
    ...
            "",
        /* "/etc/varnish/main.vcl"*/
            "sub vcl_synth{\n"
    ...
            "",
    };
    ...
    const struct VCL_conf VCL_conf = {
            .magic = VCL_CONF_MAGIC,
            .init_vcl = VGC_Init,
            .fini_vcl = VGC_Fini,
            .ndirector = 9,
            .director = directors,
            .ref = VGC_ref,
            .nref = VGC_NREFS,
            .nsrc = 4,★VCLの個数
            .srcname = srcname,★名前(inputはルートのVCL、builtinはVarnishのデフォルトの動作を定義したもの、ファイルパスのものはincludeしたもの)
            .srcbody = srcbody,★VCLそのもの
            .recv_func = VGC_function_vcl_recv,
            .pipe_func = VGC_function_vcl_pipe,
            .pass_func = VGC_function_vcl_pass,
            .hash_func = VGC_function_vcl_hash,
            .purge_func = VGC_function_vcl_purge,
            .miss_func = VGC_function_vcl_miss,
            .hit_func = VGC_function_vcl_hit,
            .deliver_func = VGC_function_vcl_deliver,
            .synth_func = VGC_function_vcl_synth,
            .backend_fetch_func = VGC_function_vcl_backend_fetch,
            .backend_response_func = VGC_function_vcl_backend_response,
            .backend_error_func = VGC_function_vcl_backend_error,
            .init_func = VGC_function_vcl_init,
            .fini_func = VGC_function_vcl_fini,
    };
    
    

    直近のVDDによると次は4.1でが予定されていて速くて年内に出る可能性があります。


    10月 182014
     

    varnish3.0.6がリリースされました。
    現在計画されている3.0.x系の最終リリースになります。

    Changes
    ダウンロード

    今回のリリースはほぼドキュメント修正とバグフィックスですがpanic起こすバグ修正もありますのでバージョンアップをおすすめします。


    バグフィックス

    http_max_hdrが4の倍数でない場合にクラッシュして起動しないバグを修正しました(#1327)
    親プロセスは起動しますが子プロセスがpanicを起こして上がってきません。

    ESI利用時にReqEndのタイムスタンプがマイナスになるのを修正しました(#1297)
    コードを見てる感じだと本来親リクエストでのみ初期化すべきタイムスタンプを
    小リクエストを処理している際にも初期化してしまって演算時にマイナスになるようです。
    動作上の実害はありませんが、詳しくログを眺めてる人にとっては気になるかもしれません。

    特定条件でbanの回収が正常に出来ないケースを修正しました(#1470)
    Busy状態のオブジェクトに対してban lurkerスレッドが動作しようとする場合は処理をスキップしますが
    フラグの立て方がまずく、再実行時にマッチされないのを修正しました。

    同梱されているjemallocがsegfaultを起こすのを修正しました(#1448)

    バックエンド名のprefixがif/include/elseで始まる際にVCLのエラーになるのを修正しました(#1439)
    地味に嬉しいです。

    オリジンのレスポンスでgzipデータ終了後にごみデータが続くとスレッドがスピンするのを修正しました(#1086)

    varnishtest実行時にバッファ不足でassertが出るのを改善しました
    varnishtestのログのバッファサイズは256KB持っているのですが
    出力されるログが多すぎると以下の様なエラーがでるので512KBまで拡張しました。

    
    Assert error in vtc_log_emit(), vtc_log.c line 122:
      Condition(vtclog_left > l) not true.
    
    

    ヘビーにvarnishtestを使う人(私とか)にとっては嬉しい変更です。


    その他変更

    varnishncsaの%Dが整数に切り捨てられます
    4.0での変更と同様です。
    マイクロ秒単位なので特に影響ないと思います。


    6月 262014
     

    Varnish4.0.1が公開されました。
    ついでに公式サイトもデザインが新しくなって見やすくなりました。

    バージョンアップ自体は主にBugfixで、4.0.0がリリースされて報告されていたバグが基本的に修正されています。
    幾つか重要度の高いbugfixがあるので4.0.0を入れた人は適用するのをおすすめします。
    (僕が報告してたスレッドが開放されないなどのバグも修正されてました)

    また、今回も機能変更と追加がかなりされています。
    動作に関わるところをについて抜粋して紹介します。

    公式Changes
    ダウンロード

    機能変更

    Persistent storageがdeprecatedになりました

    ML見てたら不穏な動きが出てたのでどうなるかなーとおもってたんですがさっくり廃止予定になりました。
    4.0.0になって多少使いやすくなったとおもったんですがパフォーマンスを維持しつつ整合性を確保するのがきつかったみたいです。
    今後利用する際は-s deprecated_persistentと指定する必要があります。
    また、やり取りでの想像ですが次のリリースで消すということはなさそうな気がします。
    コード修正が必要になった段階で切り離すんじゃないかなと


    vmod_std機能追加

    クエリソート機能が追加されました(querysort)

    vimeoのboltsortが取り込まれました。

    
    sub vcl_recv{
      //in:/?a=1&amp;c=3&amp;b=2
      //  :/?b=2&amp;c=3&amp;a=1
      //out:/?a=1&amp;b=2&amp;c=3
      set req.url = std.querysort(req.url);
    }
    
    

    クエリをお手軽に正規化することが可能になりキャッシュ効率がよくなることが期待できます。
    一つ注意事項があるとすればキー数は32に制限されていることです。
    ただ、最新コード上はその制限が解除されており(というかリリース日当日に解除されてる)
    次のリリースには取り込まれると思います。
    32以上のキー数を扱う可能性がある場合はとりあえずこのComitを適用すればよいと思います

    変換系のメソッドが追加されました

    文字列->浮動小数(real)

    
    //std.real([文字列], [パース失敗時のfallback値])
    //out:
    //-   VCL_Log        12.990
    //-   VCL_Log        0.000
    std.log(""+std.real("12.99",0.0));
    std.log(""+std.real("hoge",0.0));
    
    
    

    浮動小数->時間(real2time)

    
    //std.real2time([浮動小数])
    //out:
    //-   VCL_Log        Wed, 25 Jun 2014 15:26:40 GMT
    //-   VCL_Log        Wed, 25 Jun 2014 15:26:40 GMT
    std.log(""+std.real2time(1403707478));
    std.log(""+std.real2time(1403707478.999));
    
    

    ※若干例が悪いかも

    時間->整数(time2integer)

    
    //std.time2integer([時間])
    //out:
    //-   VCL_Log        1403707709
    //-   VCL_Log        1403707769
    std.log(""+std.time2integer(now));
    std.log(""+std.time2integer(now + 1m));
    
    

    時間->浮動小数(time2real)

    
    //std.time2real([時間])
    //out:
    //-   VCL_Log        1403707750.479
    //-   VCL_Log        1403707750.489
    std.log(""+std.time2real(now));
    std.log(""+std.time2real(now + 10ms));
    
    

    VCL変更

    日付の指定に年(y)を指定できるようになりました

    365d = 1yです


    その他変更

    varnishncsaの%Dが整数に切り捨てられます

    マイクロ秒単位なので特に影響ないと思います

    varnishncsaで新しいフォーマットが追加されました

    %I(全受信バイト数)と%O(全送信バイト数)が追加されました。
    個人的に結構嬉しいです。

    passがtransfer-encoding: chunkedに対応しました

    今までreturn(pipe)じゃないとダメでした(builtin.vclでpipeしてた)


    あとアップデートかけた時にVarnishのrestart走ります。(前まで無かったような気が・・・)
    以下の組み合わせの場合は即死しますので注意してください
     ・persistentを利用している
     ・パッケージの自動アップデートが有効になっている
    このケースの場合以下のコンボが成立します
     1) パッケージの自動アップデートがかかる
     2) 4.0.1でrestartがかかる
     3) persistentの名前を置き換える必要があるので起動しない
     4) ( ˘ω˘)

    また、まだ告知はされていませんが3.0.6RC1が上がっているので近いうちに3系のアップデートも来るかもしれないです。
    あと週末にでも別記事で4.1といった今後のリリーススケジュールについて書きます!


    5月 182014
     

    4/29に全世界同時でVarnish4のリリースパーティーがありまして、東京もやるぞーということでクックパッド様でピザ食べながら発表してきました。
    v4rpのタグを眺めていると野外BBQしながらブロック壁に投影しているところもあったりとなかなか良い感じでした。

    で、前回と同様にVarnish4での新機能や変更点を発表しようと思いまして、GWもあるしと資料をのんびり書いてましたら結局尻に火がついてしまって前日ぐらいまでガリガリ涙目で書いていました。
    2->3の時も涙目だった記憶があるのですが、今回は変更点がかなり多いこともありまして、途中でこれ間に合うんかな・・・とかんがえる事も・・
    ということであまり発表練習が出来なかったのでお聞き苦しいところがありましたら申し訳ありませんでした。

    で、私の発表資料はこちらです。

    GoogleDocs版(アニメーションする)

    また、発表の際に忘れていて触れていなかったのですが、是非一度builtin.vclを見てみてみるとデフォルトでどのように動くか、また上書きする際に何を注意すればよいかわかるのでお勧めです。(特にvcl_hitに今回からロジックが入るようになっているので)
    VCLの動きは「同じVCLアクション(vcl_recvなど)を複数定義する」の記事で触れているようにまずユーザが定義したVCLが読み込まれてその後にbuiltinのVCLが動きます。
    builtin.vcl

    最後に
    参加者の皆様方お疲れ様でした。また、会場の準備・提供をしていただきましたmirakui様・クックパッド様本当にありがとうございました!


    4月 252014
     

    先日Varnish4リリースされたよ―(^O^)/な記事を書いた際に、リリースパーティーどっかでやらないかなとVarnish3のリリースパーティーを行った白金台方面を眺めつつチラチラしていたところ、今回もクックパッド様で行うことになりました。
    @mirakuiさん本当にありがとうございます。

    日程は4/29の19:00~からでGW中なのですが(平日だと思って夜にしていた)
    ピザでも摘みながらVarnish関連について話ができればなと考えています。
    私のほうではVarnish4で変わったことやとあるサイトの本番(知り合いのサイト)にVarnish4入れて嵌ったドキュメントに記載されていない事項などを話そうと思っています。
    v4_io
    こんなスライドや
    vsl_group
    こんなの(比較的見栄えするところをキャプチャしました)を今書いているところです。

    またVarnish Softwareよりステッカーなどをいただけることになっていまして、当日間に合えば配布できると思います。

    当日皆様とお会いできるのを楽しみにしています。
    Varnish 4.0 Release Party in Tokyo申し込み


    4月 112014
     

    3.0.0の公開から約3年ぶりにメジャーバージョンが上がりました。(公式サイト)
    今回も非常に多岐に渡る変更があるのですが、前回とはまた少し毛色が違います。
    大きな変更点について見て行きましょう。

    ストリームのフルサポート

    3.0の時もストリームはサポートしていたのですが、4.0になってより強化されました。

    初回コネクション 同時接続してきたコネクション
    3.0 ストリームされる 初回コネクションが完了するまでロックされ、その後一気に転送
    4.0 ストリームされる 既に初回コネクションでストリーム済みのデータを一気に転送してその後ストリーム

    イマイチイメージが掴みづらいかもと思ったのでgifアニメを作ってみました。
    やってる内容は、1秒ごとにaを出力するphpに対して開始時間を数秒ずらして3並列で取得していっています。
    初回のアクセスが終わった後は何回かアクセスしてみてキャッシュされていることを確認しています。

    window配置

    初回のクライアント 3秒遅れのクライアント 5秒遅れのクライアント
    apacheログ
    varnishncsa

    検証コード
    ■slow.php

    
    <?php
    header('Cache-Control: max-age=20');
    ob_end_flush();
    ob_start('mb_output_handler');
    for($i=0;$i<10;$i++){
            echo "a\n";
            ob_flush();
            flush();
            sleep(1);
    }
    
    

    ■vcl@3.0.5

    
    sub vcl_fetch{
      set beresp.do_stream = true;
      set beresp.ttl   = 1w;
    }
    
    

    ■vcl@4.0.0

    
    sub vcl_backend_response{
      set beresp.do_stream = true;
      set beresp.ttl = 1w;
    }
    
    

    ストリームの様子のgif
    3.0.5
    varnish3-stream


    4.0.0
    varnish4-stream


    3.0.5は最初のアクセス以外はブロックされていますが4.0.0はブロックされていない上に既に転送されているものは最初に一気に転送されているのがわかります。
    比較的大きなコンテンツを配信する場合は非常に有用な機能といえます。

    オブジェクトがexpireした際にgrace期間が残っている場合は、古いオブジェクトを返しつつバックグラウンドでオブジェクトを更新します

    オブジェクトがexpireした時の動作も強化されました。

    初回expire後のコネクション 同時接続してきたコネクション フェッチ終了後
    3.0 fetchを行い新オブジェクトを転送する、fetchの間は通常どおり待機させられる 古いオブジェクトを転送 新オブジェクトを転送
    4.0 バックグラウンドでfetchを行い、自コネクションは古いオブジェクトを転送 古いオブジェクトを転送 新オブジェクトを転送

    今回もgifを撮ってみました。
    取得に3秒かかるコードでTTLは10秒です。expire時の動きを見てみてください。

    検証コード
    ■date.php

    
    <?php
    header('Cache-Control: max-age=20');
    echo date("Y/m/d H:i:s")."\n";
    sleep(3);
    
    

    ■vcl@3.0.5

    
    sub vcl_fetch{
      set beresp.do_stream = true;
      set beresp.ttl   = 10s;
      set beresp.grace = 10m;
    }
    
    

    ■vcl@4.0.0

    
    sub vcl_backend_response{
      set beresp.do_stream = true;
      set beresp.ttl   = 10s;
      set beresp.grace = 10m;
    }
    
    

    grace動作
    3.0.5
    varnish3-bgfetch


    4.0.0
    varnish4-bgfetch


    3.0ではexpire時にsleepが効いているのが分かります。
    4.0ではそれがありません。

    varnishlogをグルーピング出力したりqueryで絞り込むことが可能に

    これは非常に大きな機能なので別記事で取り上げますが
    簡単に言うとリクエストがどのESIにサブリクエストを使っているかなどがグルーピングできたり
    携帯端末で1秒以上レスポンスにかかったログの抽出が出来たりします。

    directorがvmodになりました

    これも別記事で取り上げます。
    独自のdirectorが作りやすくなったのと他にも利点があります。

    vmodがrequest bodyを見ることが可能になりました

    今までも超トリッキーな事をすれば見ることは可能だったのですが正式にサポートされました。
    POSTリクエストの中身を見て何かしらの処理を行うようなvmodを作るのが簡単になります。

    インラインCがデフォルト無効になりました

    これは廃止されるというわけではなくセキュリティ対策としてデフォルト無効になっているだけです。
    vcc_allow_inline_cというパラメータで復活可能です。

    VCLが大幅に変わった

    恒例行事です。別記事で書きます。
    公式のアップグレード方法は以下です
    Upgrading to Varnish 4

    varnishapi周りが刷新

    当然ですが3.0向けのvmodは移行が必要です。

    バグ修正多数

    今までバグ修正はされていたもののリリースには含まれていなかった様々なバグ修正が今回のタイミングで取り込まれています。
    たとえば
    syntheticでASCIIコード以外を出力しようとした場合に文字化けするバグ修正が取り込まれていたり
    vclをdiscardしてもヘルスチェックが止まらないバグなどが直っています

    varnishstatの表示改善

    これは実際に触ってみたほうが早いですが、カウンタの説明が出るようになっています。

    パラメータの変更

    これも別途記事で書きます。

    まとめ

    他にも取り上げては居ませんがかなりの変更点があります。

    さて、ここまでわざとぼかして書いていたのですが
    今回の一番大きな変更はクライアントとバックエンドのスレッドを分離したことです。
    これにより、ストリームやgrace時の動作改善などが可能となりました。
    また現versionでは残念ながら実装されていませんが、パラレルフェッチESIも可能となるはずです。(予定には入っているようです)
    また、これはコード上の話ですが3.0まではHTTPを処理する箇所がvarnishのコードと結構くっついていたのですが
    4.0では分離されており拡張が容易な構造にリファクタリングされています。
    これはHTTP2.0を見据えた変更です。
    最初に2.1から3.0の変更とは毛色が違うといったのは、構造を大幅にリファクタリングしたということです。

    また、検証をしている段階では比較的安定しており、最近趣味で手伝っているPVもそれなりに多いサイトに週末にでも投入して動作検証も行う予定です。
    その結果も記事などにできればなぁと考えています。

    あと今回もリリースパーティーやるみたいなので
    誰かやらないかなとチラチラと・・・


    2月 052014
     

    Varnishでヒット率などの統計情報を見たい時はvarnishstatを利用しますが
    この統計ではそのインスタンス丸ごとの統計情報しか取得できません。
    複数のドメインをホストしている場合や、特定のパスでは動的にコンテンツを生成していたりするすると
    本当に適切なキャッシュ戦略となっているか判断するにはvarnishstatだけでは不十分です。
    ヒット率を押し上げているのはスペーサーの1×1のgifファイルで、キャッシュすべき生成コストが高いコンテンツは低いヒット率かもしれません。
    そこで今回はホスト別・パス指定が可能なvarnishhoststatというスクリプトを作成しました。
    出力はこんな感じです

    vhs1

    取得している項目は
    ・トラフィック(ヘッダを除く)
    ・RPS
    ・ヒット率(バックエンドにフェッチしない場合はHitとして扱っています)
    ・平均レスポンスタイム
    ・ヒット時の平均レスポンスタイム
    ・ミス時の平均レスポンスタイム
    ・平均ファイルサイズ
    ・HTTPステータスごとのRPS(2xx, 3xx, 4xx, 5xx)
    です。

    また、-Fオプションを使うことでホスト・パスでの絞り込みが可能です。
    このように指定します。

    
    -F [後方一致のホスト名]@[パスの正規表現(省略可能)]
    
    

    -Fは複数指定可能で指定された順で評価されます。
    たとえば
    example.netで/img/ /css/ その他で集計したい場合は以下のように指定します

    
    python varnishhoststat.py -F example.net@^/img/ -F example.net@^/css/ -F example.net
    
    

    出力はこんな感じになります
    vhs2

    またjsonで出力したり(-j)
    ファイルに書き出したり(-w)
    することもできます。

    最後に使用上の注意ですが、VSLにアクセスして取得しているのでそれなりに負荷が高いです。
    大体varnishdのCPU使用率の40~50%ぐらいを使います。
    本番で使おうと思われる方は一応負荷をみてください。

    ということで、よかった使ってみてください。
    varnishhoststat


    12月 172013
     

    6ヶ月ぐらい前の話になるんですがVarnish User Group7(VUG7)で発表してきました。
    下書きは書いたものの発表後の燃え尽きと、時期逃したかなと放置していたのですが、先日VUG8もあったのでせっかくなので書きました。

    資料はこれです。

    話した内容は古い配信システムをマイグレーションした話とその過程で作った、使ったツールの紹介です。
    会社のシステムなので細かいことは書けないのですが、所属している会社を考えて頂ければそれなりの規模だと想像していただけると思います。更にいうと単一ではなく複数のシステムの統合です。
    また、スライドにも書いてあるとおりなのですが、マイグレーションはダウンタイムなしで最初の1台を入社後の一月以内で投入というスピード感で行われました。

    どのようなマイグレーションでもそうだと思うのですが、今回私が特に気をつけて行ったのが以下です。
    ・キャパシティプランニング
    ・分割リリース
    ・十分なテスト
    ・投入後の念入りな計測とフィードバック
    ・ドキュメント整理

    スライドには使わなかったのですがざっくりこんなサイクルを回していました。
    vug7
    なぜこんなにTDDっぽいことをやっていたかというと、今回のシステムがそれなりに大きかったため分割リリースという手段を取ったことと、VCL自体を共通部分とホスト固有の設定を分割したからです。
    このようなサイクルを回したことでデグレードもテストで抜けましたし、バグが混入しているんじゃ・・・という心理的な不安も軽減され、一日に何度も設定をDeployも不安なくできました。
    また、投入後もドメインや場合によってはディレクトリ別のトラフィックやRPSやhitrateなどをみたり非常に細かく計測行いチューニングを行いました。
    では、これらを標準で提供されていたコマンド群(varnishtest/varnishlog…)で全部足りたかというとそうではなく、いくつかは自分で開発したコマンドを使いました。
    VUG7では開発したテストと計測についてのツール3つを発表してきました。

    ・Varnishのログをわかりやすく表示するvsltrans
    ・varnishtestのログをわかりやすく表示するvtctrans
    ・VSLにサクッとアクセスするためのライブラリpython-varnishapi

    なんでこんなツールを作ったかというと

    ・Varnishが吐き出す各種ログは詳細過ぎて人間が読むには時間がかかる
    ・標準コマンドだと細かい測定を行う際に微妙に手が届かない

    例えばApacheのmod_rewriteのLv9のログ出力を即把握出来る人は少ないんじゃないかと思います。
    同様にvarnishlogも詳細すぎて正直すぐ把握しづらいものです。
    事実VarnishのIRCをたまに眺めていると、このようなやり取りを見ることが有ります。

    「キャッシュヒットしないんだけど助けて」
    「VCLとvarnishlogのログをだせ」
    「出したよ!」
    「ああVaryの問題だね」
    「!!!」

    他ミドルウェアでもよくあるやりとりにも見えますが、ここに重大な問題があると考えています。
    varnishlogの出力する詳細なログには原因が出力されているのですが理解出来ない、これは非常に残念なことだと思います。
    ミドルウェアを使う上でいろいろな問題点にぶち当たることは多々あることです。
    そういう時に解決しやすい、仮に解決できないとしても一体何が起きているかということを把握できるのは重要だと思います。
    これはvarnishtestのログにも言えることで情報がぱっと見わかりづらいです(参考:Varnishでテストコードを書こう!
    ツールが一助になればなぁと考えています。

    また、キャッシュを行う際に重要な指標の一つにヒット率があると思います。
    しかしVarnishが標準で取れるのはそのインスタンスでのヒット率で、例えばホストごとや特定のディレクトリでのヒット率・トラフィックを調べるのはできません。
    なぜそのような細かい条件でのヒット率が重要なのかというと、キャッシュするオブジェクトの生成コストは同一ではないからです。
    コストが低いオブジェクト(=ファイルとか)のヒット率に隠れて、コストの高いオブジェクト(=動的に生成してる画像とか)のヒット率が低くなってしまうと、システム全体としての負荷が高まって本末転倒になってしまう可能性があります。
    私はサマライズされたヒット率ではなくてシステム全体の負荷を見るべきだと考えています。
    1×1の透明画像のヒット率がいくら高くてもあんまり嬉しくないのです。
    そこでホスト別やディレクトリ別のような細かい計測を行うためにVarnishが共有メモリ上に吐き出している生ログ(VSL)に簡単にアクセスするためのライブラリを作りました。
    そんなに大したことはしていないのですが案外便利です。

    若干記事に上げるのは遅くなったのですが誰かの参考になれば嬉しいと思います。

    また、今回初めて海外の勉強会に参加してしかも英語で発表してきたのですが
    Varnish Software・コミュニティ・会社のネイティブな方の添削・レアジョブの講師の方々などのサポートもあり、私の中では非常にうまくいったんじゃないかなと思っています。
    今後も機会があれば、日本に限らず海外の勉強会行ってみたいなーと思います。

    あと関係無いですが今日誕生日だったりするので何か貰えるとうれしいです!