VPS構築ついでにApacheの最適化を行おうと思い立ち、例によって備忘録ついでに書いておきます。
この記事の内容
- はじめに
- ホスト名逆引きの停止
- 持続的接続の調整
- MPMの調整
- コンテンツの圧縮転送
- ログの整理
- 不要なモジュールの停止
はじめに
この記事はApache HTTPDの動作効率改善を目的とし、その最適化を行うものです。環境や条件によって最適解は異なってきますので、あくまで参考としてご利用ください。
なお、この記事では主にApache 2.0系を対象にしています。その他のバージョンでは設定内容が異なることがありますのでご注意ください。
ホスト名逆引きの停止
Apacheは標準でリクエスト毎にDNSの逆引きを行なっており、ホスト名をログに記録したりドメインベースでの認証に利用しています。しかしこの処理は非常に遅く、リクエストの処理もそれだけ遅れてしまいます。
特に事情がなければ逆引きを停止してしまいましょう。ただしPHPなどにはホスト名を渡すようにします。
HostnameLookups off <File ~ "\.(py|pl|php|cgi)$"> HostnameLookups on </File>
持続的接続の調整
これはクライアントとの接続を一定時間持続させ再接続のコストを軽減する「KeepAlive」。これはぜひ有効にしたいものですが、この設定を誤ると処理効率が悪化し、逆にこれを無効にしたり極端に短くすると負荷が増えてしまうという悩ましい設定です。
KeepAliveTimeoutは一般的には2秒程度がもっとも効率がいいようです。MaxKeepAliveRequests(持続接続で一定以上リクエストをこなしたら一旦切断する)は1ページで読み込む平均的なファイル数に少し余裕を加えた数を指定します。
KeepAlive On KeepAliveTimeout 2 MaxKeepAliveRequests 50
MPMの調整
MPM(Multi Processing Module)の設定は、もっとも大きくパフォーマンスに関わる部分です。主に「同時並行でどれだけのリクエストを処理するか」に関わる設定で、大きくするとそれだけサーバーの負荷が増大し、小さくしすぎると大量のリクエストを捌ききれなくなってしまいます。
prefork
標準の動作モードであるprefork MPMでは、プロセスの数を設定します。この設定は標準のままにしておくとメモリの少ないサーバーで過負荷になることがあります。特にPHPなどを走らせればそれだけメモリを食いますので、サーバーにあわせて設定しておきましょう。
説明
<IfModule prefork.c> StartServers 8 MinSpareServers 5 MaxSpareServers 20 ServerLimit 256 MaxClients 256 MaxRequestsPerChild 4000 </IfModule>
StartServers
は起動時に生成するサーバープロセスの数です。MinSpareServers
とMaxSpareServers
はそれぞれクライアントの要求を待ち受けるアイドルプロセスの最小・最大数を指定します。これらの値は非常にアクセスの多いサーバーを除いて初期値のまま運用すべきであり、設定次第ではパフォーマンスが大きく低下してしまう恐れもあります。
MaxClients
は同時に処理できるクライアントの数、つまり最大同時接続数を設定します。preforkでは一つの接続に対しプロセスが一つ割り当てられるため、最大常駐プロセス数を制限するServerLimit
は通常MaxClientsと同じ値にします。
プロセスはMaxRequestsPerChild
の数だけリクエストを処理すると強制終了し再生成されます。0にすると無制限になりますが、メモリリークがあると悲惨なことになります。プロセスの再生成にはそれなりのコストがかかるとはいえ、できれば定期的に終了しメモリを解放すべきでしょう。
サーバーにあった設定を
MaxClients=ServerLimitは、設定を大きくすればそれだけメモリを消費します。たとえば1つのプロセスが平均2MBのメモリを消費するなら、標準設定の256個だと最大で2×256=512MBが使用されます。メモリが底をつくとスワップに入りますが、アクセス過多時にスワップが起こると極端にパフォーマンスが低下します。
静的リソースばかりならまだしも、PHPなどを走らせる場合は特に注意が必要です。軽量なスクリプトやとても行儀よく設計されたアプリケーションはともかく、たとえばWikiなどでは内容の多いページでかなりのメモリを消費します。php.iniのmemory_limit
を大きくしすぎない(デフォルトでは128MB!)のも重要ですが、なにより平均的なメモリ使用量を監視して適切な設定を行うようにしましょう。
MaxRequestsPerChild
も同様で、特にmod_perl、modo_phpなどを動作させる場合は念のため50-100程度の値にすべきでしょう。そうでない場合もあまり多くない値にしておくのが安全です。
worker
大量のアクセスをより効率よく処理できるworker MPMでは、プロセス数ではなくスレッド数を設定します(他にもさらに効率のいいevent MPMなどがあります)。
ちなみにマルチプロセスモデルのpreforkが仕組み上プロセス数(つまり同時処理するリクエストの数)に応じてメモリを消費するのに対しworkerは行儀よくメモリを節約するなど高効率な処理が望めるのですが、PHPなど一部のモジュールが正常に動作しないという話もあり(詳細)、導入には慎重な姿勢が必要です。
設定
Note: 一般的にはpreforkで動作させているケースがほとんどですので、ここでは概要のみ説明します。
基本的にはpreforkと似通っていますが、こちらはMinSpareServersおよびMaxSpareServersのかわりにそれぞれMinSpareThreads
とMaxSpareThreads
で待機スレッド数の上限と下限を設定します。
workerでは一つのスレッドが一つの接続を受け持つため、最大同時接続数(MaxClients)はすなわち最大スレッド数となります。スレッドはプロセス起動時にThreadsPerChild
の数だけ生成され、スレッド総数はプロセスの生成・削除により増減されます。
コンテンツの圧縮転送
非圧縮のテキストファイルをそのまま転送するのはとても非効率です。できれば圧縮して転送時間を短縮しましょう。転送量も削減できます。
以下の手順のどちらかを設定します。
mod_deflate
mod_deflateを使用して、毎回ファイルを圧縮します。ただしCPUリソースを食うので処理能力に余裕が無いならこの設定は禁物です。後述のあらかじめ圧縮しておく手法を使うならこの設定は不要です。
手順は対象のMIMEタイプに対し「AddOutputFilterByType
」を指定するだけです。
<Directory /path/to/directory> AddOutputFilterByType DEFLATE text/plain text/html text/css application/javascript application/xml </Directory>
MultiViews
あるいは手間が多くなりますが、あらかじめファイルを圧縮しておくほうがより有効です。これなら少ない処理で転送時間を短縮できるので、パフォーマンスを大きく改善できます。
手順としては、まずGZip圧縮したファイル(example.html.gz
)と非圧縮のファイル(example.html.html
)を用意します。後は「Options MultiViews
」を有効にすれば完了です。
Note: 非圧縮ファイルの拡張子が重複していることに注目してください。これはApacheにどちらのファイルを転送させるか選択させる上で必要です。
<Directory /path/to/directory> Options MultiViews </Directory>
このファイルに対して~/example.html
というアドレスでアクセスするとApacheにより最適なファイルが選択され、対応ブラウザには圧縮されたファイルが、そうでない環境には非圧縮のファイルが転送されます。
ログの整理
Apacheでは、リクエストの都度アクセスログをログファイルへ書き出しています。毎度余分な書き込みアクセスが発生するとなると、積もり積もれば結構なオーバーヘッドになります。
ログのバッファ
この負荷を減らすには、単純に書き込みの頻度を少なくしてやります。Apache 2.0.41からはこのアクセスログを一旦メモリに貯めておき、ある程度溜まってからまとめてログファイルに書きだすBufferedLogs
というディレクティブが追加されました。まだexperimental(試験的)な機能ですが、パフォーマンスは確実に改善されるのでこれを検討しない手はありません。
httpd.confに以下の設定を追加します。
BufferedLogs On
ログの分割
アクセスログファイルは際限なく追記され、たとえそれが何十GBになろうとApacheはお構いなしに記録を続けます。もちろんアクセスの多いサーバーでディスク容量が食いつぶされるのは目に見えていますし、肥大化するファイルに追記を続ければパフォーマンスの低下も避けられません。rotatelogs
を使用して定期的にログファイルを分割します。
httpd.confのログファイル保存先を以下のように書き換えます。ログの保存先は適宜変更してください。
CustomLog "|/usr/sbin/rotatelogs /path/to/logs/access.%Y%m%d.log 86400 540" combined ErrorLog "|/usr/sbin/rotatelogs /path/to/logs/error.%Y%m%d.log 604800 540"
もっともこの方法はパイプ出力しているので単純な書き出しに比べるとどうしても負荷が増えますが、どうしようもない巨大ファイルができることを思えばはるかにマシです。
古いログの圧縮
分割されたログはそのままだとディスク容量を圧迫するので、古いログは圧縮してしまいましょう。
ログを圧縮するシェルスクリプトを作成します。ログの保存先は先ほど指定した場所に読み替えてください。
Note: この例では高圧縮のbzip2を使用していますが、これはシングルスレッドで動作します。マルチコアCPUを積んでいるなら、並列処理に対応したpbzip2を利用するとより高速に処理できます。
# sudo vim /usr/bin/logcompress.sh
#!/bin/sh LANG=C cd /path/to/logs for i in `find . -name "*.log" -mtime +2` do bzip2 -9 $i done
次にこれを実行可能にした後、定期的に起動するためcronに登録します。
#sudo chmod 755 /usr/bin/logcompress.sh # sudo crontab -e
15 9 * * * /usr/bin/logcompress.sh >/dev/null
ログファイルは午前9時(UTCの午前0時)を以て分割されるので、9時過ぎに走らせています。
不要なモジュールの停止
Apacheでは標準で様々なモジュールが読み込まれていますが、中には一般的には必要ないモジュールも多く含まれています。どうせ使わないなら、思い切って不要なモジュールの読み込みをコメントアウトしてしまいましょう。
認証
LDAP認証など一般用途では使わいでしょうから、これを外しておきます。他にも目的に応じてコメントアウトしておきましょう。
#LoadModule ldap_module modules/mod_ldap.so #LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
プロキシ
通常のWebサーバーではプロキシ機能はまったく不要です。すべて無効化しましょう。
#LoadModule proxy_module modules/mod_proxy.so #LoadModule proxy_balancer_module modules/mod_proxy_balancer.so #LoadModule proxy_ftp_module modules/mod_proxy_ftp.so #LoadModule proxy_http_module modules/mod_proxy_http.so #LoadModule proxy_connect_module modules/mod_proxy_connect.so
ただしconf.d
ディレクトリ内にproxy_ajp.conf
ファイルがある場合は、これを忘れず編集しておきます。さもなければ設定の構文エラーと判断されhttpdの起動に失敗します。
# sudo vim /etc/httpd/conf.d/proxy_ajp.conf
mod_proxy_ajp.so
を無効化します。
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
ログ、ステータス、バージョン
mod_usertrack
はCookieを用いてユーザーの行動を追跡し、ログに記録する機能です。Apacheのアクセスログでそこまで行う意味については疑問です。mod_status
とmod_info
はそれぞれステータスやサーバー情報のページを吐き出す機能です。mod_version
は複数バージョンのApacheを動作させる時にそれぞれの設定を切り替えるディレクティブを提供します。これらはすべて不要でしょう。
#LoadModule usertrack_module modules/mod_usertrack.so #LoadModule status_module modules/mod_status.so #LoadModule info_module modules/mod_info.so #LoadModule version_module modules/mod_version.so
キャッシュ
コンテンツのキャッシュを行わないならこれらのモジュールをすべて無効にします。
#LoadModule cache_module modules/mod_cache.so #LoadModule disk_cache_module modules/mod_disk_cache.so #LoadModule file_cache_module modules/mod_file_cache.so #LoadModule mem_cache_module modules/mod_mem_cache.so
参考サイト
- [@IT] httpd.confによるWebサーバの最適化
- [Turbolinux 11 Server: ユーザーガイド] 9.6. MPM(Multi-Proccessing Module)の設定
- [とある暇人のメモ帳] apache(prefork)の設定で悩まないようにメモ
- [プログラマー某の外部記憶] さくらVPS+wordpressでパフォーマンステストしたら応答なくなったwww
- [ftp-adminの憂鬱] BufferedLogsは効果絶大
- [ftp-adminの憂鬱] ログローテーションはrotatelogsで、圧縮はpbzip2で
- [(っ´∀`)っ ゃー] ログ圧縮方法
No comments:
Post a Comment