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


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の記事書く前にこっちの記事を書くことになるとは・・・(下書きにはあるんですがね)


5月 252013
 

みなさんお久しぶりです。いわなちゃんさんです。
最近会社で、「○○さんっていわなちゃんですよね?」と確認されたりしていますが元気しています。

さて、来週の5月30日~31日にかけてニューヨークで行われるVarnish User Group Meeting 7(VUG7)で発表する機会を頂けましたので、先日会社のブログでちらっと触れたレガシーシステムを載せ替えた話といくつか作ったツールについて発表してきます。
本当はVMODの話でもしようかなと考えていたのですが、MLとかIRCを見てて困ってる人が多いのはツールかなと感じたので、そっちの話をしてきます。

ツール自体の記事は、また帰ってきたら書こうと思いますがgithubにはあげていますので見てもらえれば嬉しいです。
あと、ニューヨークで美味しいものを食べたいので、おすすめのお店・ここは見とけといったスポットを教えてもらえると嬉しいです。
飛行機の都合でフリーな時間が多少あるんですが、何処に行こうとかほぼ決めておらず、最悪ホテルに引きこもりかねないので・・・


正直、年初に立てた目標を1つ残して達成してしまったので
今年は順調でもう少し目標追加することを考えています。
残り1つについても見込みが立っていて、多分VUG中に決まるんじゃないかなとか思っています。
色々頑張って行きたいですね


11月 142012
 

Varnishは様々なオブジェクトのキャッシュを行いますが
その際にオブジェクトの保存を何処に行うかを選択することができます。
現在のバージョンでは

malloc
file
persistent

といった3つのストレージが存在しており、それぞれに特徴があります。
今回は特にpersistentに焦点をあてて解説します。

malloc

メモリ上にストレージを置いているVarnishで一番高速なストレージです。
メモリ上に置くため当然のことながらサーバの移設での一時停止や再起動、
workerのpanicでの自動再起動などでキャッシュが吹き飛んでしまいます。

file

ファイル上にストレージを置く、若干遅いストレージです。
ファイルと名前はついているものの永続化を目的としておらず、
ストレージへの書き込み時にflushしません。
読み書きはページ・バッファキャッシュ、つまりOSに任せており
Varnishでは特に制御はおこなっていないため、オーバーヘッドが少なく高速です。
正直HDDを使っているときは、あまりおすすめできません。
しかし、SSDやioDriveといった高速なデバイスの場合は使えるストレージです。

先程も書いた通り、永続化を目的としていないためmallocと同様に再起動でキャッシュが吹き飛びます。
名前に騙されてはいけません。

persistent

永続化を目的としたストレージです。
単一のファイルですが、内部では複数のセグメントを持っており
10~60秒に一回程度でオブジェクトを書き込むセグメントを変更します。
(ざっくりコードを見た感じだとセグメント変更時もflushをしていない)
これにより書き込み途中でpanicで自動再起動したとしても、
壊れたセグメントのみを切り離して再開することができ、安全性が高いストレージです。

私がV3.0.3でテストしたところ以下の条件でもキャッシュを維持しました。
 ・親プロセスも含めたVarnishの停止・開始(V3.0.0の時は消えましたが3.0.1で修正されました)
 ・varnishadmなどの管理ツールからの停止・開始
 ・panicなどでの自動再起動(一部消えることはある)

更にVarnish Software公式のアナウンスによるとfileストレージより高速なため
非常に使ってみたいストレージといえるんじゃないかと思います。

しかしまだPersistentストレージは発展の途上です。
最新バージョンである3.0.3では実用上に?がつく残念な仕様が幾つか存在します。

特にセグメントが一巡した(=指定ストレージサイズを使いきった)際に
最初のセグメントから再利用するのですが、期限切れしていない場合は再起動を行い拡張を試みます。
そのため、現時点では非常に玄人向けのマニアックなストレージではないかなと考えています。

もし私が使うのであれば、
 ・セグメントが一巡することが起因の再起動を起こさせないことが確信できている
 ・最上段ではなく2段目以降
であれば使うかなーっと言った感じです。

じゃぁまったく使えないじゃないかというとそうでもなく
VUG6でのプレゼン資料やVarnish Softwareのブログを見る限り、
persistentの強化を進めていくように感じられますし
現在のtrunk(確認したのは2012/11/13バージョン)では再起動も起こらず期待どおりの動きをしています
恐らく近い将来Varnishの主流のストレージになるのではないかと考えています。
もちろん人柱覚悟でtrunkを使うのも有りだと思います

