最終回 Apacheパフォーマンス・チューニングの実践

Apacheのチューニングを行っていく。


Index
ApacheによるWebサーバ構築
処理の簡略化による負荷の低減
 不必要なモジュールの削除
 DNSの逆引き停止
 .htaccessファイルを読み込ませない
 ディスクアクセスの分散
  セッションのチューニング
 KeepAliveとセッションの切断
 プロセスの制限と待機プロセス
稼働状況の把握
 mod_statusによるステータス表示
 Web Application Stress Tool
チューニングのコツとは?

処理の簡略化による負荷の低減

 初めに紹介するのは、処理を減らすことによってApacheの負荷を少なくする方法だ。1つ1つの効果は小さいかもしれないが、積み重なると大きな差となって表れる。

不必要なモジュールの削除

 最初に行うチューニングは、不必要なモジュールの削除だ。周知のとおり、Apacheはモジュールの組み合わせで動作している。モジュールの種類は実にさまざまで、仮想ディレクトリ機能(mod_alias)やユーザーディレクトリ(mod_userdir)といった基本的な機能さえも、モジュールとして実装しているくらいである。

 Apacheがこのような形態で実装されているおかげで、利用する側は不要な機能を切り離してプログラムを軽量化できる。プログラムのサイズが小さくなることは、実行パフォーマンスに少なからず影響を及ぼす。

 まず、プログラムを読み込んで保存するメモリ容量が小さく済む。そして、余計なロジックを通過しないことで、CPUの計算時間も短縮できる。こうしたメリットは小さなことと思われるだろうが、多人数から同時実行されるApacheでは、その同時実行数分の差が出る。不必要なモジュールを削除する努力は、重要なパフォーマンスチューニングの1つなのである。

 モジュールを削るには、まず現在組み込まれているモジュールを知る必要がある。Apache(httpd)を「-l」オプション付きで実行すればそれが分かる。

# /usr/local/apache/bin/httpd -l

などとして実行すると、その結果としてApacheに組み込まれたモジュールのファイル名(通常は拡張子が「c」のもの)が表示される。こうして表示されたモジュールを取り除くには、再インストール(コンパイル)するほかない。configureを行うときに、「--disable-module=…」とすれば、そのモジュールは組み込まれなくなる。

 このように固定的に組み込まれているモジュール以外に、現在のApache(1.3以降)ではDSOと呼ばれる仕組みによって組み込まれるモジュールが存在する。これは、必要に応じて呼び出し、組み込むことのできるモジュールだ。DSOで読み込まれるモジュールは特別に決まっているわけではなく、どのモジュールであっても構わない。

 ただし、前出の「mod_alias」のように、頻繁に呼び出されるモジュールをDSOで組み込むとかえってパフォーマンスを悪化させる可能性もあるので注意したい。頻繁に組み込まれる(確実に利用する)モジュールはあらかじめ組み込んでおき、ときどき利用するモジュールはDSOで組み込むのがいいだろう。不必要なモジュールを、「いずれ使うかもしれない」という程度の感覚で組み込むのは感心しない。

 DSOで組み込むモジュールは、インストール時に「--enable-shared=..」としなくてはならない。そして、それらのモジュールは「httpd.conf」にリストされることになっている。具体的には、「LoadModule」ディレクティブと「AddModule」ディレクティブがそれで、これらのディレクティブは1つのモジュールに対してペアで記述される。インストール時に組み入れたモジュールが不必要になったら、これらのディレクティブの先頭に「#」を付けて、コメントアウトしてしまえばよい。また使いたくなったら、コメントアウトを解除すればいいのだ。

DNSの逆引き停止

 不必要なモジュールを削減した後は、無駄な処理をしないようにチューニングしていこう。ただし、その処理が無駄かどうかは、一概に判断できないところに問題がある。

 ここで、Apacheにおける無駄な処理の1つとしてDNSの逆引きを挙げる。なぜApacheがDNSの逆引きを行っているかというと、主にログの記録や認証のためである。アクセスログやエラーログにどこからのアクセスがあったかを記録する際、IPアドレスよりドメイン名の方が(人間にとっては)分かりやすい。コンテンツへのアクセスを認証するにも、IPアドレスの範囲よりドメイン名の方が設定しやすいが、そうすると認証時にドメイン名を調べる必要が出てくる。ただし、DNSの逆引きは、通信を伴うので意外にパフォーマンスへの影響が大きい。アクセスが集中すれば、ネットワーク回線にまで負荷をかけてしまう。

 DNSの逆引きを停止するには、「HostnameLookups」ディレクティブを使う。具体的には、

