Apache2で動的コンテンツをキャッシュさせたい
ウェブサービスでフロントエンドとしてApache2を使っています。役目はフロントキャッシュと、負荷分散。こないだ入れたシステムで、Zope複数のZopeインスタンス間でデータをAPIをつかって取り出すような仕組みになりました。
動的とはいえ内容の更新頻度は低いので、Apacheを噛ませてキャッシュきかせられたらいいなぁと。
単純に書いてみる
単純にこんな設定をいれてみましたが、
<IfModule mod_cache.c> CacheDefaultExpire 36000 CacheEnable disk / CacheIgnoreNoLastMod On CacheStoreNoStore On CacheStorePrivate On CacheMaxExpire 86400 <IfModule mod_disk_cache.c> CacheRoot /usr/local/apache2/cache CacheDirLevels 2 CacheDirLength 3 CacheMaxFileSize 2000000 CacheMinFileSize 1 </IfModule> </IfModule>
これだとまったくキャッシュしてくれません。キャッシュに関するRFCで、クエリ文字列(?とか&とか)があるURLはキャッシュしちゃいかんよってのがあるらしいです。
無視してくれないかな
きっとApacheくらい気の利いたやつだと無視してくれる設定があるんだろう、とIgnore Queryなどと適当にGoogle先生に聞いたところ、ありましたよ。こんなのを入れて再起動。
CacheIgnoreQueryString On
ばっちりキャッシュしてくれる。。。と思いきや、クエリ文字から下をちょん切ってキャッシュを取り出してくる。つまり、
http://www.hogehoge.com/getitem?country=cn&trade=01
をキャッシュすると、
http://www.hogehoge.com/getitem?country=jp&trade=02
をリクエストされると上記のキャッシュをかえす。そりゃ意味がないな。
ソースをのぞくと
ソースではどんな処理になってるのかなとチェック。mod_cache.cの1309行目あたり(Apache2.2.11)にあります。
else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL && !ap_cache_liststr(NULL, cc_out, "max-age", NULL)) { /* if a query string is present but no explicit expiration time, * don't cache it (RFC 2616/13.9 & 13.2.1) */ reason = "Query string present but no explicit expiration time"; }
えーとですね。クエリ文字列がURLにあって、CacheIgnoreQueryStringがOFFになってて、Expiresヘッダがついてない場合はキャッシュしないそうです。はい、そうですか。
じゃあ
ってなことでこんな風に改造。
else if (!conf->ignorequerystring && r->parsed_uri.query && !ap_cache_liststr(NULL, cc_out, "max-age", NULL)) { /* if a query string is present but no explicit expiration time, * don't cache it (RFC 2616/13.9 & 13.2.1) */ reason = "Query string present but no explicit expiration time"; }
Expiresヘッダのところの条件を削除。これで再コンパイル、再起動してキャッシュしてくれることを確認。