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&c=3&b=2
  //  :/?b=2&c=3&a=1
  //out:/?a=1&b=2&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月 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・コミュニティ・会社のネイティブな方の添削・レアジョブの講師の方々などのサポートもあり、私の中では非常にうまくいったんじゃないかなと思っています。
今後も機会があれば、日本に限らず海外の勉強会行ってみたいなーと思います。

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


12月 032013
 

Varnish3.0.5が公開されました。
今回はBugfixですが
varnishlogの-mオプションで動きが変わったため一瞬戸惑うかもしれません。

修正された項目は以下になります。

varnishd

■ESIのパースに失敗した場合に標準出力にメッセージを出していたのをやめました
(Stop printing to stdout on ESI parse warnings)

デバッグの時の消し忘れっぽいですね。

■syntheticの最初のパートでNULLを指定した場合segfaultで落ちるのを修正しました
(#1287)

vcl_error内でstd.filereadを使ってNULLが帰ってきた場合や存在しないヘッダを指定したときなどに出ると思いますが
普通はしないと思います。

■streamを利用した際にContent-Lengthが重複してクライアントに送信されるのを修正しました
(#1272)

重要なFix

■不正なRequestかつvcl_errorでrestartをしている際にクラッシュする問題を修正しました
(#1367 CVE-2013-4484)

この問題はvcl_error内で不正なリクエストをrestartした際に起こる問題です。(リクエスト内容はチケットを参照下さい)
40xや50xを起きた際にrestartを行い別バックエンドなどへのfailoverを行う場合がありますが
その際に不正なリクエストのものをrestartしてしまうとクラッシュします。
バージョンアップでも解決しますが、すぐに行えない場合は以下で回避が可能です


sub vcl_error{
  if (obj.status == 400 || obj.status == 413) {
    return(deliver);
  }
}

このVCLは必ず先頭に書いてください。(vcl_errorが複数あってもOK)
アクションが複数あっても問題ない理由は「同じVCLアクション(vcl_recvなど)を複数定義する」を参照下さい

■クライアントが接続を閉じた後にserver.ipを利用した際にクラッシュする問題を修正しました
(#1376)

varnishadm

■標準入力で渡されたコマンドを適切に扱えなかったのを修正しました
(#1314)

3.0.4(パイプでの渡しが出来ない)


echo vcl.list|varnishadm
200
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,2.6.32-71.18.1.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit
varnish-3.0.4 revision 9f83e8f

Type 'help' for command list.
Type 'quit' to close CLI session.

200
active          0 boot

3.0.5(パイプで渡せる)


echo "vcl.list"|varnishadm
200
active          4 boot

一気にpurgeしたいときとか便利ですね。

varnishlog

■-mオプションで絞り込む際に-c若しくは-bを指定しない場合は両方が指定された扱いとなります
(#1071)

3.0.4(-c/-bを指定しなくてもデータが取れる)


varnishlog -m "RxHeader:Host: xcir.net"
...
   12 RxHeader     c Host: xcir.net
...


3.0.5(指定しないと取れない)


varnishlog -m "RxHeader:Host: xcir.net"
^C

varnishlog -m "RxHeader:Host: xcir.net" -c
...
   16 RxHeader     c Accept: */*
   16 RxHeader     c Host: xcir.net
...

今までリクエストヘッダにHost: exmaplnetが含んでいるものを取りたい場合は
varnishlog -m “RxHeader:Host: example.net”
だけでもとれたのですが、
きちんとクライアント<->Varnish(-c)、それともVarnish<->バックエンド(-b)の通信なのかを指定する必要があります。

次は4.0ですね。VUG8でもいろいろ出ていましたが楽しみです
—–
Varnish Cache 3.0.5


11月 302013
 

少し前にサムネイルの作り方をチームの人に聞かれて教えていたのですが
座標の関係がすらすら言えなかったので備忘録的にまとめてみました。
ついでに他の事もまとめてみました。

サムネイルの座標

サムネイルを使う場面はいろいろあると思うのですが大きく分けると2つあると思います。

・単純に小さくする(例:640×480 -> 320×240)
・指定サイズにする(例:640×480 -> 60×60)

単純に小さくする場合はあまり気にしないのですが
指定サイズに収まるようにサムネイルを作る場合は座標を気にする必要があります。

imtg

例えば、上記の例のように縦長の画像を日記のアイコンに使うような正方形のサムネイルにしたい場合において
できれば顔のある可能性が高いあたりをサムネイルとしたいケースがあります。
その場合は何をどのように指定すればよいでしょうか?

image
使う画像処理エンジンによって、呼び名は変わったりするのですが
基本的には上記の例のような関係性が有ります。
先ほどの縦長の画像の上の方をサムネイルに使いたい場合は、元画像のy座標(Source y)を0や縦幅に対して10%のような指定にするとよいでしょう。

また、これらから分かるようにサムネイルの作成は
元画像(Source Image)から切り抜いた画像(crop)を、新しいキャンバス(Thumbnail Image)に指定の座標にリサイズしながら転送するものです。
言い換えると、ケーキ(Source Image)を切り分けて(crop)、個別の皿(Canvas)に載せる(dest)となります。
(この場合はcropのサイズとdestのサイズは同一)
たまにサムネイルのサイズ(canvas width/height)と転送のサイズ(dest width/height)の関係があれ?となる事があると思うのですが、このように覚えるといいんじゃいかなと思います。

また、imagemagickでこのような位置決めをする際に右上とか右下みたいな指定ができます(gravity)
ただnortheastやらsouthwestみたいな指定で日本人的には直感的じゃないかと思いますので図にしてみました。
gravity

長辺・短辺基準

サムネイルを作る際に長辺基準、短辺基準というのが出てきます。
これはどういうことでしょうか?

長方形の画像を正方形のサムネイルにするというケースで考えてみましょう。
当然、長方形を正方形に変更する場合は潰してしまわないとできません。
しかしサムネイルを作る際は、縦横比を変更せずに(=潰さずに)作ることが多いです。
では、縦横比を変更しないで長方形を正方形にするにはどうすればよいでしょうか?
2つの方法があります。

・隙間が空くことを許容して長方形の長い辺がサムネイルのサイズに合うようにする(=長辺基準
s_5
元画像は640×480で、赤い箇所が隙間です

・切り落とされることを許容して長方形の短い辺がサムネイルのサイズに合うようにする(=短辺基準
s_6
長い辺(横)の両端が切り落とされていることがわかると思います。
これが長辺・短辺基準です。

アニメーションgifのリサイズとパレット

今はどうだかわからないのですが、普通に見えていたのにリサイズしてみたら特定の携帯で色が崩れるというケースがありました。(AU端末)
これはどういうことかというと、パレットの持ち方がアニメーションGIF全体で持っているグローバルパレットから、各フレームで持っているローカルパレットに変わったからです。
特定の携帯では、最初のフレームのパレットのみを使い、それぞれのフレームで持っているパレットを無視するため、アニメーションが虹色に見えるといったことが起こります。
これはリサイズする際にギザギザが目立たなくするためにアンチエイリアス処理が走り、使う色が変わったためにグローバルを諦めローカルにしたためです(wikipedia:アンチエイリアス)
また、パレットがグローバルからローカルに変わると、それぞれのフレームでパレットを持つためファイルサイズが増えてしまいます。
こういうことがあるということを知っておくといいかもしれません。

参照:携帯向けアニメーションgifをimagemagickを使ってリサイズする方法(php)

横幅・縦幅のサイズを2倍にした時のファイルとメモリのサイズ

すごく前に、真顔で聞かれて真顔で返したんですが
縦横サイズを2倍にだったらファイルサイズも2倍だろうと言われました。
面積の計算を思い出してください、4倍です。
実際のファイルサイズは圧縮が効いていたりするので一概に言えませんが2倍ではありません。
また表示する際に端末で使うメモリは、基本的に画素数とその1画素で使うサイズが関係するので
640×480で24bitの場合でファイルサイズが50KBの場合でも900KB以上のメモリを使っていると考えていいでしょう。
偶に倍のサイズの画像をブラウザ上で等倍にする人もいますが、こういうことを頭の隅に置いておくといいと思います。

クオリティ

jpegでは画像のクオリティを指定できますがqualityを10にしたからファイルサイズが1/10になるかというとそうではありません。
qual
ちょうどいい画像がなかったので大昔に描いた画像(88,685byte)を
imagemagickでクオリティを1~100で変化させた時のファイルサイズをとってみました。
比例していないのがわかると思います。
また、画像によって傾向は違いますが大体の場合は90ぐらいまでqualityを落とせば高画質とサイズを両立できると思います。

qualst
またいくつかのクオリティで画像がどのような感じになるかです。(im[quality].jpg)

さらにquality=1の画像をquality=100にしてみました。
im1to100
当然の事ながら綺麗になるわけではありません。
JPEGは非可逆であり失われた情報は残っていません。
しかしファイルサイズは増えてしまいます。(3,525byte -> 23,381byte)
クオリティとサイズの関係は覚えておくといいと思います。

RGBとCMYK

これはサムネイルに限った話ではないのですが
偶にブラウザによっては画像の色がおかしく感じる事があります。
cmyk
大体の場合は色の表現方法がCMYKという印刷用のものになっているケースがです。
WebではRGBが基本なので注意が必要です。

ざっくりサムネイルを作るときに知っておくと便利かなとおもったことを書いてみました。
また思いついたら追記するかもしれません。


6月 192013
 

Varnish3.0.4が公開されました。
今回はほとんどBugFixですが、いくつかの機能改善があります。

公式リリースノート(3.0.4)

バグフィックス

CVE-2013-4090 特定条件でACLで想定外のマッチ・マッチ漏れが起こる
#1312
対象は3.0.3までの全てのバージョンです
引っかかる条件は以下だと思います
・CIDR形式の定義が存在(/8,/16,/24を除く)
・単一のIPアドレスを指定している
・その定義範囲が重複している
こんな感じです
VCLコード


acl foo {
  "127.0.0.2";
  "127.0.0.0"/19; //(127.0.0.1 ~ 127.0.31.254で127.0.0.2を含む)
}

Cに変換したコード(3.0.3)


static int
match_acl_named_foo(const struct sess *sp, const void *p)
{
    const unsigned char *a;
    unsigned short fam;

    a = p;
    VRT_memmove(&amp;amp;fam, a + 0, sizeof fam);
    if (fam == 2)
        a += 4;
    else if (fam == 10)
        a += 8;
    else {
        VRT_acl_log(sp, "NO_FAM foo");
        return(0);
    }

    if (fam == 2) {
     if (a[0] == 127) {
      if (a[1] == 0) {
       if (a[2] == 0) {//ここで本来マッチしなくては行けない127.0.1~127.0.31が排除される
        if (a[3] == 2) {
         VRT_acl_log(sp, "MATCH foo " "127.0.0.2");
         return (1);
        }
        VRT_acl_log(sp, "MATCH foo " "127.0.0.0" "/19" );
        return (1);
       }
      }
     }
    }
    VRT_acl_log(sp, "NO_MATCH foo");
    return (0);
}

Cに変換したコード(3.0.4)


static int
match_acl_named_foo(const struct sess *sp, const void *p)
{
        const unsigned char *a;
        unsigned short fam;

        a = p;
        VRT_memmove(&amp;amp;fam, a + 0, sizeof fam);
        if (fam == 2)
                a += 4;
        else if (fam == 10)
                a += 8;
        else {
                VRT_acl_log(sp, "NO_FAM foo");
                return(0);
        }

        if (fam == 2) {
         if (a[0] == 127) {
          if (a[1] == 0) {
           if (a[2] == 0) {
            if (a[3] == 2) {
             VRT_acl_log(sp, "MATCH foo " "127.0.0.2");
             return (1);
            }
           }
           if ((a[2] &amp;amp; 0xe0) == 0) {
            VRT_acl_log(sp, "MATCH foo " "127.0.0.0" "/19" );
            return (1);
           }
          }
         }
        }
        VRT_acl_log(sp, "NO_MATCH foo");
        return (0);
}

影響を受けるかの確認はVCLをCで出してみて
該当のACLマッチ関数(match_acl_named_[ACL名])を見たほうが良いかと思います。

ESI利用時にバックエンドが無効なgzipを送信した場合においてエラーを起こす可能性があった
#1184

バックエンド名が長いとAssertで子プロセスが落ちる
#1224

バグ修正は他にもありますが個人的に気になったのをピックアップしました

ツール改善

varnishncsaのフォーマットで%D,%Tをサポートしました
varnishadmでtabを打つと候補が出るようになりました

パフォーマンス系

TCP_NODELAYを有効にしました(NagleをOffにした)
chunkの時効いてきそうです。

その他

複数のHostヘッダを送られてきた場合はエラーとする
即切断されますのでvcl_recvは呼ばれません(壊れたセッション扱いです)


Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /test HTTP/1.0
Host: exmple.jp
Host: exmple.jp

Connection closed by foreign host.

varnishncsaログ
★ホストヘッダ1つ
127.0.0.1 - - [18/Jun/2013:22:42:40 +0900] "GET http://exmple.jp/test HTTP/1.0" 404 287 "-" "-"
★ホストヘッダ複数
127.0.0.1 - - [18/Jun/2013:22:42:44 +0900] "GET http://exmple.jp/test HTTP/1.0"  - "-" "-"

ドキュメントが改善されました
ABI変わってるのでvmodのリコンパイルが必要

#vug7の記事書く前にこっちの記事を書くことになるとは・・・(下書きにはあるんですがね)