Web サーバーとしてのチューニング

全世界的に、Web サーバーとしては Apache が一番多く使われています。その Apache を利用する際になるべく最適な環境を作る方法についてまとめてみます。

1. はじめに

Apache の設定ファイルは、httpd.conf、srm.conf、 access.conf と三種類ありますが、最近のバージョンではほとんど httpd.conf のみで行います。Apache 2.0 では、srm.conf, access.conf は無くなります。そこで、設定はすべて httpd.conf で行なうものと思って作業してください。

2. Apache のチューニング(httpd.conf)

設定ファイルでは、幾つかディレクティブがあります。その中で注意して設定することで、Apache を最適に動作させるディレクティブ説明と方法を記述します。

2.1. HostnameLookups

HostnameLookups は、Web サーバーである Apache にアクセスしてきたクライアント(ブラウザを利用しているPCなど)の情報をアクセスログに記録する際に IP Address で記録するか ホスト名で記録するかを設定します。on と設定することで、IP Address から DNS でホスト名を逆引きしてアクセスログに記録します。off の場合、そのまま IP Address で記録します。この時、やはりアクセスログはホスト名で記録されている方が分かりやすいので on に設定しがちです。しかし、DNS による逆引きはシステムに負荷をかけます。そこで、ログファイルを解析する際に重視するファイルに対してのみに対して逆引きをするように設定します。例は、.html と .cgi のアクセスだけ DNS による逆引きを行ないます。

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

HostnameLookups を off にしておき、ログファイルを参照する時に logresolve コマンドで DNS による逆引きを行う方法もあります。

2.2. DirectoryIndex

ディレクトリに対する(末尾が「/」で終わる URL への)アクセスがあった場合に、 実際のディレクトリの中身の一覧の代わりに 転送するファイルのファイル名を設定します(デフォルトは index.html)。この事を、コンテンツ・ネゴシエーションといいます。もし、Web サーバーに最高のパフォーマンスを要求するなら、このネゴシエーション機能を無効にすることですが、ある程度機能低下を伴っても利用する利点はあります。その中で、なるべく Web サーバーに負荷をかけないようにするには、

    DirectoryIndex index

という具合にワイルドカードを利用するのではなく

    DirectoryIndex index.html index.shtml index.cgi

と全て羅列することです。一番頻繁に使うものをリストの先頭に記述する。本当なら、index.html のみの方がよい。

2.3. AllowOverride

アクセス権の設定を、AccessFileName で指定したファイル(.htaccess)の内容によって上書きできる属性を指定します。セキュリティの観点などから一切上書きを許可しない場合には None を設定します。しかし、どうしても上書きを許可したい場所がでてきた場合、許可するパス以降に対してのみ設定するようにして下さい。例えば、

    DocumentRoot /home/httpd/html
    <Directory />
        AllowOverride All
    </Directory>

として /index.html の URI をリクエストをした場合、Web サーバーは /.htaccess, /home/.htaccess, /home/httpd/.htacsess, /home/httpd/html/.htaccess を開こうとします。このようなことが無いように AllowOverride を指定しなければならなくなった場合は以下のように明確に指定する。

    DocumentRoot /home/httpd/html
    <Directory />
        AllowOverride none
    </Directory>
    <Directory /home/httpd/html>
        AllowOverride All
    </Directory>

パフォーマンスを追求するなら、どんなところでも AllowOverride None とすることをお勧めします。

2.4. Option の FollowSymLinks と SymLinksIfOwnerMatch

シンボリックリンク先の参照を許可する FollowSymLinks は、シンボリック先を参照するのは安全性に問題があるので利用しない方が良いと考えます。しかし、ファイルやディレクトリーがシンボリックされているかどうかチェックするためにそれぞれのファイルやディレクトリーに対して lstat 関数を実行します。さらに、lstat の結果はキャッシュされないのでリクエストのたびに発生します。これは、パフォーマンスを考えると非常に問題になります。また、シンボリックリンクファイルの持ち主とリンク先ファイル/ディレクトリの持ち主が同じだった場合にリンク先を参照することを許可する SymLinksIfOwnerMatch は、設定されるとパフォーマンスに影響します。でも、どうしてもセキュリティーチェックが必要なら以下のような設定をお勧めします。

    DocumentRoot /home/httpd/html
    <Directory />
        Options FollowSymLinks
    </Directory>
    <Directory /home/httpd/html>
        Options -FollowSymLinks +SymLinksIfOwnerMatch
    </Directory>

