8月 032017
 

Varnishの複数のバージョンがリリースされました。 [changelog] [パッケージDL] [ソースDL]

今回のリリースはセキュリティ対策によるもので、なるだけ迅速にアップデート、もしくは回避VCLを入れるべきです。
詳しくは公式情報(VSV00001)を参照してください。

脆弱性の内容

書くか少し迷ったんですが、テストコードがまんまコミットされてるので解説します・・
クライアントがTransfer-Encoding: chunkedかつchunk-sizeの指定が内部の変数でMSBが立つぐらい大きな指定でリクエストを行った場合、AssertでVarnishが再起動します。(DoS)


$ sudo varnishadm panic.show|head
Panic at: Wed, 02 Aug 2017 16:45:40 GMT
Assert error in v1f_pull_chunked(), http1/cache_http1_vfp.c line 172:
  Condition((vfe->priv2) == 0) not true.
version = varnish-5.1.2 revision 6ece695, vrt api = 6.
0
...

対象バージョン

Transfer-Encoding: chunkedに対応したのは4.0.1からなのでそれ以降のすべてのバージョンになります。

バージョン系 影響を受けるバージョン 修正バージョン パッケージDL先
4.0.x 4.0.1~4.0.4 4.0.5 link
4.1.x 4.1.0~4.1.7 4.1.8 link
5.0.x 5.0.0 5.1.3まで上げる必要があります link
5.1.x 5.1.0~5.1.2 5.1.3 link

4.0.0及び3.0.xは先に述べた通り、そもそも今回の機能がないので対象外です。

回避方法(VCL)

VCLでの暫定的な回避方法があります。
これらはchunkedでリクエストしてきたものを503で落とすことで回避します。
大抵のブラウザの場合はTransfer-Encodingを指定したリクエストは行わない事が多いのですが、念のため確認すると良いでしょう。
varnishlog -cq ReqHeader:Transfer-Encoding -i ReqMethod -i ReqURL
これで何かしら出てきて、正規のリクエストの場合はVCLでの回避は不可能ですのでバージョンを上げる必要があります。

なおここで紹介している回避コードは公式そのままなので公式も参考にしてください(VSV00001)
4.0.x向け
インラインCを利用します。
そのためvcc_allow_inline_cをtrueに設定する必要があります
起動パラメータの場合は
-pvcc_allow_inline_c=true
varnishadmで指定する場合は
varnishadm param.set vcc_allow_inline_c true
で可能です
VCLは以下の通りです。


sub exploit_workaround_4_0 {
        # This needs to come before your vcl_recv function
        # The following code is only valid for Varnish Cache and
        # Varnish Cache Plus versions 4.0.x
        if (req.http.transfer-encoding ~ "(?i)chunked") {
                C{
                struct dummy_req {
                        unsigned magic;
                        int restarts;
                        int esi_level;
                        int disable_esi;
                        char hash_ignore_busy;
                        char hash_always_miss;
                        void *sp;
                        void *wrk;
                        int req_step;
                        struct {
                                void *a;
                                void *b;
                        };
                        int req_body_status;
                };
                ((struct dummy_req *)ctx->req)->req_body_status = 6;
                }C

                return (synth(503, "Bad request"));
        }
}

sub vcl_recv {
        # Call this early in your vcl_recv function
        call exploit_workaround_4_0;
}

4.1.xと5.0.0向け
同じくインラインCを利用しますので4.0.xで有効にしたように指定が必要です。


sub exploit_workaround_4_1 {
        # This needs to come before your vcl_recv function
        # The following code is only valid for Varnish Cache and
        # Varnish Cache Plus versions 4.1.x and 5.0.0
        if (req.http.transfer-encoding ~ "(?i)chunked") {
                C{
                struct dummy_req {
                        unsigned magic;
                        int step;
                        int req_body_status;
                };
                ((struct dummy_req *)ctx->req)->req_body_status = 5;
                }C

                return (synth(503, "Bad request"));
        }
}

sub vcl_recv {
        # Call this early in your vcl_recv function
        call exploit_workaround_4_1;
}

5.1.x向け
インラインCは使用しません。


sub vcl_recv {
        if (req.http.transfer-encoding ~ "(?i)chunked") {
                return (fail);
        }
}

その他

実は今回の脆弱性について概要と公開予定時刻を事前に教えてもらっていました(攻撃には使用できないぐらいの荒い情報ですが)
お陰で公開後に即対処することが出来たのですが、VIVU – Very Important Varnish Usersで触れられているようにVMLを買うと教えてもらえるようなので(€1000/年)
企業でVarnishを使っているころは買ってみると良いのではないでしょうか?


8月 022017
 

4.1系の最新版の4.1.7がリリースされました。 [changelog] [公式のリリース文] [パッケージDL] [ソースDL]

今回の変更内容は主にstat周りのバグフィックスとちょっとした新機能です。

追加された機能

