だるろぐ

だるいぶろぐです

httpdでcacheする apache編

※このエントリは微妙に自力ではありません


webアプリを運用していて、静的・動的問わず

  • 転送量がやばい
  • 負荷がやばい
  • そのせいで誰かがやばい

などといったときがあることもあって、普通はmemcachedなりsquidなりを使うけど、

  • そこまでガッツリcacheする程ではない
  • 又はめんどい
  • 又はわざわざ他のミドルウェア導入せんでもhttpdだけである程度なら
  • いいから早く何とかしろ

などのケースが有ったり無かったり。


で、静的コンテンツをhttpdでさくっと対処する場合の話。
apacheだったらそこでmod_cache。
mod_cacheにはディスクに記憶するmod_disk_cacheとメモリに記憶するmod_mem_cacheがある。
静的コンテンツならmod_disk_cache、動的コンテンツ・リバースプロキシならmod_mem_cacheが定石らしい。

設定内容

例えば /images/ 以下のファイルをキャッシュする場合。

    <IfModule mod_disk_cache.c>
        CacheEnable disk /images/
        CacheRoot /dev/shm/mod_cache
        CacheDefaultExpire 3600
        CacheIgnoreCacheControl On
        CacheIgnoreNoLastMod On
        CacheDirLevels 1
        CacheDirLength 1
    </IfModule>

で、ディレクトリ作ってやる。

% sudo mkdir /dev/shm/mod_cache
% sudo chmod 777 /dev/shm/mod_cache

本当はディレクトリはこんな権限777じゃなくて、apacheを動かしているユーザ・グループで作るべし。
キャッシュをr/wするのはapacheを動かしているユーザなので。
777だとrootにならなくてもディレクトリにcdできるし中見るのも楽だわーとかになるので俺は個人的に777にしているだけである。
セキュリティホールになる気がしなくもない。


大体はマニュアルに載っているのだけど。

CacheEnable

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheenable

キャッシュするパスと、mod_disk_cache/mod_mem_cacheのどちらを使うか指定する。
fdを指定した場合がマニュアル見てもいまいち分からないが多分必要になることは無い気がするのでYAGNIの精神で華麗にスルー。

CacheDirLength / CacheDirLevels

http://httpd.apache.org/docs/2.2/ja/mod/mod_disk_cache.html#cachedirlevels

cacheするのに使うディレクトリの階層と長さと。キャッシュするファイルが少なければどっちも1でいいだろう。
多くなったら…YAGNIの精神で略。

CacheRoot

http://httpd.apache.org/docs/2.2/ja/mod/mod_disk_cache.html#cacheroot

キャッシュするディレクトリを指定する。apacheは作ってくれないから手動で作る。
どうせなら物理ディスクよりもtmpfsを使った方がディスクio減るんじゃないかと。
そういえばtmpfsとramディスクってどっちが性能いいんだっけ。

CacheDefaultExpire

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cachedefaultexpire

キャッシュする時間。内容が変化しない静的コンテンツなら巨大な値でもいい。

CacheIgnoreNoLastMod

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheignorenolastmod

Last-Modifiedが無かろうとキャッシュする。ご丁寧にLMつけてるケースの方が少ない気がする。

CacheIgnoreCacheControl

http://httpd.apache.org/docs/2.2/ja/mod/mod_cache.html#cacheignorecachecontrol

個人的にはこれがハマりどころ。
ヘッダでCache-Control: no-cache や Pragma: no-storeがあってもキャッシュを返す。
俺はfirefoxでリロードして設定を確認するのだけど、どうもfirefoxさんのリロードはスーパーリロードか何かになっているらしく、mod_cacheがキャッシュを作ってもそのキャッシュを使わない。
アクセスログも304ではなく200が返る。それじゃ困るんですよ。

キャッシュの動作

これで例えば /images/hoge.jpg とかにアクセスするとこんなファイルが出来る。

% find /dev/shm/mod_cache/ -type f
/dev/shm/mod_cache/6/KXf3h0Y6M8uQNrbWN0eyA.data
/dev/shm/mod_cache/6/KXf3h0Y6M8uQNrbWN0eyA.header


※ここからうそ臭いです


キャッシュファイルのプロセスはこう。

  1. アクセスされたらキャッシュファイルが生成される
  2. 生成されてからCacheDefaultExpireで指定した秒数が経過するまでは、アクセスが来てもキャッシュがコンテンツを返し、実ファイルにはアクセスがいかない
  3. CacheDefaultExpire秒が経過しても、キャッシュファイルは削除されない。次のアクセスがきて初めて削除される。そして新しいキャッシュファイルが生成される。

なので、沢山のファイルにアクセスされた後に、コンテンツ一新などしてそのファイル全てがアクセスされなくなると、削除されないキャッシュファイルがたくさん残る。
手動でキャッシュを削除してやってもいいやも。
以下をcronで実行するとか。

find /dev/shm/mod_cache -type f -exec rm '{}' \;

todo

httpdでcacheする nginx編」を書く