HostnameLookups off

とする。

 特定のファイルや拡張子については逆引きを有効にしておきたい、ということもあるだろう(CGIプログラムの内部でドメイン名を使いたい場合など)。そのような場合には、次のように「File」ディレクティブを活用すればよい。

HostnameLookups off
<File ~ "\.(shtml|cgi)$">
  HostnameLookups on
</File>

 この設定ではログの分析の際に困るという方がいるかもしれないが、これについては第14回 ログローテーションとAnalogの導入で紹介したように、分析前にDNSの逆引きをまとめて行うことをお勧めする。

.htaccessファイルを読み込ませない

 DNSの逆引きのほかに無駄な処理があるとすれば、それは「.htaccess」ファイルへのアクセスである。.htaccessファイルがコンテンツへの認証を行うために不可欠であることは、以前にも説明したとおりだ。しかし、このファイルもサーバの負荷を増やす要因となる。必要最小限の利用にとどめるべきだろう。

 認証が不必要なディレクトリについては、必ず「AllowOverride None」としてファイルを探しに行かないようにする。そのうえで、本当に必要なディレクトリだけを個別に設定して「AllowOverride All」などにする。こうするだけでも、無駄なファイル検索や読み込み処理を削減でき、全体で見ればパフォーマンスの向上につながるのである。

ディスクアクセスの分散

 Apacheのプログラム自体を改良してディスクの読み書きを削減するのは困難だが、ちょっとした工夫で効率を上げることはできる。その1つが、ログファイルのディスク分散である。通常は、インストール時の設定のまま「/usr/local/apache/logs/」などにログを書き込んでいると思う。しかし、これではコンテンツファイルへのアクセスも、ログファイルへのアクセスも1つのディスクに集中することになってしまう。

 ディスクが複数台あってRAIDなどでグループ化されていないのであれば、ログファイルを物理的に異なるディスクへ分散することを勧める。細かいことをいうようだが、ログの記録はリクエストのたびに行われるので、意外と侮れないチューニングとなる可能性もある。パフォーマンスを追求するなら、ぜひ実践しておきたいポイントの1つである。


最終回 Apacheパフォーマンス・チューニングの実践

セッションのチューニング

 ここまでのチューニングは、必要か必要でないかを判断すればよく、手探りで最適な値を探し出すというものではなかった。しかし、これから紹介する「セッションのチューニング」はそうもいかない。ある程度の見通しは立てられても、最適な答えを見つけるのには手間がかかってしまう。

KeepAliveとセッションの切断

 セッションのチューニングの手始めとして、「KeepAlive」について考えることにしよう。KeepAliveはHTTP/1.1から用意されたもので、クライアントとの接続を保持する仕組みである。HTTPは「ステートレス・プロトコル」と呼ばれるとおり、1回の要求(リクエスト)ごとに接続が切断される。しかし、今日では1つのWebページを表示するために複数のファイルが必要となる場合がほとんどなので、1リクエストごとに接続を切っていたのでは効率が悪い。そこで考え出されたのがKeepAliveであり、一度接続したらある条件を満たすまで接続を保持するようになったのである。

 Apacheにおいて、KeepAliveを有効とするか否かを決定するのが「KeepAlive」ディレクティブである。デフォルトは「On」になっているはずだから、そのままであればKeepAliveは有効になっている。便利な仕組みなので基本的には有効に利用したいものなのだが、あまり長期間接続を維持し過ぎると、かえって効率が悪くなるので注意が必要だ。

 なぜ効率が悪くなるのか? それは、リクエストが終了したら接続を切断できればいいのだが、残念ながらそうした仕組みは備わっていないからである。リクエストが終了したクライアントに対して、いつまでも接続を維持しているとリソースの無駄遣いになってしまう。そのため、適度に接続を切断できるようにしておきたい。

 それを設定するのが、「MaxKeepAliveRequests」ディレクティブと「KeepAliveTimeout」ディレクティブである。MaxKeepAliveRequestsは、接続してから切断するまでに受け付けるリクエストの数、KeepAliveTimeoutは、接続しているセッションからのリクエストが来なくなってから切断するまでの待ち時間を設定する。

 いくら連続してリクエストが来ていたとしても、大量のリクエストを1セッションで受け付けていると、ほかのセッションが割り込むすきがなくなるかもしれない。また、早く接続を切断すると、再び接続を受け入れる際にオーバーヘッドが加わることも考慮しなければならない。難しいところだが、MaxKeepAliveRequests(デフォルトは100)には1ページ当たりの平均的なファイル数+α程度を設定し、KeepAliveTimeoutにはデフォルト(15秒)よりも小さい値を設定するのがいいだろう。