varnishncsaのLogFormatの%{X}xでrecord-prefixに対応しました(#2077)

もともとは%{VSL:tag[field]}xといった感じで指定できたのですが
Timestampのように同一タグでラベルで情報が違うものの場合、例えばProcessにかかった時間、Fetchにかかった時間を分けて出力することは不可能でした。(最初にマッチしたものだけなのでStartになる)
しかし今回record-prefixに対応したため、vsl-queryのような柔軟な指定が可能になりました。(levelには対応してないですが)


$ sudo varnishncsa -F "fetch:%{VSL:timestamp:fetch[2]}x process:%{VSL:timestamp:process[2]}x"
fetch:0.000377 process:0.000392

バグ修正

workspaceのリセット漏れでworkspaceが足りなくなって落ちるケースがあったのを修正(#2219)

varnishstatでのglobを修正(#2022,2118,2320)
あまり知られていないオプションだと思うのですが -fでstatのキー絞り込みをできるのですが
-1との組み合わせの時にうまく動かないバグがいくつかあったようです。

nuke_limitの効果がなくなっていたのを修正(#1764)

ヘルスチェックの応答でReason-Phraseがない場合に失敗していたのを修正(#2069)

(ちなみに今回記事が遅れたのは前の記事書いたあとあたりに書いたつもりになって忘れてました・・すいません)


5月 052017
 

4.1系の最新版の4.1.6がリリースされました。 [changelog] [公式のリリース文] [パッケージDL] [ソースDL]

今回の変更内容は基本的にバグフィックスと5.1.1/5.1.2で追加された一部機能の取り込みになります。

追加された機能

すべて5.1.1/5.1.2で追加された機能です。
vmod_stdにgetenv(STRING)の追加
varnishtestにsetenvの追加
vsl-queryでvxid指定が可能に

バグ修正

Ageレスポンスヘッダの数値が実経過時間より大きな数値になるケースがあったのを修正しました(#2216)
Ageレスポンスヘッダの小数点の丸めをsprintfの%.0fで行っていたため、実際の経過時間より大きな数値になることがあったんですが
切り捨て(floor)を行うようにした感じです。

std.querysortでワークスペースが足りない際にpanicしてたのを修正しました(#2233)

稀にVSLを利用するクライアントが初期化に失敗するケースがあるのを修正しました(#2241)
あくまでに初期化時(VSM_Init)のみなので稼働中のクライアントの場合には問題ありません。
自分もVSLを利用するクライアントを作ったり使ってますが遭遇したことがないのでかなり稀だと思います。

クライアントワークスペースの空き容量が少ない場合にチャンク転送を行った場合にpanicしていたのを修正しました(#2275)

動的バックエンドを利用している場合で稀に子プロセスが再起動するのを修正しました(#2295)


4月 072017
 

5.1.2がリリースされました。
5.1.1の記事で4月中旬まで様子を見たほうがよいと言っていたのはこの件です。
(まだ確定じゃなかったので微妙にぼかした表現でしたが・・)
今回のリリースは1件の機能強化と主にHTTP/2関連のバグフィックスです。
[changelog] [リリース文] [パッケージDL] [ソースDL]
 

機能強化

std.collectでセパレータを指定できるようになりました
std.collectは同一名のヘッダが複数行送られてきた場合に1行にまとめる関数ですが今までは[, ]でまとめられていました。
通常の場合は特に問題ないのですが、Cookieの場合は[; ]でまとめる必要があり、追加で置換が必要など面倒でした。
デフォルト値には[, ]が指定されているので、既に使用している場合は特に追加指定は不要ですが
Cookieで使用する場合は以下のように指定するとよいです。


std.collect(req.http.cookie, "; ");

 

バグ修正(h2以外)

#2295 動的バックエンドを使用しているときにヘルスチェックが無限ループに陥ることが合ったのを修正
#2207 #2278 PROXYプロトコルを使用したバックエンドのヘルスチェックで競合状態がおきるのを修正
 

バグ修正(h2)

#2291 #2300 Cookieヘッダを1行にまとめるように修正
#2247 ボディを含むリクエストにContent-Lengthが存在した場合でもTransfer-Encoding: chunkedを追加していたのを修正
上記2つの修正により、前回紹介したVCLトリックは不要になりました。

#2238 ReqAcctの値がないためvarnishncsa等で入出力したバイト0になるのが修正されました
わかりやすいところだとvarnishncsaの%bなどが常に0になっていたのですが、この部分が実装されたためサイズがでるようになりました。

多数のassertを修正

Varnishでのhttp/2について

5.1.1では検証環境で使用できると書きましたが、今回は十分な検証を行った上であれば本番環境に入れることもできなくはないと考えています。
もちろんまだexperimentalで残バグもおそらく新規バグもあると思いますが
主にSimonや自分が相当数踏み抜き、修正されているので
以下の幾つかの注意点を守れば比較的安定的に動作すると思います。

#2268 PRIV_TASK/TOPを利用しているvmodを避ける
PRIV_TASK/TOPについてはこちらの記事を御覧ください。
このPRIVの確保・解放を行う際に競合状態が起きているようで、稀にassertが起こります。
現時点で回避するには使用しているvmodの関数を避けるしかありません(例:vmod_cookie)
使用しているかどうかの判定はvccファイルを見てPRIV_TASKかPRIV_TOPがあるかで判定できます。

スレッドのメモリ使用サイズがh/1の時と比べて大幅に増える可能性があるのでチューニングが必要
h2はh1と比べるとメモリをより多く使用するため一瞬なんか漏れてると思うぐらい増えます。
元々メモリに余裕がある環境であれば特に問題はないのですが、VPSなどあまりメモリがない環境の場合は問題といえます。
解決方法としては単純にスレッド数に余分があれば減らす感じです。
もし、減らしすぎてスレッドが足りなくなったとしても、そのリクエストはキューイングされて、すぐにスレッドを追加作成して処理されます。
関連するパラメータとカウンタはこれです。

パラメータ
thread_pools スレッドプール数
thread_pool_min スレッドプール毎の最低スレッド数
thread_pool_max スレッドプール毎の最大スレッド数
thread_queue_limit スレッド枯渇時のキュー長
カウンタ
MAIN.threads_limited ドロップされたセッション数
MAIN.sess_dropped ドロップされたセッション数
MAIN.sess_queued キューイングされたセッション数
MAIN.threads 現在のスレッド数

スレッド数はthread_pools * thread_pool_min以上thread_pools * thread_pool_max以下となります。
チューニングをする際はMAIN.sess_droppedが起きるのは論外で、MAIN.sess_queuedもそんなに起きないのが望ましいです。
このあたりのチューニングは今回の本筋ではないので詳しくは解説しませんが、要は過剰であればthread_pool_minを減らしてみて
MAIN.threadsが止まったあたりでdropped/queuedも起きないように調整するとよいのではとか思います。
本当にメモリが辛い場合は多少パフォーマンスは落ちますがqueuedを覚悟してthread_pool_minをガッツリ下げてthread_queue_limitを上げるのも手だと思います。(その前にスペックとか他のパラメータを再検討したほうが良いと思いますが)
結局のところ、ここでいいたいのはメモリの使用傾向が変わるとおもうのできちんとチューニングしようねって話です。
追記:上記で長めに運用しましたが、多少ましになる程度でした。(とはいえスレッド数の調整はしたほうがよいかなと思います。

とはいえ、HTTP/2を使う際はpkg-varnishcacheを使ってなるだけ最新を追っておくと良いかと思います。

hitch1.4.4を使う場合の注意事項
hitchは設定のreloadをサポートしているのですが(HUPを投げる)
ocsp staplingが有効だとreload時にゾンビプロセスが残る場合があります(#167)
以下のように設定して無効にすることで回避も可能です。


ocsp-dir = ""

あくまでoffにすることを推奨しているのではなく、ここは各自考えてといった感じでお願いします。

最後に
ぜひVarnishのhttp/2を試してみてほしいなと思います。
また、Varnishの開発を助けるためにVMLを購入するのをぜひ検討してみてください


4月 022017
 

5.0.0の後継の5.1.1がリリースされました。 [changelog] [リリース文] [changes] [Upgrading]
また、今回からパッケージがpackagecloudで提供されるようになりました。(packagecloud)
5.1.0はどうなったの?という話ですが、ちょっと問題となるバグがあったため翌日にすぐ5.1.1を出した感じです。
今回のリリースでは4.1.4/4.1.5で変更された内容と細かい機能修正(VCL変更含む)があります。(それについては割愛してます)
VCLの変更はあるものの修正しないと動かないような変更はないのでよほどのことがない限りそのまま動作するはずです。
なお、VMODについては動かなくなるものもあるので事前に使用しているものが動くかを確認したほうが良いでしょう。
また、累積バグも修正されているのですが、よほど修正されているバグで困ってない限りは本番への適用は一旦4月中旬までは様子見たほうが良いかと思います。(何もなかったらすいません)

機能強化

varnishdのパラメータ追加(-I [cli file])
workerが起動する前に指定されたcli file読み込まれます。
このファイルはvarnishのcliコマンド(vcl.loadやvcl.useなど)が列挙されています。
これがなんの役に立つのかというと、5.0.0で追加されたvclのラベル機能を使っている人には非常に便利な機能です。
以前紹介したとおりlabel機能を使うには先にvcl.loadを利用してラベルを定義する必要がありました。
しかしvarnishdでvclを読み込む-fオプションではラベルを指定できなかったため、有効に使うには別にスクリプトを作るなど若干めんどくさかった面も否定できませんでした。
しかしこのオプションを使うことでworkerが起動する前にラベル付きでvclを読み込むことができるので非常に楽になります。


vcl.load panic /etc/varnish_panic.vcl
vcl.load siteA0 /etc/varnish_siteA.vcl
vcl.load siteB0 /etc/varnish_siteB.vcl
vcl.load siteC0 /etc/varnish_siteC.vcl
vcl.label siteA siteA0
vcl.label siteB siteB0
vcl.label siteC siteC0
vcl.load main /etc/varnish_main.vcl
vcl.use main

このようなcliファイルを作っておいて


sub vcl_recv {
    if (req.http.host ~ "asite.example.com$") {
        return(vcl(siteA));
    }
    if (req.http.host ~ "bsite.example.com$") {
        return(vcl(siteB));
    }
    if (req.http.host ~ "csite.example.com$") {
        return(vcl(siteC));
    }
    // Main site processing ...
}

このようなVCLを使うことでラベル機能を使うことが出来ます。

なお、コマンドの先頭に「-」をつけることでそのコマンドが失敗しても処理を続行することができます


起動に失敗する
vcl.load nf /etc/varnish/notfound.vcl
 
起動に失敗しない
- vcl.load nf /etc/varnish/notfound.vcl

varnishdのパラメータ追加(-x (parameter|vsl|cli|builtin))
これは何かしらの動作がというわけではなくて以下の情報が表示されるコマンドです

parameter
起動パラメータ(-p)の情報(デフォ値など)

vsl
vslのタグや出力フォーマットの説明

cli
varnishのcli(vcl.listなど)の説明を出力します

builtin
builtin.vclを出力します

HTTP/2がより使えるようになりました
5.0.0のHTTP/2は正直検証環境でも使うには辛いものだったのですが(POST投げると落ちるなど)
5.1.1では一部気をつけるポイントはあるものの検証環境で使えるぐらいには動きます。
また、HTTP/2関連は5.1.1リリース後も積極的にバグ修正が行われており、もし使いたい場合はこの記事で紹介したpkg-varnish-cacheを使って最新のコードで試すことをおすすめします。
なお、気をつけるポイントですが以下のとおりです。

  • 転送サイズ(varnishncsa %I %Oなど)などの統計がすべて0 #2238
  • bodyがあるリクエストでcontent-lengthがある場合でもTransfer-Encoding: chunkedを付与する #2247
  • クッキーの畳み込みを行わないのでVCLでクッキーの操作を行う場合に問題がある #2291 #2300

です。
統計については現時点ではどうしようもないのですが、ほかについては以下のVCLで一旦回避可能です。
もちろん修正された場合は不要となります。


sub vcl_recv{
  if(req.http.cookie){
    // temporary...
    // https://github.com/varnishcache/varnish-cache/issues/2291
    // https://github.com/varnishcache/varnish-cache/issues/2300
    std.collect(req.http.cookie);
    set req.http.cookie = regsuball(req.http.cookie,", ","; ");
  }
  if(req.proto ~ "HTTP/2"){
    if(req.http.content-length){
      // temporary...
      // https://github.com/varnishcache/varnish-cache/issues/2247
      unset req.http.content-length;
    }
  }
}

なお上記で行っているクッキーの畳み込みですが、もしESIを利用していない場合はHTTP/2に限定しても問題ありません。
他の注意点としてはPRIV_TASK/PRIV_TOPを利用しているvmodについては現時点では避けておいたほうが無難です。(HTTP/1では問題ありません)
またHTTP/2関連のパラメータとして以下が追加されています

  • h2_rx_window_increment
  • h2_rx_window_low_water

デフォルトは10MBで十分大きいので特に変更する必要ははなさそうですが、
大きなPOST/PUTを受ける場合は大きくしても良いかと思います。

即処理を終了するためのreturn(fail)が追加されました
これはどのvclアクションからも呼び出すことができます。
なおfailの後はvcl_synthがコールされますが、デフォルトでresp.statusには503がresp.reasonにはVCL failedが入っていますので、特に操作をしない場合はクライアントからは503が見えます。
なおvcl_synth内でfailを呼び出した場合は接続をアボート(即切り)します。

vcl_backend_responseでreturn(pass(DURATION))が追加されました
要はhit-for-passです。
TTLを同時に指定することができるので以前より指定しやすくなったので便利かと思います。
この辺(HFP等)わかりづらいとおもうので動きの解説記事をそのうちかきます・・

vsl queryでvxidの指定ができるようになりました
vxid(x-varnishレスポンスヘッダ)はリクエスト毎に発行されるので当然ながら事前にわかりません。
ヘルスチェックなどはvxid=0で実行されるのでそれの絞込ぐらいにしか使えないのかというとそうではなく
varnishncsaなどのlog系オプションの-dと組み合わせることで強力に使用できます。
varnishのログはメモリ上(VSM)に保存されるのですが、これはリングバッファのため古いログも多少残っています。
-dオプションは残っているログの先頭から出力するオプションのため、リクエストを行った後に取得したvxidを指定することでvarnishの挙動の確認を行うことが容易にできます。

fallback directorにstickeyオプションを追加しました


new fb = directors.fallback(sticky = true);

fallbackのdefaultの挙動では優先度の高いバックエンドがsickになった場合は当然fallbackします。
今回のstickeyオプションを指定するとこの優先度の高いバックエンドがhealthyになったときの挙動が変わります。
指定がない場合は優先度の高いバックエンドが選択されますが、指定がある場合はそのまま今繋いでるバックエンドを使用し続けます。
この動作は順繰り行われ、一番優先度の低いバックエンドがsickになった場合は再度先頭から評価されます。

起動時にvmodのバックアップを行うようにしました
これはVarnishの起動しているときにvmodの差し替えが行われて、その後の操作(reloadなど)でおかしくなることがあったので、使うvmodについてはバックアップを取るようになりました。

IPアドレス同士の比較ができるようになりました
vmod_stdにgetenvとlate_100_continueが追加されました

仕様変更

vcl_dirはvcl_pathに変更されます(起動パラメータ)
vmod_dirはvmod_pathに変更されます(起動パラメータ)
req.ttlは廃止予定です
beresp.storage_hintは廃止予定です
完全に同じものではないのですがberesp.storageで代替可能です。
レスポンスコードを1000以上でも指定できるようにしました
これはあくまでもVCL中で使うためのもので、実際にレスポンスされるときは1000以上の桁は削られます。
要はreturn(synth(1000))とかで指定しておいて、vcl_synthで処理するのに使う感じです。
DURATION型をBOOL値として使用することができるようになりました
0以下はfalseでそれ以外はtrueです
TIME型にDURATIONを加算・減算できるようになりました
REAL型にINTを加算・減算できようになりました

パラメータの追加

ban_cutoffが追加されました(起動パラメータ)
req.storageが追加されました
これはrequst bodyを保存するのに使用されます。
未指定の場合はTransientが使用されます。

バグ修正

基本的には4.1.4/4.1.5で修正されたものが大きいものだったので割愛します。


2月 102017
 

4.1系の最新版の4.1.5がリリースされました。 [changelog] [公式のリリース文]

公式でも触れられてる通りほぼバグフィックス(あとドキュメント周り)なのですが、1点パフォーマンスに影響する修正があります。
個人的に重要かなと思うのは#2106の修正です

バグ修正

workspaceが溢れた場合にpanicしていたのを修正 #1834

Basic認証でAuthorizationのフォーマットがおかしい場合varnishncsaでデコードできない問題の修正 #2148

VCLでバックエンドの比較が動いていなかったのを修正 #2168

VSMの使用状況のカウンタ(vsm_free)がおかしかったのを修正 #2188

ESIのincludeでパスが存在しない場合にpanicしたのを修正 #2197
「http://foo/」の場合は問題なかったのですが「http://foo」の場合は今までpanicしていました
その修正になります。

INT/REAL型において「-」をパースできなかったのを修正 #2167
要は-10とかを扱えるようになりました。

beresp.backend.ipが本来使用できないbackend_errorで呼び出すとpanicしたのを修正 #1865
backend_responseでのみ利用できるように修正されました

CNT_Requestでパニックしていのを修正 #2106

仕様変更

バックエンドへの接続にNagleアルゴリズムを使っていたのをやめました #2134
クライアントとの通信はもともとTCP_NODELAYだったのですがバックエンドとの通信はTCP_NODELAYを指定していませんでした。
キャッシュが出来ないオブジェクト(pass)の場合だと多少効いてくるのではと考えています。

改善

devicedetect.vclをアップデートしました(bot情報)


12月 022016
 

4.1系の最新版の4.1.4がリリースされました。 [changelog] [公式のリリース文]
主にバグ修正とドキュメントの改善ですが
1件すごくタイムリーなバグ修正が存在します。
また、今回のリリースで4.0.xがEOLになりました。

バグ修正

バックエンドの現在の接続数のカウンタが機能していないのを修正 #2011

ラウンドロビンDirector利用時にクラッシュすることがあるのを修正 #2024

フェッチ時にワークスペース・ストレージ確保失敗するとリークする可能性があったのを修正しました

return(pipe)時にstd.cache_req_bodyが機能しないのを修正 #1881

vmod_named利用時にVBE_Deleteでpanicすることがあるのを修正しました #2008
コードの修正を見た感じnamedに限らずに動的にバックエンド定義をUpdateしていくようなDirectorの場合に問題が起きそうです。

エラーなどで起動できなかった場合にvsmファイルが残っていたのを修正しました #2115

keepalive時に複数のrangeリクエストが来た場合に先頭リクエスト以外をしばらくブロックすることがあるのを修正しました #2035

バックエンド選択時に稀にpanicするのを修正しました #2027

時刻が逆行(STEP)した場合に子プロセスが再起動する場合があるのを修正しました #1874
うるう秒もありますのでこのあたり注意しておいたほうが良いと思います。
条件としてはセッションがクローズ(close)されるタイミングの時刻がセッション開始時刻(open)が早くなっていた場合です。
Varnishのこの時間の精度はナノ(clock_gettime/CLOCK_REALTIME)もしくはマイクロ秒(gettimeofday)なので
うるう秒で23:59:58->59->59->00のように59を繰り返す場合(STEP)でリクエスト自体を1秒未満で処理していると引っかかる可能性があります。
そのため、今回のうるう秒でSTEP動作をする可能性がある場合は強くアップデートを勧めます。
なお5.0.0も影響を受けます。今のところ5.0.1がリリースされる気配はないのでSLEWで動かすか独自で現時点のmasterのものをビルドするかをおすすめします。(4.0.xは影響なさそうです)
また、この問題の解決のためにclock_stepといパラメータが追加されています。

機能強化

varnishhistの表示にy軸が追加されました
5.0.0のhistと同じ表示です。

仕様変更・追加

varnishtestで外部のコマンドを実行するfeature cmdが追加されました。
すでにあるshellコマンドとの違いですが、shellの場合はその実行結果でテストが成功・失敗しますが
feature cmdの場合はテスト自体が実行されるかされないかです。
混在環境(OSやCPU)で特定環境のみのテストを行う際に便利に使えると思います。

varnishtestのresp.msgはresp.reasonに変更されました

clock_stepが追加されました
時刻同期で一気に時刻が変更(STEP)された場合の許容秒数です。
デフォルトは1秒です。

thread_pool_reserveが追加されました
重要なタスクのために予約されるスレッド数です。
例えば、クライアントの処理でスレッドを使い尽くした場合でもreserveされているスレッドがあればバックエンドの問い合わせが可能です。
この値は引き上げるとクライアント処理で使われるスレッド数が少なくなるため注意する必要があります。
あくまで一気にリクエストが来てスレッドが足りなくなった場合に発動するものなので、普段から適切なスレッド数を指定していればそこまで問題無いと思います。
デフォルトは0(auto)で、thread_pool_minの5%が自動的にセットされます。

パッケージ構成が変更されました
5.0の構成とおなじになりました。(varnish = varnish + libvarnishapi + varnish-doc)
そのためそのままapt-get installで更新しようとすると失敗します。
一度4.1.3までのバージョンをremoveしてアップデートするのをおすすめします

その他変更

ドキュメントの改善やRaceコンディションで起きる幾つかのバグが修正されています。


10月 032016
 

二年ぶりぐらいにメジャーバージョンが更新されました。[公式リリース] [ダウンロード]
今回の目玉機能としてHTTP/2対応とDirectorのConsistent Hash対応があります。
なにはともあれ、とりあえずHTTP/2を使うセットアップをしてみましょう。

Hitch1.4.0+Varnish5でHTTP/2を使う

Varnishはよく知られてるようにHTTPSに対応していません。
HTTP/2に対応したこのバージョンにおいても、やはり本体では対応をしていません。
そのため通常のブラウザからVarnishに対してHTTP/2にアクセスするにはTLSを解かなくては行けません。
今回はVarnishSoftwareが提供しているHitchを利用します。
なお、HTTP/2を利用するには1.4.0以降のバージョンが必要です。
また、一部ディストリビューションではパッケージが提供されていますが、私が利用しているUbuntu 16.04向けのパッケージはなかったのでソースからbuildしていきます。

Hitchのインストール
公式手順を参考に行います


sudo apt-get install libev-dev libssl-dev automake python-docutils flex bison pkg-config
git clone https://github.com/varnish/hitch.git
cd hitch
./bootstrap
./configure --prefix=/opt/hitch/
make
sudo make install

これだけです。(prefixはお好きなところにでも)
なお、HTTP/2を使うにはNPNもしくはALPNのサポートが必要です。
NPNはOpenSSL1.0.1、ALPNの場合は1.0.2が必要ですが、既にChromeでは今年の6月ごろにNPNでのHTTP/2サポートは打ち切られALPNのみでのサポートとなりました。
そのため実質HTTP/2を利用するにはALPNをサポートしている必要があります。
とりあえず確認する程度であれば、FireFox49はNPNでも接続できるので1.0.1でも問題はないです。

Hitchの設定


HTTPS:443           HTTP:80
   ↓               ↓
Hitch:443--(localhost:81)-->Varnish:80
                 ↓
                Origin

今回はこんな感じで構成します。
まずはHitchの設定です。


#/etc/hitch/hitch.conf
frontend       = "[*]:443"
ciphers        = "ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:EECDH+HIGH:EDH+HIGH:HIGH:+3DES:!RC4:!MD5:!aNULL:!eNULL:!LOW:!EXP:!PSK:!SRP:!DSS:!KRB5:!DH"
backend        = "[127.0.0.1]:81"
write-proxy-v2 = on
workers        = 2
backlog        = 1024
keepalive      = 3600
syslog         = on
user           = "nobody"
daemon         = on
alpn-protos    = "h2,http/1.1"
pem-file       = "/etc/hitch/******.pem"

ciphersとかは割と適当ですがきちんと設定したい人はこちらで考えると良いかと思います。
なお、hitchのpem-fileは
秘密鍵 + 証明書 + 中間CA証明書 + dhparam
です。
Let’s Encryptでやる場合は
privkey.pem + fullchain.pem + dhparam
になります。
また、どうやって複数のvhostsに対応するのかというとpem-fileを列挙します。
ちなみにデフォルトのものは最後に定義されたものになります。
Hitchの起動


/opt/hitch/sbin/hitch --config=/etc/hitch/hitch.conf

次はVarnishの設定です。
Varnishの設定
まずはListenの指定をしましょう。
ポート80で通常のHTTPを受付して81でPROXYプロトコルで受付します。
そのための設定はこのような感じです。


-a :80 \
-a 127.0.0.1:81,PROXY \

また、HTTP/2はデフォルトでは有効にされていません。
そのためfeatureでhttp2を指定する必要があります。
varnishadmから設定する場合は


root@proxy02:~# varnishadm param.set feature +http2

root@proxy02:~# varnishadm param.show feature
feature
        Value is: +esi_disable_xml_check,+http2
        Default is: none

        Enable/Disable various minor features.
           none                       Disable all features.

        Use +/- prefix to enable/disable individual feature:
           short_panic                Short panic message.
           wait_silo                  Wait for persistent silo.
           no_coredump                No coredumps.
           esi_ignore_https           Treat HTTPS as HTTP in
                                      ESI:includes
           esi_disable_xml_check      Don't check of body looks like
                                      XML
           esi_ignore_other_elements  Ignore non-esi XML-elements
           esi_remove_bom             Remove UTF-8 BOM
           https_scheme               Also split https URIs
           http2                      Support HTTP/2 protocol

です。
起動パラメータで指定する場合は


-p feature=+http2 \

を追加すれば良いです。
これで動作します。

なお、後述しますが絶対本番環境では行わないでください。

それでは、HTTP/2での動作のさせかたを紹介したところで、いつも通り新機能などの紹介を行います。

全体的な話

過去のメジャーバージョンアップを振り返ってみると
2.1->3.0

  • VMODのサポートとVCL文法の整理

3.0->4.0

  • リクエスト・フェッチ・レスポンスといった一連の動作をClient/Backendスレッドに分割
  • VCLにバージョン番号付与とスレッド分割に対応するための変更

4.0->4.1(マイナーバージョンアップですが)

  • PROXYプロトコルのサポート
  • 内部処理にフックできるようなしくみの追加

4.1->5.0

  • HTTP/2の実験的サポート
  • shard director(consistent-hash)対応
  • バックエンドフェッチがPROXYプロトコルサポート
  • 別VCLを動的リンクして使うlabel機能のサポート

こうしてみると4.0の頃からHTTP/2の準備を着実にすすめていたのがわかるかと思います。
また、嬉しいことに5.0では3.0->4.0のときのような破壊的なVCLの変更はありません。
もちろん幾つかのVCLの変更はあります。
しかし大抵の場合は変更せずとも動き、もしくは少しのreplaceで済んでしまいます。
また、statsの項目も削られたものはあるものの出力フォーマットは変わっておらず、
LOGについてもHTTP/2関連の追加はあるものの大きな変更はなく、
大抵のVMODもリビルドすれば動き、累積バグは修正されています。
そのため、4.1で動いていた監視や周辺ツールはほぼ変更なしで動き既存の資産を使いやすいと思います。
10/03時点で知り合いのサイトの本番に投入して、20日程度経過していますが大きな問題もなく動作しています。
当然メジャーバージョンアップのため慎重な検証は必要ですが、3.0->4.0のときのような苦しみはなく
HTTP/2を使わないのであれば、どちらかと言うと4.0->4.1のときのような変更と思ってもらえればよいかと思います。

新機能

HTTP/2のサポート(experimental)

先程も紹介しましたがHTTP/2の極めて実験的(Very Experimental)なサポートを行っています。
有効にする場合は起動パラメータ、もしくはvarnishadmでfeatureパラメータを+http2に指定します。
なお、現時点で私が確認しているバグだと回避不能でリクエストで容易にクラッシュを起こすものが1件、回避可能なものが1件、仕様なのか判断できないが実装漏れっぽいのを1件見つけてます。(また今度泣きながら英語書きます)
そのため決して本番に投入することはおすすめしません。
しかし実際に触ってみていろいろバグを見つけて報告するとよいかと思いますので触ってみてほしいところです。

vmod-directorでsharedをサポート

consistent-hashのサポートです。
元々はUPLEXが提供していたvslpを公式に持ってきた形になります。
consistent-hashについてはぐぐるといろいろ出てくるとおもうので詳しくは割愛します(参考
今まではbackend数に変動があった場合には全体で再計算が走るのでキャッシュヒット率が全体で落ちる問題がありましたがこれを使うことで解決することが出来ます。
特に複数台のクラスタで複数段のキャッシュを組んでる環境ではかなり効いてくると思います。

VOID shard.set_rampup(DURATION duration=0)
0秒以上を指定した場合、バックエンドがhealthyになった場合にいきなり100%のトラフィックを流すのではなく、指定秒数(duration)の間に徐々にトラフィックを流していくようになります。(slow start)

BOOL shard.add_backend(BACKEND backend, STRING ident=0, DURATION rampup=973279260)
バックエンドを追加します。
identはノードの識別子で、デフォルトではバックエンドの名前を使うようになっています。
通常は使うことはないと思いますが、weight的な指定をしたいときなどに使うと良いかもしれないです。
rampupはサーバ個別に指定する場合に指定します。(973279260はmagic valueでset_rampupで指定された値を使うようになります)

BOOL shard.remove_backend(BACKEND backend=0, STRING ident=0)
バックエンドを削除します。
backendを指定した場合は一致するすべてが削除されます。

BOOL shard.clear(PRIV_TASK)
全てのバックエンドを削除します。

VOID shard.set_warmup(REAL probability=0.0)
指定の確率で次の代替バックエンドにリクエストがいくようになります。(0.5=50%)

warm

要はそのバックエンドが死んでキャッシュが落ちたとしても、
代替バックエンドがキャッシュをある程度持っている状態なのでダウン時の影響をより減らすことができるようになります
(ただし当然ながらキャッシュの二重持ちが起きるので空間効率は悪くなります)
なお、rampup期間中のバックエンドはwarmupの対象外になります。

BOOL shard.reconfigure(INT replicas=67, ENUM {CRC32,SHA256,RS} alg=”SHA256″)
consistent-hashで使うハッシュリングを作ります。
replicasは1つのバックエンドが仮想的に何個のバックエンドになるかです。(consistent-hashの仮想ノード)
algはどのハッシュ関数を使ってハッシュリングに配置していくかです。
なお、shardディレクターを使う場合は必ず一度は呼び出す必要があります。
イメージ的にはcommitと思ってもらえれば良いかなと思います。

BACKEND shard.backend(ENUM {HASH,URL,KEY,BLOB} by=”HASH”, INT key=0, BLOB key_blob=0, INT alt=0, REAL warmup=-1, BOOL rampup=1, ENUM {CHOSEN,IGNORE,ALL} healthy=”CHOSEN”)
バックエンドを選択します。

by=HASH(デフォルト)
vcl_hashで生成したhash値を使用して振り分けサーバを決めます。

by=URL
req.url/bereq.urlを使用します。

by=KEY
keyで指定したINT数値を使って振り分けします。
例えばcookieをもとに振り分けしたい場合は


shard.backend(by=KEY,key=shard.key(bereq.http.cookie))

といった感じです。

by=BLOB
key_blob指定したblobを使って振り分けします。
通常は使うことはないと思います。
また、blob全体を使うのではなく先頭4バイトを使用します。

key
by=keyを指定した場合に指定する数値です

key_blob
by=blobを指定した場合に使用するblobです

alt
指定した場合はn番目の代替バックエンドを選択します。
どのようなときに使うかというと何かしらのエラーが起きて別のバックエンドを選択したい場合(restart/retries時)に使用します。
alt=req.restart or bereq.retriesと指定しているとリスタート/リトライのたびに別のバックエンドを選択することが出来ます。
なお、rampup/warmupはaltが0のときのみ有効で、1以上のときはaltが優先されます。

warmup
代替サーバが選択される確率を指定します。(-1,0~1)
-1の場合はset_warmupで指定した値を使用します。

rampup
rampup機能を使うかどうかです。

healthy=CHOSEN(デフォルト)
healthyなバックエンドを選択します。
altが0以上の場合はバックエンドのhealthyを無視してn番目の代替バックエンドを選択します。
ドキュメントにはthen return the next healthy backend.とあるのですが、コードと実際の動作を見る限りだとalt指定時の代替バックエンド選択ではhealthyかの評価をしていません。

healthy=IGNORE
helathyを無視します。
altを指定した場合はhealthyを無視した状態で代替バックエンドを選択します。
またrampup/warmupは機能しません。

healthy=ALL
基本的にはCHOSENと同じですが、altが0以上のときに代替バックエンドを選択する際にもヘルスチェックをします。

ちょっとややこしいのでまとめてみました

healthy alt==0 alt>0
CHOSEN ヘルスチェックを行う ヘルスチェックを行わない
IGNORE ヘルスチェックを行わない ヘルスチェックを行わない
ALL ヘルスチェックを行う ヘルスチェックを行う

 

INT shard.key(STRING string, ENUM {CRC32,SHA256,RS} alg=”SHA256″)
指定した文字列を指定したハッシュアルゴリズムを通したときのINT値を得ます。
例えばSHA256は256bitなんですが、32bit分だけ返します。
この関数はshard.backendをby=KEY指定で使う場合に使用します。

で、実際のところどうやって使うかというとこんな感じです。



sub vcl_init {
  new ws_cache = directors.shard();
  ws_cache.set_rampup(10s);
  ws_cache.add_backend(ws01);
  ws_cache.add_backend(ws02);
  ws_cache.add_backend(ws03);
  ws_cache.add_backend(ws04);
  ws_cache.reconfigure();
}

sub vcl_recv {
  //x-varnish-hashにはユーザIDとかそんなのが入ってる
  ...
  set req.backend_hint = ws_cache.backend(by=KEY, key=ws_cache.key(req.url + ":" + req.http.host + ":" + req.http.x-varnish-hash));
}

 

INT,BACKEND型がBOOLで評価できるようになりました

こういうことができるようなります。


sub vcl_recv {
  if(1){
    set resp.http.foo = "1";
  }
  if(req.backend_hint){
    set resp.http.bar = "1";
  }
}

INT型で0はfalseになります。
また、BACKEND型では割り当てられていない場合はfalseになります。

別VCLを動的リンクして使うlabel機能のサポート

いままで異なるVCLを読み込む方法としてはincludeがありました。
これは単純にincludeを記載した場所に指定したVCLを展開するものでした。
そして今回追加されたlabelは別のコンパイルされたVCLを動的リンクします。
とりあえず使い方を紹介します

まずラベルを持つVCLをloadします


varnishadm vcl.load a_example_net /etc/varnish/a_examplet_net.vcl
varnishadm vcl.load b_example_net /etc/varnish/b_examplet_net.vcl
varnishadm vcl.load c_example_net /etc/varnish/c_examplet_net.vcl

varnishadm vcl.label vcl_a_example_net a_example_net
varnishadm vcl.label vcl_b_example_net b_example_net
varnishadm vcl.label vcl_c_example_net c_example_net

default.vcl


vcl 4.0;
//最低限1つはバックエンドがないと動かないのでダミー
backend default { .host = "127.0.0.1"; }

sub vcl_recv {
  if(req.http.host ~ "a\.example\.net$"){
    return(vcl(vcl_a_example_net));
  }
  if(req.http.host ~ "b\.example\.net$"){
    return(vcl(vcl_b_example_net));
  }
  if(req.http.host ~ "c\.example\.net$"){
    return(vcl(vcl_c_example_net));
  }
  return (synth(403));
}

a.example.netの場合はvcl_a_example_netというラベルを持つVCL(/etc/varnish/a_examplet_net.vcl)を使うようになります。
これは何に使えるかというとCDNのMWとしてVarnishを使っていたりして外部の人にVCLの記述を解放したいけど
VCLがそれぞれ干渉しないようにしたい場合に使えます。
vcl_a_example_netの中からb.examplet.netに関する処理を書いてもそもそもそういうリクエストが割り振られないからです。
また、今回はreq.http.hostで分けましたが、もちろん他のキーで振り分けを行うことが出来ます。

なお、設定を更新する場合は再度vcl.loadしてvcl.labelを叩く感じです


varnishadm vcl.load a_example_net_1 /etc/varnish/a_examplet_net.vcl
varnishadm vcl.label vcl_a_example_net a_example_net_1

ちなみにvcl.listを見てみるとこんな感じになります


# varnishadm vcl.list
active      auto/warm          0 boot
available   auto/warm          0 a_example_net
available  label/warm          0 vcl_a_example_net -> a_example_net_1
available   auto/warm          6 a_example_net_1 (1 label)

vcl_a_example_netがa_example_net_1になっているのがわかると思います。
また、reloadを行った場合はラベルの先のVCLについてはreloadされませんので注意が必要です。

バックエンドフェッチがPROXYプロトコルサポート

バックエンドの定義に.proxy_header=[プロトコルバージョン];を指定することでproxyプロトコルが使えるようになりました。


backend ws01 {.host = "192.168.1.1";.proxy_header = 1;}//PROXYプロトコルv1
backend ws02 {.host = "192.168.1.2";.proxy_header = 2;}//PROXYプロトコルv2

varnishtestの強化・変更

HTTP/2のテストやproxyプロトコルのサポートが行われました。
また、resp.msgはresp.reasonへ
semaはbarrierに名前が変更されました。

std.integerがREAL型の数値をパースできるようになりました

1.2といったものはもちろん1E+2みたいな表記もパースできるようになりました。
もちろんINT型になるように小数点以下は削除されます。

std.logがvcl_initで動くようになりました

 

varnishhistにy軸の目盛りが付きました

 

varnishstatの-fオプションがglob(7)の形式が使えるようになりました

 

POSTをキャッシュできるようになりました

正確にはVCLを正しく書けばPOSTもキャッシュできるようになったということです。(もちろんデフォルトではされないです)
内部的な変更としてbodyを常にバックエンドに送るように変更されており、これによりGETとbodyを使うPOSTなどと扱いが変わらなくなったためです。
とはいえGETはbodyがいらないのでbuiltin.vclでは削除するようになっています。


sub vcl_backend_fetch {
    if (bereq.method == "GET") {
        unset bereq.body;
    }
    return (fetch);
}

もし、自身のVCLがbuiltin.vclを通らない(return)している場合はunset bereq.bodyを追加する必要があるでしょう。
また、POSTのキャッシュができるようになったとはいえbuiltin.vclではやはりpass動作になっています。
試していませんがここをhashにすればキャッシュできると思いますが、オブジェクトのハッシュを作る際にbodyを評価していないため
ここらへんはbodyに対してアクセスできるvmodを使って中身を精査してハッシュを作る必要があります。

仕様変更

statsからn_waitinglistがなくなりました

VCL名に指定可能な文字が制限されました
わざわざvcl名を使っている人はそんなにいないと思うんですが
[A-Za-z][A-Za-z0-9_-]*にマッチする名前じゃないとだめになりました。

すべてのVCLオブジェクトは使う前に定義しないといけなくなりました
backendとかaclとかそういうのですね、むしろ今まで意識してなかった(いつも先頭に持ってきてた)ので
え、いけたの?ぐらいです。

pass(uncacheable)されたリクエストではcache-control/ExpiresのTTLはパースされなくなりました
今まではpassした場合でもTTLのパースはしていたのですがされなくなったので、対応するログも出力されなくなりました。

-T/-Sを無効化する場合は明示的にnoneを指定する必要があります

パラメータの変更

追加:ban_lurker_holdoff
効率的でないbanの指定などでban.listが肥大化した場合、ban_lurkerスレッドとの潜在的な競合によりlookup性能が悪化するケースがありました。これを防ぐためにsleepを入れるようになってその値です。
デフォルトは0.1sとban_lurker_sleepと同じです。

追加:session_max
session_maxは削除されました。
もともと4.0のリリースで効果がなくなったものです。
なお、将来的に復活する可能性はあるとのことです。

名前の変更:vcl_dir->vcl_path / vmod_dir->vmod_path
まだどちらも使えますがおそらく将来的に_dirのほうはなくなります。
また、:で分割して複数のpathを指定できるようになりました。
vcl_pathのデフォルトは/etc/varnish:/usr/share/varnish/vclとなっていますが
これはincludeなどでVCLを読もうとした際にまず/etc/varnishを探索し、
存在しない場合は/usr/share/varnish/vclも探すといった動きになります。
また、/usr/share/varnish/vclにはデバイスを判定するためのdevicedetect.vclが入っていています。

builtin.vclの変更点

GET時にbereq.bodyのunset
これは先程「POSTをキャッシュできるようにしました」で説明したとおりです。

hit-for-passの取扱について
今まではreturn(pass)したりそもそもキャッシュできないオブジェクトはhit-for-pass(HFP)としてマークされて
2分間は常にpass扱いとされていましたが、HFPとしてマークしないようにしました。
以下が4.1と5.0のdiffです。


 sub vcl_backend_response {
-    if (beresp.ttl <= 0s ||
+    if (bereq.uncacheable) {
+        return (deliver);
+    } else if (beresp.ttl <= 0s ||
       beresp.http.Set-Cookie ||
       beresp.http.Surrogate-control ~ "no-store" ||
       (!beresp.http.Surrogate-Control &&
         beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
       beresp.http.Vary == "*") {
-        /*
-        * Mark as "Hit-For-Pass" for the next 2 minutes
-        */
+        # Mark as "Hit-For-Pass" for the next 2 minutes
         set beresp.ttl = 120s;
         set beresp.uncacheable = true;
     }

VCLの変更点

backendsの定義に.proxy_headerが追加されました
新機能で触れたものです

vcl_recv:returnにvcl(label)が追加されました
新機能で触れたものです

vcl_recv:rollbackが削除されました

vcl_hit:return(fetch)が削除されました
元々4.1の時点でfetch->missに変更するようにアナウンスが出てたものですが、このタイミングで削除さらえました。

vcl_backend_*:remote.ip, client.ip, local.ip, server.ipにアクセスできるようになりました

vcl_backend_fetch:bereq.bodyが追加されました
新機能で触れたものです

vcl_backend_error:synthetic()がberesp.bodyに変更されました
こんな感じの表記になります


    set beresp.body = {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + beresp.status + " " + beresp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + beresp.status + " " + beresp.reason + {"</h1>
    <p>"} + beresp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + bereq.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"};

vcl_synth:synthetic()がresp.bodyに変更されました

vcl_deliver: obj.ttl, obj.age, obj.grace, obj.keepにアクセスできるようになりました(read)

正規表現でmatchした時の結果をBOOLとしてそのままセットできるようになりました


set req.http.foo = req.http.bar ~ "bar";

このような表記ができるようになりました。

アップデート時の注意

パッケージの構成が変更された
元々は

  • Varnish本体
  • libs
  • libs-dev
  • docs

の4種類でパッケージが別れていたのですが

  • Varnish本体+lib+docs
  • dev

の2種類に変更されました。
そのためインストールするときに失敗する場合は一度既存パッケージをアンインストールしてみてください。

VMODのABIが変更されたのでリビルドが必要
VMODのABIが変更されたので使用しているVMODについてはリビルドが必要です。

環境によってはreloadに失敗するかも
これは私が引っ掛かった問題+私のsystemd力が低いのでパッと解決策が思いつかなかった問題なのですが
VCL名が仕様変更(先頭文字はアルファベットである必要がある)されたけど、reloadスクリプトがそれに追随していないように見えます。
Xenial(systemd)でリロードしようとするとこの部分のLOGNAMEが入らないため先頭がuuidになります。
uuidは数字を含むためreload時にVCL名の仕様変更に引っかかってしまう感じです。
とりあえず先頭にreload_とかつけとけば回避はできるのでもし引っかかった場合は


-    vcl_label="${LOGNAME}${LOGNAME:+_}${uuid}"
+    vcl_label="reload_${LOGNAME}${LOGNAME:+_}${uuid}"

こんな感じで修正すると良いかなと思います。
また、私がRHEL/CentOSの環境を持っていないので試していませんが、おそらくRHELでも同様の問題がおきます。(:は使えない)

その他変更

累積バグが直ってたり、細かい改善があったりします。


7月 132016
 

Varnish4.1.3がリリースされました。
バグフィックスが主でアップデートを強く進めますが、他にも結構使える新機能が増えています。

ダウンロードはこちら
changes

新機能・変更

varnishncsaにバックエンドに問い合わせにいったものだけを表示するオプションが追加されました(-b)
今までは幾つか絞込の指定をしないと取れなかったのですが-bだけで済むので便利です
また同時にクライアントで絞り込んで表示するオプション(-c)も追加されています。(デフォルト動作)
ちなみに-b -cを同時に指定することも出来ます。

VSMを開放する際にどれだけ待機するかのパラメータが追加されました(vsm_free_cooldown)
今までは60秒でハードコードされていました。デフォルト値も60秒です。
通常の使い方ではいじることはないと思いますが、かなり激しいログの書き込みをするとかの環境だといじる機会はあるかもしれないです。

varnishlogの出力でバックエンドのトランザクションが開始する際にBackendStartが入るようになりました
クライアントのReqStartと対になるものです。

varnishncsaの-Fで指定できるものが増えました
3つ増えました。
 Varnish:side
 先ほど紹介した-b -cオプションに伴って増えたものです。
 バックエンドで絞込をしている場合はbを、クライアントからの表示の場合はcを出力します。
 -b -cを両方指定している場合に使うとどちらのログなのかがわかって良いと思います。
 Varnish:vxid
 vxidを出力します
 VSL:tag VSL:tag[field]
 指定したタグ(TimeStampなど)を出力します。
 基本vsl-queryと同じ指定ですがヘッダ指定は出来ません(VSL:ReqHeader:User-Agentみたいなのは出来ない)
 これできるといいなーと思うのでp-r書こうかな・・
 ちなみに複数引っかかる場合は最初のを出力します。
 例えばVSL:TimeStampを指定した場合は毎回Startのタイムスタンプが表示されます

TCP Fast Openをサポートしました
デフォルトはoffです(tcp_fastopen)

varnishtestに新しい同期用の命令を追加しました(barriers)
semaより使いやすいです

varnishstatで12桁以上の数値を出力する場合は丸めるようにしました#1855
CURRENTの表示でK/M/G/Tのように単位がつけられないカウンタは” %12ju”だったのですが12桁を超える場合は1000で割って” %9ju…”という表示になります。
コードを見た限りではxml/jsonで出力するときには影響しないのでそこまで気にすることはないかなと思います。

バグ修正

今回はかなりバグ修正が多いので幾つかピックアップして紹介します。
特にESI周りの修正が多いのでESIを使っている場合はアップデートすると良いと思います。

varnishncsaで-Lオプションが受け付けられないようになってたのを修正しました#1994

たまにAgeとAccept-Rangesヘッダが複数レスポンスされることがあるのを修正しました#1955

同名のVCLでvarnishをstop->startを繰り返すとその後segfaultを繰り返す事があったのを修正しました。#1933
dlopenのリファレンスカウンタが信用ならなかったみたいです。
vcl名は変わらないのですが、コンパイルしたvgc.soのパスに現在時刻(ナノ秒)が付与されるようになりました。
バッドアイデアとメッセージにあるので割と苦悩した感じがあります。

vcl_init/finiでstd.log/std.syslogを利用するとクラッシュするのを修正しました#1924

VSMのサイズが小さくてオーバーラン検出に問題が合ったのを修正しました#1873
varnishncsa等でオーバーランした際にもクラッシュしなくなりますが
オーバーランしたらvsmサイズを増やしたほうが良いでしょう。
それでも困るようであれば今回追加されたcooldownの調整も考えると良いかも

-Cオプション利用時にテンポラリで使用したディレクトリを消していなかったのを消すようにしました#1869

POSTリクエストをpipeで繋いだ場合に1分待たされることがあるのを修正しました#1806
4.1からはPOSTリクエストのデフォルトの動作がpassになっているので通常の場合は問題ないのですが
以前からの設定を使いまわしてる人などは割りとハマるかもしれないです。

バックエンドの接続数を示すカウンタを復活させました#1725
バックエンド周りのコード修正した際に意図せず消えたカウンタを復活させました。
確かに消えてました・・気づかなかった・・

次は5.0.0かなー
楽しみですね


3月 072016
 

Varnish4.1.2がリリースされました。
バグフィックスが主ですが、一部新機能があります。

ダウンロードはこちら
changes

また2016-03-09 12:00 CET(日本時間 同日20時)からリポジトリの場所が変更になります。
これは去年アナウンスされていたVarnish Cache project autumn cleaningの一環になります。
また、まだドキュメント側は更新されていませんがバグ報告についてもgithubに移行するはずです。

機能追加/改善

REAL型同士で算術演算子を使えるようになりました
4.1.1まではREAL型同士は+以外は使えなかったのですが新たに-*/がサポートされるようになりました。(1.1 – 0.9とかが出来るように)

absoluteURIでhttpsからはじまる場合でもHostをパース出来るようになりました
言葉にするより表のほうがわかりやすいと思いましたので動作パタンを表にしました。

  http://example.com/foo https://example.com/foo
Version req.http.host req.url req.http.host req.url
~4.1.1 example.com /foo https://example.com/foo
4.1.2~(with feature +https_scheme) example.com /foo example.com /foo

PROXYプロトコルに4.1で対応したしといった感じかと思います。
なお、標準ではoffになっているのでfeature +https_schemeを指定する必要があります。

VMODでACLが扱えるようになりました
vmodtool.pyを改善して4.0/4.1でソースツリーを共有出来るようにしました
おもにVMOD作成者向け

vmodtool.pyを改善して1つのディレクトリから複数のvmodを作成コンパイル出来るようにしました
varnish-modulesというのが少し前に公開された(Varnish謹製のVMOD集)のですが、これのための対応といった感じです

バグ修正(一部抜粋)

Content-LengthがないHTTP/1.0かつPOST/PUTした場合すぐ400を返すように変更(#1843)
今まではchunkedとして扱ってしまって結果としてtimeoutを待ってましたが400をすぐ返すように変更しました。

フェッチ時(VFP_Push)にworkspaceがオーバーフローした場合panicしていたのをFetchErrorに変更しました(#1739)
panicするほどのエラーではないということで変更です。

hit-for-pass利用時にbodyが空っぽになるケースがあったのを修正(#1858)
本来不要なIMSの評価を行っていたため結果としてbodyが空っぽになるケースがあったのでhit-for-pass時のIMSの評価を辞めました。

ESI利用時にメモリリークするケースがあったのを修正(#1860)
これはAddressSanitizer(ASAN)で検出したのです。(他にも#1852を検出しています)
ASANについては以下を見てみると面白いと思います
CAN WE RUN C CODE AND BE SAFE?

ban-listを回収(ban-lurker)してる際にpanicするケースがあるのを修正しました(#1863/#1864)