仕方ないのでバージョン2.2から実用可能になったApacheのmod_disk_cacheを使おうかと思ったのですが、これがうまくありませんでした。
まず、リクエストが来るとファイルを全部キャッシュするまでレスポンスを返しません。4GBあるDVDのISOイメージをキャッシュするまでクライアントを待たせてしまう可能性があります。せっかちなクライアントはタイムアウトしてしまうかもしれません。
ディスクキャッシュを掃除するhtcachecleanも、レスポンスにExpireヘッダがないとファイルのmtimeを見て古いのから消してしまいます。人気のあるファイルをキャッシュしたいという我々の思惑とは程遠いです。
仕方ないので、ディスクキャッシュの仕掛けを自前で作ることにしました。この仕掛けは以下の三つの要素からなります。
- Apacheのログを元にキャッシュするファイルの一覧を更新して、一覧から消えたファイルをキャッシュから消すスクリプト
- 30分に一度ファイルの一覧に基づいて、ドキュメントルートの.cacheディレクトリにマウントされたSSDにファイルをコピーするrsync
- 各リクエストについて、先に.cacheの下を調べてファイルがあればターゲットを.cacheの下に書き換える書き換え規則
RewriteCond /DocumentRoot/.cache/$1 -f RewriteRule ^/(.*)$ /DocumentRoot/.cache/$1
ポイントはキャッシュするファイルを決めるアルゴリズムです。キャッシュの更新間隔は最短で30分ですが、単純にLRUで30分ごとにキャッシュするファイルの一覧を更新すると、新たにキャッシュされるファイルが多すぎてSSDへのコピーが30分で終わりません。
書き込み中はSSDの読み込み性能が低下しますし、コピー元のディスクアレイにも負荷がかかります。それに書き込みはSSDの寿命を縮めます。ずっとコピーが続く状態は避けなければなりません。しかし、アクセスの多いファイルはなるべく早くSSDに送り込む必要があります。
試行錯誤の結果、現在ではキャッシュするファイルの決定にファイルの転送量の指数移動平均を用いています。指数移動平均の時間間隔は2時間で平滑化係数は0.02です。つまり直近2時間の転送量は2%しか反映されません。かなり控えめですが、ほとんどのファイルは散発的にしかアクセスされないので、アクセスの集中したファイルはすぐにキャッシュの対象になります。
キャッシュするファイルの一覧の更新も2時間に一度です。2時間ごとに入れ替わるファイルの数はかなり少なめに抑えられていますが、DVDやCDのISOイメージが入るとファイルのコピーに20分以上掛かることもあります。間隔を縮めるとしても1時間がいいところでしょう。
キャッシュするファイルを決めるスクリプトは、以下のようなCustomLogディレクティブを使って、標準入力からログを読み込むプログラムとして実行しています。
CustomLog "| /opt/.../bin/icache.pl" "%>s %O %f"スクリプトは標準入力からレスポンスのステータスとデータの転送量とファイル名を読み込んで、ステータスが200番台のものについてファイルごとに転送量の指数移動平均を計算します。
CustomLogから起動されるプログラムは、遅滞なくログを読み続けなければなりません。そうしないとhttpdがリクエストを受け付けなくなってしまいます。次に述べる2時間ごとの処理は少し時間が掛かるので、この間止まるのを避けるために、このスクリプトではログを読むスレッドと処理するスレッドを分けています。
このスクリプトは2時間ごとに、ファイルサイズの合計が指定された値に達するまで、指数移動平均の大きな順にキャッシュするファイルを選びます。キャッシュされているファイルのうち、このときに選ばれなかったものとオリジナルが存在しなくなったものをキャッシュから削除します。すべてのファイルの指数移動平均を保持し続ける必要はないので、このときにデータを1万個まで減らします。
現在のキャッシュの合計の設定は500GB (465GiB)です。キャッシュされるファイルの個数は2000~3000個と幅があります。これはDVDのISOイメージが出入りするせいです。160GBのSSDを4つ束ねているのでファイルシステムの容量は587GiBありますが、あえて120GiBほど空けてあります。これはアクセスの殺到が予想されるファイルを事前に手作業でキャッシュに送り込めるようにするためです。メモリが64GiBになったから、もうその必要はないかもしれませんけど。
このようなキャッシュ機構を用いて、13TiBのコンテンツのうち3.5%の465GiBをSSDにキャッシュしただけで、平均で90%もヒットするようになり、ディスクアレイの負担は大きく軽減されました。
/.cache/ 以下も Browserable になってたのか。全然気にしてなかったな。。
返信削除そういえば、最初はお試しって感じで、SSD で組んだファイルシステムに人気のあるコンテンツ(Fedoraとか)を直接置いていましたね。
返信削除で、こりゃ猛烈に性能がいいぞってことで、さらに効果的に使うためにキャッシュとして使おうと色々とトライ。結局、てきとうスクリプト & mod_rewrite ってのが現状では一番という感じか。。。
ZFS の L2ARC はやくこないかなぁ。。。
Fedoraはでかすぎて丸ごと移せなかったから、最初に置いたのはCentOS、openSUSE、Eclipseあたりだよ。
返信削除SSDの性能の良さもあるけど、むしろディスクアレイの負荷が軽減したことによる、全体としての出力向上が大きかった。だから、このエントリの結論もそうなってる。今でもSSDは性能の4%くらいしか発揮していないし。
キャッシュの利点は、SourceForge.netみたいに一部のファイルに人気が集中していて、それが変化する場合の負荷を、効率よくSSDに散らせることだと思う。
正直Zinくんが書いたスクリプトはいまいちだった。ブロックしてたしね。でも、キャッシュ機構の大枠はよかったし、キャッシュの利点もよくわかったから、僕もスクリプトの改善に注力した。
まあ今だから言えることだけど、SSDより先にメモリだったね。