7月 112012
hiro_yさんからこんな質問を受けたので
@xcir VarnishからS3の認証突破する方法とかご存知ないですか…と思いまして
— 山岡広幸さん (@hiro_y) 7月 2, 2012
AWSの勉強がてら作ってみました。
S3のREST-APIのAuthorizationヘッダは、日付やリソースの場所などを改行で結合して
HMAC-SHA1でハッシュ化して、BASE64エンコードする必要があります。
HMAC-SHA1については、Varnish公式が公開しているvmod-digestを使うことでできるのですが
出力をBASE64にすることができないので、コードを拝借して今回のVMODを作ってみました。
ちなみに改行を扱うことについても、インラインCかVMODを使う必要があります。
使い方
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 ); }
上記のように呼び出すとreq.http.Authorizationとreq.http.Dateに生成したヘッダがセットされます。
15 TxHeader b Date: Tue, 03 Jul 2012 16:21:47 +0000 15 TxHeader b Authorization: AWS accessKey:XUfSbQDuOWL24PTR1qavWSr6vjM=
セットされるのがbereqではないのでvcl_recvで呼び出すことを推奨します。
またAuthorizationを生成するのでもしキャッシュを行いたい場合は適切にVCLを記述してください。
デフォルトのVCLではreq.http.Authorizationを含む場合はpassするためです。
僕の方でも簡単な動作チェックを行なっていますが、もし変な動きをしたら教えて下さい。
—
参考サイト
PHP で Amazon S3 の REST API を使用 #1
Authenticating REST Requests
良いプラグインを作っていただきありがとうございます。
ところで、これはキャッシュがヒットせずS3に見に行く場合に、メモリにキャッシュするのに加えてVarnish鯖のローカルディスクに保存するような挙動を設定することはできるのでしょうか。
恐らく、Varnish鯖のローカルのディスクに保存しない場合、
ユーザ -> Varnish鯖(malloc backend) -> A3
この流れが常に起こってしまうことになります。
これではスマートではないので、
ユーザ -> Varnish鯖(malloc backend) -> Varnish鯖(file backend) -> A3
このような流れになると嬉しいのですが。これはVarnishの設定次第でできるんでしょうか、それともプラグインレベルでカスタマイズしないとできないのでしょうか。
A3じゃなくてS3でした。typo…。
Varnishのストレージには3種類あって
■malloc
一番速い。
メモリに保存する。再起動すると消える
■file
ファイルに保存するが再起動すると消える。
実ディスクにアクセスしに行くかはOS依存(ページキャッシュに乗ってれば速い)
■persistent
ファイルに保存する。
現バージョンではマスタープロセスが落ちない限りは消えない。(気にするレベルではないですがフラッシュのタイミングは独特なので直近にキャッシュしたものは消える可能性があります)
実ディスクにアクセスしに行くかはOS依存(ページキャッシュに乗ってれば速い)
ってなかんじです。
> ユーザ -> Varnish鯖(malloc backend) -> Varnish鯖(file backend) -> S3
わざわざファイルとmallocを別立てする必要はないと思います。
サーバのメモリに余裕があればページキャッシュに上手く乗るはずなので
fileかpersistentを指定すればいいんじゃないかなと思います
ここらへんは一度記事書いたほうがよさそうですね
近いうちにまとめます
なるほど。基本的な箇所の理解も甘かったので勉強になりました。
ただ、ログファイルや大量の静的画像ストレージなど、一度保存したら内容がほぼ99%変わらないようなデータをメインにキャッシュしたい場合となると、もう少し工夫できるのではないでしょうか。(できるのか分からないので憶測です。)
つまり、persistentをもっと強化したものと言いますか、なんというか……説明が難しいですね。とにかく、1回S3に保存したらその後内容がほぼ変わらないような状況で、鯖がS3を見に行くのを最小限に抑えたいんです。何か良い方法をご教授頂けませんでしょうか。
うーん・・・恐らくS3へのアクセスを最小限にして課金を減らそうということだと思うのですが
前提として
S3に保存されるファイルのサイズ(オリジン) > キャッシュサーバのサイズ
ですよね(そうでないのであればS3に置かないでキャッシュサーバをオリジンとすることをおすすめします)
この場合どうしてもキャッシュサーバで賄い切れないため落ちてしまいます
今回のケースでは
・オリジンにあるファイルはテキストと画像
・保存したら内容が変わらない
・できるだけ長くキャッシュする
なので
・TTLを長めに設定する
・persistentでサイズを大きめに設定(子プロセスのパニック対策)
・if-modified-sinceが来たら即304を返す
・ストレージ保存時にテキストはgzipをかけるようにする(もし画像が無圧縮な場合は画像も圧縮)
が順当なとこだと思います
さらにS3に保存されているデータでアクセス頻度にばらつきがあってキャッシュ容量がS3の保存容量よりかなり小さい場合はアクセス頻度が少ないものをキャッシュしないなどといった手も全体のヒット率が上がるかと思います。
他にもS3に登録されてからn日の間はアクセスが多いのであればその期間だけはキャッシュ落ちしないようにするなどといった設定もできます。
また、persistentを強化したものというのがちょっと想像できなかったのですが
もしそれがa.jpgというファイルにアクセスしたらキャッシュ側のディスク上にa.jpgというファイルができるというものであれば
Varnishでは不可能です。
答えになってるかよくわかりませんがどうでしょうか?
課金が減るというのは確かに有難いのですがそれは自分の中では言わば副次的効果のようなもので、ファイルの内容が変わらないオブジェクトを大量にキャッシュする場合はどうするのが一番原理的にスマートなのかというのが自分の気になっていた所でした。
TTLの設定等で恐らく十分に無駄が無くなりそうです。
>アクセス頻度が少ないものをキャッシュしない
や
>n日の間はアクセスが多いのであればその期間だけはキャッシュ落ちしない
も非常に参考になりました。ここら辺はユースケースを考えて細かい設定を決めた方がよさそうですね。
>persistentを強化したもの
というのは僕のVarnishの理解が甘かったため出てきた妄想だったようです。fileやpersistentを使えばファイルがメモリにマッピングされて必要に応じて書き込みが起こるというものだったのですね。メモリ上にキャッシュできるのはmallocのみで、fileやpersistentは単にファイルをいちいち読みに行くのかと誤認してました。
今回は長々とありがとうございます。お陰様でどうすれば良いのかイメージできました。
参考になったようで幸いです。
ちなみにTTLやストレージサイズを決めるときは
http://blog.xcir.net/index.php/2011/09/%E5%A4%8F%E3%81%AB%E5%87%BA%E3%81%97%E3%81%9Fvarnishcache%E5%85%A5%E9%96%80%E3%82%92pdf%E3%81%A7%E5%85%AC%E9%96%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F/
のP39あたりから44あたりまでを参考にすると捗るかもしれないです
無闇矢鱈に大きくするのもありですがここらへん考えると面白いと思います。
あとP50あたりから書いている複数ストレージの切り替えも参考になるかもしれないです。
・・・そろっと古くなってきたし書き直したいなぁこれ
ここまで言っててなんですが僕はだいたいmalloc使ってますw
おお、資料ありがとうございます。読んでみます。
>ここまで言っててなんですが僕はだいたいmalloc使ってますw
やっぱり速ければ速いほど良いですもんねぇ……w
別件でpersistentを試してみたら普通にstop startでもキャッシュ維持したので
昔試した時に条件ミスったか何かで勘違いしてたっぽいです申し訳ないです
–編集
3.0.1で修正されたようです