このように設定することで、少なくとも DocumentRoot までの余分なパスのチェックが要らなくなります。Alias や RewriteRule で設定したパスに対しても同様な処理をする必要があります。最高のパフォーマンスを引き出すには、全ての箇所に FollowSymLinks を設定し、SymLinksIfOwnerMatch を絶対に設定しないことです。

2.5. プロセスに関するディレクティブ

MaxSpareServers, MinSpareServers, StartServers を運用する目的に適した値に設定することで、パフォーマンスを最適に設定することができます。

StartServers
Apache の起動時にいくつの分身サーバを作成するかを設定します。

MaxSpareServers
リクエスト待ち状態のサーバプロセスが、最大いくつまでいてもよいかを設定します。 メインの Apache はリクエスト待ち状態のサーバプロセスが ここで設定した数よりも多くなると、余ったサーバを適宜終了させます。アプリケーションサーバーなどを構築して運用する場合、システムの CPU やメモリを増設しても、この値を適切な値に設定しないとパフォーマンス強化の効果が得られないので注意してください。

MinSpareServers
リクエスト待ち状態のサーバプロセスが、最小いくついなくてはならないかを設定します。 メインの Apache はリクエスト待ち状態のサーバプロセスが、ここで設定した数よりも少なくなると適宜必要な数だけ分身のサーバを生成します。

Apache 1.3 以降では、子プロセスを1つ発生させ1秒待ち、2つ発生させ1秒待ち、4つ発生させ1秒待ちという要領で1秒あたりの子プロセスを32発生させるまで乗数的に続きます。(MinSpareServers を満たした時点で止まる)これだけのレスポンスがあればデフォルトの設定をいじらなくても大丈夫かも知れませんが、1秒間に4つ以上の子プロセスが発生すると ErrorLog にメッセージが記録されます。このメッセージが頻繁に発生するようになったら上記3つの設定を変えることを検討すると良いでしょう。

MaxRequestsPerChild によって子プロセスの消滅を指定できます。指定したリクエストを処理すると消滅することで、プロセスが肥大化するのを防ぐ目的で使用されます。初期値が 30 となっていますが、ページが静的なものであれば 10,000 ぐらいまで上げても問題にはならない(もっと上げても大丈夫)。mod_perl などを利用する際は調査が必要です。

MaxClients によって、サーバーが同時にアクセスを受け付けられるクライアント数の最大値を設定します。この設定は、MaxRequestsPerChild の値と MaxSpareServers, MinSpareServers, StartServers の値等を考慮して設定するとよい。

keep-alives が使われている場合、既に開かれている接続により子プロセスが何もしない状態で次のリクエストを待っている。KeepAliveTimeout の設定は、この待ち時間を設定するものだが 60秒以上にしてはいけない。

3. Linux のチューニング

3.1. ファイルディスクプリタ

Web サーバーマシンとして Linux を利用する場合、システムが一度にオープンできる最大ファイル数と最大 i-node 数を増やしておくと良い(バージョン 2.2 カーネルで、デフォルトの4倍ぐらいが推奨値)。システムの起動スクリプトに、以下の行を追加することで Web サーバーが可能な限り多くのシステムリソースを使用できるようにする。

    echo 16384 > /proc/sys/fs/file-max
    echo 49152 > /proc/sys/fs/inode-max

Linux の /proc ファイルシステムは、ユーザーとカーネルのインターフェースを提供します。ユーザーは、幾つかの読み込み専用のファイルを参照することで、カーネルの利用率に関する統計情報を確認できます。top, vmstat というコマンドを利用すれば、それら統計情報を取得して表示してくれます。

3.2. プロセス

Linux の 2.2 カーネルでは、1ユーザー当たり 256 プロセスという制限があるのでスレッドの作成が制限される場合があります。これを変更するには、/usr/src/linux/include/linux/tasks.h の NR_TASKS, MAX_TASKS_PER_USER を修正する必要があります。

/usr/src/linux/include/linux/tasks.h
    #define NR_TASKS 1024
    #define MAX_TASKS_PER_USER (NR_TASKS-256)

修正後、カーネルを再構築します。カーネル 2.2.14 では、デフォルトで 2048 になっています。

3.3. 物理メモリ

Linux は、デフォルトで 1GB 以上のメモリが載っていても、1GB までしか使用しません。(1GB の一部は除外され、実際には 950MB )もし、2GB のメモリを載せているなら、メッセージングパフォーマンスが強化される可能性があります。それには、/usr/src/linux/include/asm-i386/page.h と /usr/src/linux/arch/i386/vmlinux.lds を修正する必要があります。このメモリ制限の拡張によって、動作しなくなるもの(boot ramdisk 等)があります。

 
    1GB 0xC0000000/ 2GB 0x80000000/ 3GB 0x40000000