プロセスの制限と待機プロセス

 Apacheは、1つのプロセスで多数の接続を処理するのではなく、接続ごとにプロセスを1つ作成して動作する。つまり、同時に接続するクライアントが増えれば、それに比例してプロセスも増えるのだ()。プロセスが増えれば、メモリやCPUを圧迫するのは当然のことだから、増え過ぎないように注意していると思う。しかし、プロセスを増やすにもCPUパワーと時間を必要とすることは、あまり注意されていないのではないだろうか?

注:これは、Apache 1.3.xまで。Apache 2.0はマルチスレッドで動作するため、1つのプロセスで指定したスレッド分の同時接続を処理できる。

 プロセス数を制限するためのディレクティブが「MaxClients」である。このディレクティブには、同時に接続できるクライアント(厳密にはセッション)の数を指定する。デフォルトは150となっているが、もう少し大きい値を指定するべきだろう。

 この値の調整には、前回紹介したabを使って飽和点を探り出す作業が必要となる。abで同時接続数を上げながら、CPUやメモリの状態、abが示すパフォーマンスの推移を調査する。それに伴ってMaxClientsの値も上げながら、飽和点を探る作業を行うのだ。しかし、飽和点いっぱいに設定するのはお勧めできない。本当に飽和してしまうとサーバがフリーズしたようになってしまい、サービスできるはずのクライアントにもサービスが提供できなくなるからである。少し余裕を持って動作できるくらいがちょうどいいのだ。

 次に調整するのが、待機プロセス(SpareServers)である。先に述べたとおり、プロセスを起動するにも時間がかかるから、いま動作しているプロセスの数よりも余分にプロセスを起動しておく。こうすることで、足りなくなってからプロセスを起動するよりも、大幅にパフォーマンスを改善できるのである。

 待機プロセスには、2つのディレクティブが関係する。「MinSpareServers」ディレクティブ(デフォルトは5)に待機プロセスの最小値を指定し、「MaxSpareServers」ディレクティブ(デフォルトは10)に最大値を指定する。これにより、少なくともMinSpareServersで指定しただけのプロセスが常に待機するが、多くなってもMaxSpareServersで指定した以上にはならない。注意が必要なのは、リクエストを処理しているプロセスは待機プロセスと呼ばない点である。つまり、最大時にはMaxClientsとMaxSpareServersを足した数のプロセスが起動するということだ。

 これらの値の調整は、Webサイトの性質によって変わるので一概に基準を示すわけにはいかない。1つだけいえるのは、MinSpareServersとMaxSpareServersの数値の差をあまり大きくすべきではないということである。いずれにしても、次の接続を待ち受ける「待機」プロセスなのだから、その値はそれほど大きなものにはならないはずだ。

 プロセスの数そのものは上記の3つのディレクティブで指定すればいいのだが、それらとは別にプロセス自体の生存回数を決めるディレクティブがある。それが「MaxRequestsPerChild」ディレクティブである。プロセスは、一度起動すると通常はApacheを停止するまで起動したままになる。プロセスが停止するのは、MaxSpareServersを超えて待機状態になったときだけだ。

 もちろんそれでも構わないのだが、まれに長時間起動したままになっていると、徐々にメモリーリークなどの問題を引き起こすことがある。そこで、一定回数以上リクエストを処理したプロセスは、一度停止させようというのがMaxRequestsPerChildディレクティブの役割だ。このディレクティブは、デフォルトでは「0」(無制限)となっているが、一定回数でプロセスをクリーンアップしたければ特定の数を指定する。サイトのアクセス数にもよるが、100から1000の間くらいで、適当な値を指定するといいだろう。

