酒日記

2001 11 20

Tue, 20 Nov 2001

モルツ (5% × 1000 ml)

仕事、先日から引き続いて、負荷分散やらベンチマークやら。

特にチューニングしないで平均 30 requests/sec 程度を捌ける Web アプリケーション (mod_perl + DBI) があるのだが、 こいつを最大 100req/sec まで持っていきたい。

バックエンドの DB サーバ(PostgreSQL) に負荷があまり掛からない条件なら、Webサーバを並列にして3台も並べれば100程度行きそう。 が、30/sec の時点で DB サーバが限界近くに達する場合もあって、この場合は Webサーバを増やしても DB サーバがボトルネックになるので処理能力は上がらない。ここをなんとかしたい。

単純に考えれば、DBサーバのスペックを上げれば解決できる。 現状 Pentium III のシングルだから、Xeon の 4Way ぐらいにすれば、多分大丈夫。 ただし、最低200万円コース。

まあ、ハードウェアに物を言わせるのも芸がないので、ソフトウェア的になんとかしてみようと、 mod_perl の永続化環境を活かしてキャッシュを実装してみる。

具体的には、DBに問い合わせて得たオブジェクト (単なるハッシュリファレンスだったりする) を、パッケージグローバルな変数にぶち込んで、以後一定時間は DB にアクセスせずにそれを参照する、という方針で。 ユーザ情報のオブジェクトみたいに、更新をかける必要があるものはキャッシュせず、静的なテーブル(メンテナンス時に内容を更新するのみ) から得られたオブジェクトをキャッシュする。

以下はメモというか、動作検証してない殴り書き。

package CacheOjecct;
use vars (%CACHE);
sub get_cache
{
    my $self = shift;
    my $id   = shift;        # キャッシュを特定する名前
    my $expire = shift;        # 有効時間 (秒)
    
    if(defined $CACHE{$id}{object}){
        if($CACHE{$id}{time} + $expire > time){
            # キャッシュに格納してから有効時間以上経ったので消去
            delete $CACHE{$id};
            return undef;
        }
        return $CACHE{$id}{object};
    }else{
        return undef;
    }
}
sub set_cache
{
    my $self = shift;
    my $id   = shift;        # キャッシュを特定する名前
    my $object = shift;        # 格納するオブジェクト(内容不問)
    
    $CACHE{$id}{object} = $object;
    $CACHE{$id}{time} = time;        # 格納時刻を記録
    1;
}

これを使うスクリプトの方では、

use CacheObject;
use vars qw ($CACHE_OBJ);
unless(defined $CACHE_OBJ){
    $CACHE_OBJ = CachedOjecct->new();
}

my $object;
unless($object = $cache->get_cache('hoge', 60)){
    # DB に問い合わせて $object を取得。
    # $object = *************;
    $cache->set_cache('hoge', $object); # キャッシュに保存
}

こんな感じかな。安直だけど。

ただし、この実装だと httpd のプロセス毎に別々のキャッシュを(それぞれのメモリ空間に) 保持することになるので、少々メモリを無駄に使ってる気もする。 IPC::SharedCache モジュールでも使って共有メモリに保持すれば、消費メモリを節約できるんだろうけど。
# 実は CPAN には Apache::Cache とか、Cache::Cache とか、それらしいモジュールもあるので、そっちを使うのが利口だとは思う。

....

で、上記のように実装をしてベンチを取ってみると、劇的に DB への負荷が減少。 (キャッシュに溜まってるうちは DB を使わないのだから、当たり前といえば当たり前だが。) これなら Web サーバを単純に増やしても DBの負荷はあまり上がらないから、パフォーマンスの向上が見込める。めでたい。


神亀 純米 (16% × 180 ml)


powered by blosxom