nginxでcacheの部分的なpurgeをしてみる (あまり使えない)

18th Aug, 2010 | nginx

ちょっと調べてみたのだけど、現実的にあまり使えない気がする。でもせっかく調べたのでメモ。

まず、このブログは Sinatra+MongoDBをnginx+thin で動かしているのだけど、非力なVPSサーバなので、Sinatra+MongoDB+thinをなるべく使わないように できるだけnginxにcacheをさせている 。そのため更新時にはcacheを消さないといけない(トップページとか)。今はデータ更新時に、すべてのキャッシュを消している。ただ、どう考えてもださいので更新したコンテンツだけpurgeできる方法がないか調べてみた(サーバに余裕あれば、毎回backend(Sinatra)に問い合わせてもいいんだけどもね)。

nginxはデフォルトでは部分的なpurgeはできないので、 ngx_cache_purge module を使ってみた。FreeBSDのports (www/nginx-devel をこのサイトでは使っている)ではオプションで選択できる。Gentooだと USE=“nginx_modules_http_cache_purge” でいけそう(未確認)。

基本的には、 そのサイトのトップページに乗っている設定 を自分のURLの構成にあわせて変更してnginx.confとかに追加すれば動く。

ポイントは、

proxy_cache_key $uri$is_args$args;

の一つ目の引数と、

proxy_cache_purge tmpcache $1$is_args$args;proxy_cache_key

の二つ目の引数に同じ値が来るようにすること。一文字でも違ったら動かない(最後の/があるとかないとかではまる)。

実際のpurge(キャッシュのクリア)はhttpで行う。GETでいいみたい(POST/DELETEでもいい)。

たとえば、

curl http://example.com/purge/{key}

みたいにコマンドラインからも呼べるし、httpなんで呼ぶのは色々なスクリプトや言語からでも簡単。

で、何が現実的に使いづらいかというと、 key の部分は通常URL(query stringとかも込み)になるのだけど、たとえば、

http://example.com/hoge?page=2
http://example.com/hoge/
http://example.com/hoge?tag=gentoo

みたいなのが、それぞれ別々のキーでキャッシュされることになる(それ自体はそうなるべきであるケースもあるし別にいい)。しかし、ここで今/hogeに関連するコンテンツを更新したとして、/hogeに関するキャッシュをすべて消したいとしよう。でも、それを簡単にやる方法がない。ワイルドカードや正規表現が使えないので、いちいち全部自分で消さないといけない。引数まで考えると場合によっては非現実的。

同じように、 http://example.com/javascript/*.js みたいな条件でpurgeをしたい場合もあると思うけど、それもできない。

というわけで、いまいち使えないなーという結論なのでした。

おまけ: 会社では、リバースプロキシ+キャッシュとして、varnishをメインのサイトで、nginxを社内のちょっとしたサーバ用途(redmineとか)で使っている。両方触ってみて思うのは、nginxはすごく楽だけどもう一歩深い設定をしだすとできなかったりややこしいことが多い。今回の件もvarnishだと、正規表現でpurge対象を決められたりできる。 ま、適材適所ってことで。


記事の内容についての質問、苦情、間違いの指摘等なんでもtwitterでどうぞ。