–参考リンク
Testing the persistent storage engine(Persistentがfileより速いよというベンチ内容)
Release status(VUG6で発表されたV3.1までのリリース内容)
ImprovedPersistence(Persistentストレージのマイルストーンについて)
ArchitecturePersistentStorage(Persistentストレージのアーキテクチャ(古めな内容))


9月 062012
 

Amazon S3 REST-API is necessary to generate signature.
vmod-awsrest generate to Authorization and Date header for Amazon S3.

How to use

VCL


import awsrest;

backend default {
  .host = "s3.amazonaws.com";
  .port = "80";
}

sub vcl_recv{
  awsrest.s3_generic(
  "accessKey",            //AWSAccessKeyId
  "secretKey",            //SecretAccessKeyID
  req.request,            //HTTP-Verb
  req.http.content-md5,   //Content-MD5
  req.http.content-type,  //Content-Type
  "",                     //canonicalizedAmzHeaders
  req.url,                //canonicalizedResource
  now                     //Date
  );
}

Output


15 TxHeader     b Date: Tue, 03 Jul 2012 16:21:47 +0000
15 TxHeader     b Authorization: AWS accessKey:XUfSbQDuOWL24PTR1qavWSr6vjM=

This module set to req.http.Authorization and req.http.Date, bereq is not use.
I recommend call in the vcl_recv.
And, be careful to default settings.
If req.http.Authorization contains, it is not caching. (default setting)

download here.
libvmod-awsrest


Reference site
PHP で Amazon S3 の REST API を使用 #1
Authenticating REST Requests

日本語はこっち
VarnishでAmazon S3の認証ヘッダを作るVMODを作ってみた


8月 212012
 

Varnish3.0.3が公開されました。
今回の変更は多くのバグフィックスとツール系の機能拡充とドキュメントの整備です。

公式リリースノート varnish-cache-3.0.3

バグフィックス

・ストリーミングと正規表現の評価においてクラッシュの要因となるバグを複数修正しました。
・ESIとGZIPにおいて壊れたオブジェクトを返却するケースが存在する問題を修正しました。
・ESIのremoveタグ内にHTMLのコメントがあるケースにおいて不適切な削除を行なっていたのを修正
・ban lurkerのスリープする条件の変更(回収した際は設定値・回収しなかった場合は1秒)
・多くのクラッシュの要因になるバグの修正
・その他いろいろ修正

ツール系の機能拡充

varnishstat

・json出力オプションの追加(-j)

varnishtest

・resp.bodyでレスポンスボディの評価が可能に

varnishncsa

・VCL中に”Key:Value”の形式でログを出力すると%{VCL_Log:Key}xで取得可能に


■VCL
  sub vcl_recv{
  std.log("hoge:mage");
}

[root@localhost ~]# varnishncsa -F "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{VCL_Log:hoge}x\""
192.168.1.199 - - [21/Aug/2012:08:46:27 +0900] "GET http://192.168.1.199:6081/ HTTP/1.0" 200 5 "-" "Wget/1.12 (linux-gnu)" "mage"


・%{format}tの対応


[root@localhost ~]# varnishncsa -F "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{%Y%m%d%H%M%S}t\""
192.168.1.199 - - [21/Aug/2012:08:51:54 +0900] "GET http://192.168.1.199:6081/ HTTP/1.0" 200 5 "-" "Wget/1.12 (linux-gnu)" "20120821085154"

・formart指定中に\tと\nの指定が可能に


[root@localhost ~]# varnishncsa -F "%h AAA\tBBB\nCCC"
192.168.1.199 AAA       BBB
CCC

cli

・backend.listが追加されました
 バックエンドの状態を確認することができます


■定義
director default random{.retries = 5;
  {.weight = 5;.backend={.host="127.0.0.1";.port="81";}}
  {.weight = 5;.backend={.host="127.0.0.1";.port="82";}}
}
■Admin
backend.list
200
Backend name                   Refs   Admin      Probe
default[0](127.0.0.1,,81)      1      healthy    Healthy (no probe)
default[1](127.0.0.1,,82)      1      healthy    Healthy (no probe)

・backend.set_healthが追加されました
 バックエンドの状態を強制的に変更できます


■定義
backend default {
  .host = "127.0.0.1";
  .port = "81";
}

■状態をsickに変更
backend.set_health default sick


■定義
director default random{.retries = 5;
  {.weight = 5;.backend={.host="127.0.0.1";.port="81";}}
  {.weight = 5;.backend={.host="127.0.0.1";.port="82";}}
}

■状態をsickに変更(一つだけ)
backend.set_health[0] sick

■状態をsickに変更(全部)
backend.set_health sick


