図7●スレッド数と接続数がパラメータ・チューニングの中心<BR>Webシステムを構成する3層それぞれのクライアント・サーバー接続のコネクション数をパラメータで制御することで,個々のWebアプリケーションに適したチューニングを施す。Webサーバーはクライアントの同時接続数,APサーバーはJavaVMの数とスレッド数,あらかじめ張っておいて使いまわすDBアクセス用コネクションの数,DBサーバーはDBアクセスを受け付ける同時接続数を適切な数にする。フロントエンドのWebサーバーからバックエンドのDBサーバーに向かうにつれて同時に接続可能なスレッドを減らすケースが多い
図7●スレッド数と接続数がパラメータ・チューニングの中心<BR>Webシステムを構成する3層それぞれのクライアント・サーバー接続のコネクション数をパラメータで制御することで,個々のWebアプリケーションに適したチューニングを施す。Webサーバーはクライアントの同時接続数,APサーバーはJavaVMの数とスレッド数,あらかじめ張っておいて使いまわすDBアクセス用コネクションの数,DBサーバーはDBアクセスを受け付ける同時接続数を適切な数にする。フロントエンドのWebサーバーからバックエンドのDBサーバーに向かうにつれて同時に接続可能なスレッドを減らすケースが多い
[画像のクリックで拡大表示]
図8●JavaVMのヒープ領域のサイズでガベージ・コレクション(GC)の頻度と時間を制御する&lt;BR&gt;JavaVMは,Eden,Survivor,Oldの3つの世代でオブジェクトを世代管理することで,ガベージ・コレクション(GC)にかかる時間を少なく保っている。これらの領域のサイズをチューニングすることで,GCの実行による性能の劣化を最小限に防ぐことが可能だ。例えば,Old領域のサイズを減らすことで処理に時間がかかるフルGCを起こさないようにしたり,1回のフルGCの時間を短くするといった運用も可能になる。一般に,トータルのGCにかかる時間と頻度は反比例する。頻ぱんにGCを起こせば1回あたりのGCにかかる時間は少なくて済み,GCの回数を減らせば1回のGCにかかる時間は増える
図8●JavaVMのヒープ領域のサイズでガベージ・コレクション(GC)の頻度と時間を制御する<BR>JavaVMは,Eden,Survivor,Oldの3つの世代でオブジェクトを世代管理することで,ガベージ・コレクション(GC)にかかる時間を少なく保っている。これらの領域のサイズをチューニングすることで,GCの実行による性能の劣化を最小限に防ぐことが可能だ。例えば,Old領域のサイズを減らすことで処理に時間がかかるフルGCを起こさないようにしたり,1回のフルGCの時間を短くするといった運用も可能になる。一般に,トータルのGCにかかる時間と頻度は反比例する。頻ぱんにGCを起こせば1回あたりのGCにかかる時間は少なくて済み,GCの回数を減らせば1回のGCにかかる時間は増える
[画像のクリックで拡大表示]

パート2:チューニング
適切なパラメータを見出す

 ミドルウエアのパラメータをチューニングすることも,サーバーのサイジングと性能改善には必要である*7。重要なものは,Web,AP,DBそれぞれのプロセス/スレッド数,DBサーバーへのコネクション・プール数と,以上のバランスである。これに加えて,JavaであればJavaVMのヒープ領域のサイズも性能に影響を及ぼす。

 まず,プロセス/スレッド数とコネクション・プール数を調整する前提として,これらの値は固定値で運用するべきである。リソースを動的に確保したり開放する際のオーバーヘッドを無くすためである。稼働させるプロセスとスレッドに応じたメモリー容量とCPU処理能力も搭載していなければならない。

 WebサーバーではクライアントからのHTTPリクエストを受ける数を固定する。標準では最小プロセス数と最大プロセス数が異なっており,アクセス状況に応じて動的にプロセス数が変わるようになっている。WebシステムにおいてWebサーバーはHTTPリクエストの処理にしか使わないので,アイドル状態のプロセスがメモリーを消費していても問題はない。

 プロセス/スレッド数とコネクション・プール数は,密接な関係にある(図7[拡大表示)。クライアントからのリクエストとDBアクセスをつなぐ経路の込み具合を,パラメータで決められる。一般にはフロントエンドからバックエンドにかけて,経路となるパラメータの値を減らしていく実例が多い。

GCの頻度と時間を最小化

 JavaVMのヒープ領域のサイズも性能に影響を及ぼす。ヒープ領域のチューニング次第で,ガベージ・コレクション(GC)*8の発生頻度と処理時間を調整できる。Webシステムによっては,GCの発生時に分単位でサーバーが停止することもあり得る。

 JavaVMは,生存期間の違うオブジェクトを別々に管理することで,GCのオーバーヘッドを軽減する(図8[拡大表示)。図8中のEdenと呼ばれる領域は,作られたばかりの新しいオブジェクトを置く場所である。ほとんどのオブジェクトは一時的に作られ,GCによってすぐに寿命を迎える。一方で,よく使われるオブジェクトであるがために,GCを経ても削除されずに生き残るものもある。生き残ったオブジェクトは図中のSurvivorと呼ぶ領域にコピーする。さらにその後のGCでも生き残ったオブジェクトは,図中のOldと呼ぶ領域にコピーする。

 Old領域と,EdenとSurvivorからなるYoung領域との一番の違いは,それぞれのGCで用いるアルゴリズムである。Young領域を対象とするスカベンジGCでは「Copying」と呼ぶアルゴリズムを用いる。生き残ったオブジェクトを世代ごとに分かれたメモリー領域にコピーするものだ。メモリー・アドレス空間を無駄に消費するためメモリー効率が悪くなるが,1回のGCにかかる時間が短い。これに対して,Old領域を対象とするフルGCでは「Mark-compact」と呼ぶアルゴリズムを用いる。1回のGCでシステムが停止する時間がCopyingよりも長い。

 チューニングでは,JavaVMの起動時オプションによって,ヒープ領域全体のサイズのほか,GCで用いる個々のメモリー領域のサイズを決められる。「Old領域を対象としたフルGCをいかに発生させないか,または,発生した際のシステム停止時間をいかに短くするかがポイント」(ウルシステムズの埋金進一シニアコンサルタント)となる*9

 GCの効率を上げるためには,アプリケーションの開発時にも,オブジェクトのサイズを小さく収める工夫が必要になる。例えばJSPのソースが大きくなる場合には,ソースコードを分割するといった工夫が望ましい。