稼働状況の把握

 チューニングによってどれくらいパフォーマンスが改善したか、abなどで調べるだろう。もちろん、値を変化させながら測定したりもするだろう。しかし、それはあくまでも推定された状況での調査にすぎない。実際の稼働中に、どれくらいの同時アクセスが発生しているのか、プロセスの数はどうなっているのか。そうした実稼働状況を見て、そのときの体感速度などを測ってみなくては、チューニングの成否など分かるはずもない。

mod_statusによるステータス表示

 Apacheにおいてそうしたリアルタイムの稼働状況を調べるには、OSコマンド(psやvmstatなど)のほかに、mod_statusを使うことが考えられる。Apacheのインストール時に、「--enable-module=status」または「--enable-shared=status」とすればmod_statusがインストールされる。すると、httpd.confには次のような行があるはずなので、そのコメントアウトを外して「Allow from ..」に参照を許可するドメインなどを指定する。

#<Location /server-status>
#    SetHandler server-status
#    Order deny,allow
#    Deny from all
#    Allow from .your-domain.com
#</Location>

 設定変更後に「http://ホスト名/server-status」にアクセスすると、稼働状況を示すページが表示される(画面1)。表示されるデータは瞬間的な状況でしかないから、細かな分析はできない。しかし、同時アクセス数など大まかな状況の把握には役立つと思う。まだ使ったことがないのであれば、ぜひ一度試してみていただきたい。

画面1 mod_statusによるステータス画面

Web Application Stress Tool

 以上で筆者が知り得る限りのチューニング・ポイントの紹介は終わりだが、まだ懸念事項がある。それは、abによるパフォーマンス測定は、しょせん単一URLへのリクエストでしかない、という点である。

 実際のWebアクセスにおいて、リクエストのすべてが同じURLを指定しているなどあり得ないし、各自が思い思いにページを遷移していくはずだ。完全に現実と同じ状況をシミュレートすることなどできないかもしれないが、もう少し現実に則した測定ができないものだろうか。

 市販のソフトウェアやサービスを利用するのも1つの手段ではあるが、高価である場合が多い。もちろん、価格に見合うだけの測定をしてくれるが、なかなかその導入にまで踏み切れないところだろう。そんな方に試してみてほしいのが、Microsoftが提供する「Web Application Stress Tool」である。このツールは無料で提供されているので気軽に使えると思う。

 このツールは、あらかじめ用意したスクリプトのとおりにWebサーバにリクエストを発行する。スクリプトはプログラムをコーディングするようなものではなく、「Record」と呼ばれる機能で、IEの操作を記録するだけだから簡単だ。パフォーマンス・チューニングの仕上げに、一度使ってみるといいだろう。

チューニングのコツとは?

 具体的なテスト結果などを提示するには至らなかったが、Apacheチューニングの勘所はご理解いただけたと思う。意外にチューニング・ポイントが少なくてがっかりされた方もいるかもしれないが、Webサーバの単純さから考えればこんなものだろうと思う。多くの場合、パフォーマンスに問題が出るのは動的コンテンツだから、無理にApacheでパフォーマンスを改善するよりも、アプリケーションサーバやデータベースサーバのチューニングを行う方が賢明だ。

 重要なことは、バランスよく、少しずつ設定を変えながら様子を見ることだ。あまり急激に変化をつけても、効果が出るかどうか分からないからである。そのうえで、何をやっても望んでいるパフォーマンスと隔たりがあるようなら、性能の悪いプログラムの改良や機器の増強なども検討するべきだろう。