パラメータの変更

・http_range_support (BOOL default:ON)
 rangeリクエストのサポートですがEXPERIMENTALから正式になりました。
 ただ3.0.0からデフォルトでONになっていたので、特に気にすることはないと思います。

・send_timeout (sec default:600)
 送信時のタイムアウト時間が60秒から600秒に変更されました。
 idle_send_timeoutでアイドルの設定ができるようになった影響で増えてると思います。

・diag_bitmap (bitmap default:0)
 ban-lurkerのデバッグ用の指定が増えました(0x00080000)

・redhat用のsysconfigでVARNISH_MIN_THREADSが1から50に
 デフォルト値がよくなりました

パラメータの追加

通信に関わるパラメータ

・idle_send_timeout (sec default:60)
 送信時にアイドル状態(データの送信ができなくなった)になった場合のタイムアウト時間です

内部での正規表現の呼び出しについての制限

・pcre_match_limit (1~UINT_MAX default:10000)
 呼び出し回数の制限

・pcre_match_limit_recursion (1~UINT_MAX default:10000)
 再起回数の制限

ドキュメントの整備

その他変更

EL6用RPMの用意
・DNSディレクターにおいてポートの指定がない場合はデフォルトで80を使うようになった
・libvarnishapiの変更
・ABIが変わったのでVMODのリビルドが必要
・内部関数の定義が変わってるので一部のインラインCやVMODが動かなくなる可能性アリ(HTC_Readが個人的に痛い)

多くのバグ修正を含んでいるため適用するのが良いかと思います。


8月 042012
 

急に、LDAPにアクセスしてみたくなったので、勉強がてら作ってみました。

よく使われそうな、シンプルなLDAPの認証はもちろん
特定のグループにだけ許可のようなことも可能です。
VCLはロジックがかけるので、親和性が高いんじゃないかなと考えています。

シンプルなLDAPを使ったBASIC認証


import ldap;

sub vcl_error {
  if (obj.status == 401) {
    set obj.http.WWW-Authenticate = {"Basic realm="Authorization Required""};
    synthetic {"Error 401 Unauthorized"};
    return(deliver);
  }
}

sub vcl_recv{

if(req.url ~ "^/member/"){
        if(!(req.http.Authorization &;amp;&;amp; ldap.simple_auth(
          true, //V3プロトコルで接続するか
          "cn=Manager,dc=ldap,dc=example,dc=com", //バインドアカウント(User)
          "password", //バインドアカウント(Pass)
          "ldap://192.168.1.1/ou=people,dc=ldap,dc=example,dc=com?uid?sub?(objectClass=*)", //LDAP接続先
          ldap.get_basicuser(), //認証したいアカウント(User)
          ldap.get_basicpass()  //認証したいアカウント(Pass)
        ))){
                error 401;
        }
}

グループとユーザで制限してみる


import ldap;

sub vcl_deliver{
  //LDAPを閉じる
  ldap.close();
}

sub vcl_error{
  if (obj.status == 401) {
    set obj.http.WWW-Authenticate = {"Basic realm="Authorization Required""};
    synthetic {"Error 401 Unauthorized"};
    return(deliver);
  }
}

sub vcl_recv{

  if(req.url ~ "^/member/"){
        //LDAPに接続
        if(!(req.http.Authorization &;amp;&;amp; ldap.open(
          true, //V3プロトコルで接続するか
          "cn=Manager,dc=ldap,dc=example,dc=com", //バインドアカウント(User)
          "password", //バインドアカウント(Pass)
          "ldap://192.168.1.1/ou=people,dc=ldap,dc=example,dc=com?uid?sub?(objectClass=*)", //LDAP接続先
          ldap.get_basicuser(), //認証したいアカウント(User)
          ldap.get_basicpass()  //認証したいアカウント(Pass)
        ))){
                error 401;
        }
        //グループの照合
        if(!ldap.compare("cn=test,ou=people,dc=ldap,dc=example,dc=com","memberUid")){ldap.close();error 401;}
        //ユーザの照合
        if(!ldap.require_user("uid=hogehoge,ou=people,dc=ldap,dc=example,dc=com")){ldap.close();error 401;}
        //パスワードの照合
        if(!ldap.bind()){ldap.close();error 401;}
        ldap.close();
  }
}

ちなみにget_basicuserとget_basicpassを使うと
BASIC認証を行った時に送られてくるAuthorizationヘッダからユーザIDとパスを取得する事ができます。

なおシンプルな認証で使うsimple_authは内部ではopenとbindとcloseを呼び出しています。

ダウンロードはこちら(vmod-ldap)