2011/07/30

億単位のファイルを消去する

例えば、Cache::FileCache でキャッシュ階層深めにして、億単位の数のファイルキャッシュを溜め込んでしまった場合、けっこう消すのが大変。

普通に

$ rm -rf /cache/dir/path/foo

とかやると、頑張れるだけ頑張っちゃって、LA が大変なことになる。
特に、うちのマシンは1コアでサービス継続中だったりするから、フルパワー発揮されると困る。

というわけで、以下のようなワンライナーを書いて、ゆっくり消すようにした。

perl -MPath::Class -MTime::HiRes -e 'Path::Class::dir("/cache/dir/path/foo")->recurse(depthfirst => 1,preorder => 0,callback => sub{ my $file = shift;print"$file\n";if (-f $file){ unlink $file; print "unlinked: $file\n"; Time::HiRes::sleep 0.1; } Time::HiRes::sleep 0.01; });'

ポイントは

depthfirst => 1,preorder => 0

Path::Class の再帰探索の設定で、深さ優先にしている。これを逆にして幅優先にしてしまうと、ディレクトリを全部先に探索してしまってメモリを大きく食ってしまう。キャッシュファイルをどんどん消したいので、それに突き当たるよう深さ優先で突き進んでもらう。

Time::HiRes::sleep 0.1;

ウェイトをいれると、CPU の使用率を下げられる。ウェイトしすぎると終了までに時間がかかる上に、下手するとキャッシュが出来るよりも遅くなり、実質消去にならなくなってしまう。なので、サーバのスペックとキャッシュのヒット率と相談しながら小さく調整するといいです。マルチコアで1コア使い切っていいならウェイト控えめ(ioが許す限り)で大丈夫なはず。

なお、そもそもキャッシュディレクトリをマウントしておいて、消したくなったらアンマウントして、新しい領域をマウントするとかすれば、一瞬でクリーンにすることができます(自分で思いつく限りはそれが一番速い)。
ただ、運用中のキャッシュ領域だと、まるっと入れ替わってしまうと一気にキャッシュのヒット率が下がってしまってサービスのレスポンスを劣化させてしまいます。

なので、そんなときは、ゆっくり消去でのんびり消すのが有効です。

サイト内検索