/usr/src/linux/include/asm-i386/page.h
    #define _PAGE_OFFSET (0x80000000)
/usr/src/linux/arch/i386/vmlinux.lds
    .=0x80000000 + 0x100000;

修正後、カーネルを再構築します。カーネル 2.2.14 では、ソースを編集しなくても、カーネルコンフィグレーション(make menuconfig 等)の "Processor type and features" の "Maximum Physical Memory" で設定できます。

3.4. ファイル情報の更新

Linux は、デフォルトでファイルの読み込みごとにアクセスタイムをディスクに書き込みます。もし、単なるファイルの読み込みに対するアクセスタイムの情報が必要ないのなら noatime オプションによって余計なディスク書き込みを回避することが出来ます。それには、/etc/fstab を以下のように修正します。アクセス時刻情報を必要とする tmpwatch 等は動作しなくなるので、これらのアプリケーションが利用しないパーティションのみの変更にしてください。

/etc/fstab
    /dev/sda6  /disk  ext2  defaults,noatime  1  2

3.5. スワップサイズと高速化

意外と、スワップについてあまり意識しない方が多いのでは無いでしょうか?確かに Linux システムは、スワップサイズの設定(デフォルトスワップ・サイズ:128 MB)を意識しなくても良いぐらいメモリー効率が優れています。しかし、これはデスクトップ・システムには当てはまりますが、サーバー・システムには必ずしもあてはまりません。サーバーの場合、予期せぬストレスに耐えなければなりません。例えば、クライアント側で中断したプロセスがサーバー上にいつまでも残るランナウェイ・プロセス、クライアント側から故意に不正な処理を行いサーバーの過負荷を引き起こすサービス拒否アタック、短時間に多くのクライアントの要求が殺到するスラッシュドット効果などにたえなければなりません。これには、高速なスワップを適切に設定しなければ、物理メモリーを使い尽くしてサーバーが停止またはクラッシュしてしまいます。

Linux 2.2 以降のカーネルでは、スワップサイズが 128 MB という制限はなくなったので、スワップに多くの領域を割り当てられるようになりました。(現在は、x86系の CPU で約 2 GB)でも、パフォーマンス改善は?確かに、領域が増えてもパフォーマンスの改善はみられません。この改善の方法として、複数のスワップ・パーティションを RAID 0(ストライピング)に設定し、すべてのパーティション間で読み書きを均一に分散すると効率的です。もし、これらのパーティションが別 々のドライブや制御装置にあると、サーバーはメモリー使用率の "スパイク" (瞬間的急上昇) をすばやく処理できるようになり、スワップ・ファイルのパフォーマンスが格段に向上します。 スワップにそんな贅沢な設定ができるか!とお叱りを受けそうですが、なんと最新の Linux カーネルでは、デフォルトで RAID 0 のようにスワップを並列化することができます。それには、/etc/fstab でスワップパーティションを複数指定する際に、pri オプションを使って優先度を同じに設定することで、スワップパーティションを並列に使用するようになります。

複数のスワップ・パーティションを同じ優先度する方法 (/etc/fstab)

      /dev/sda2       none    swap    sw,pri=5        0       0
      /dev/sdb2       none    swap    sw,pri=5        0       0
      /dev/sdc2       none    swap    sw,pri=2        0       0

上記のように設定すると、スワップ・パーティションである sda2 と sdb2 を並列に使用するようになります。これらのパーティションはそれぞれ別のドライブなので、読み書きのスループットがほぼ 2倍に向上します。3番目のスワップ・パーティションである sdc2 は、優先度が低いので最初の 2つのパーティションがいっぱいになった時にのみ使用されます。

pri オプションの優先度の指定は、0 から 32767 までの間の数値で指定します (32767 が最高の優先度)。それぞれのスワップ・パーティションは、優先度の高い順に使用されます。つまり、優先度の低いパーティションは、優先度の高いパーティションがいっぱいになった場合にのみ使用されます。いくつかのパーティションの優先度が同じであれば、自動的にそれらのパーティションに並列にアクセスします。この優先度を設定する方法は並列化でなくても、最も高速なドライブを常に使用されるスワップ・パーティションとして優先度を設定し、非常用スワップ・パーティションとして低速なドライブを指定するといった設定をすることもできます。

 

 

Copyright (C) 2001 Shin Motomiya, All Rights Reserved.