Apache2 - worker MPM のプロセス&スレッド数のチューニング
前エントリ pound と apache をバランスよくチューニングする必要性について の続きです。Apache2 のチューニングによる高負荷(大量アクセス)対策を考えてみます。
Apache2 はもちろん worker MPM で動作させています。worker MPM ってなんぞ?という方は、このブログを読んで頂けている方にはいらっしゃらないかと思いますが http://httpd.apache.org/docs/2.0/mod/worker.html あたりを読むと良いでしょう。
一つの制御用プロセス (親) が子プロセスを起動します。 子プロセスは ThreadsPerChild ディレクティブで指定された一定数のサーバスレッドと接続を listen するスレッドを一つ作ります。 Listener スレッドは接続が来たときにサーバプロセスに渡します。
Apache2 のチューニングでもっとも重要なのは、worker MPM の設定部分です。デフォルトでは下記のようになっているかと思います。
<IfModule worker.c> ServerLimit 16 StartServers 2 MaxClients 150 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 </IfModule>
前エントリでもお見せした下記の図ですが、pound で受け付けた全リクエストを取りこぼしなく処理するためには、MaxClients 1024 の設定が必要となります。※ただし、pound のスレッド起動最大数は起動時の ulimit の値に依存するので、一概に 1024 ではありません。
ulimit -i 8192
前述したそれぞれのパラメータの意味は下記の通りとなります。一番重要なパラメータは、全プロセス中の総スレッド数の最大値を決定する MaxClients になります。
※参考: http://httpd.apache.org/docs/2.0/ja/mod/mpm_common.html#maxclients
MaxClients
応答することのできる同時リクエスト数(クライアントに応答できるスレッドの総数)を設定します。 MaxClients 制限数を越えるコネクションは通常、 ListenBacklog ディレクティブで設定した数までキューに入ります。 他のリクエストの最後まで達して子プロセスが空くと、 次のコネクションに応答します。
StartServers
MinSpareThreads
子プロセスに十分な数のスレッドがなければ、 サーバはその子プロセスに新しいスレッドを作り始めます。
MaxSpareThreads
子プロセスにアイドルスレッドが多すぎる場合は、 サーバはその子プロセスに含まれるスレッドを終了し始めます。
ThreadsPerChild
それぞれの子プロセスで生成される スレッド数を設定します。 子プロセスは開始時にこれらのスレッドを生成して、 その後は生成しません。
MaxRequestsPerChild
あとはご自分のサーバ環境(物理メモリ容量、空きメモリ容量、httpd のメモリ使用量)にあわせて、MaxClients をどこまで上げても問題がないか、トライ&エラーで検証を行っていけば良いと思います。ちなみに僕がチューニングしたサーバでは、下記のような設定値で、実際の高負荷時にも pound がエラーを吐かない程度にまでチューニングすることができました。(※が、これはあくまで、ある特定のサーバの設定値にすぎません・・・)
チューニング前(※結構けちけち設定でした・・・orz)
<IfModule worker.c> StartServers 2 MaxClients 150 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestsPerChild 0 </IfModule>
チューニング後(※同じサーバ内で mod_perl 系 apache1 が動作しているので、あまり数値をあげられない・・・)
<IfModule worker.c> StartServers 5 MaxClients 300 MinSpareThreads 30 MaxSpareThreads 150 ThreadsPerChild 50 MaxRequestsPerChild 0 </IfModule>
ポイントは起動時に 250 スレッド起動する点。最大値は 300 だけど、起動時に上限値に近いスレッドを一気に立ち上げて、プロセス&スレッドの動的生成に要する時間をゼロ化しています。また MaxRequestsPerChild を 0 に設定されているので、プロセスが期限切れにより終了することもありません。静的コンテンツ配信なので、メモリリークとかも考えにくいので、この設定で問題なく運用できています。
MinSpareThreads と MaxSpareThreads は正直、あれこれ設定値を変更しましたけど、あまり変化はありませんでした。気分的にこんな設定値にしただけです。w
apache2 のメモリ使用量は下記の手順で大凡推測していけます。まずはプロセス ID を割り出します。
[root@srv002 conf]# ps aux|grep apache2 apache 440 0.0 0.0 19072 1640 ? S Feb09 0:00 /usr/local/lib/apache2.0.61/bin/httpd -k start root 1666 0.0 0.0 53260 748 pts/1 S+ 17:11 0:00 grep apache2 root 3783 0.0 0.0 19072 2300 ? Ss 2008 0:02 /usr/local/lib/apache2.0.61/bin/httpd -k start apache 5603 0.0 0.0 300896 6888 ? Sl 12:23 0:14 /usr/local/lib/apache2.0.61/bin/httpd -k start apache 14596 0.0 0.1 303456 10380 ? Sl Sep30 0:52 /usr/local/lib/apache2.0.61/bin/httpd -k start apache 14822 0.0 0.1 302596 8668 ? Sl Sep30 0:54 /usr/local/lib/apache2.0.61/bin/httpd -k start
次にプロセス ID を元にプロセスの状態を調べます。
[root@srv002 conf]# cat /proc/14822/status Name: httpd State: S (sleeping) SleepAVG: 88% Tgid: 14822 Pid: 14822 PPid: 3783 TracerPid: 0 Uid: 502 502 502 502 Gid: 502 502 502 502 FDSize: 64 Groups: 502 VmSize: 302596 kB VmLck: 0 kB VmRSS: 8668 kB VmData: 283728 kB VmStk: 20 kB VmExe: 546 kB VmLib: 18446744073709550266 kB StaBrk: 00591000 kB Brk: 00b38000 kB StaStk: 7fbffffcc0 kB Threads: 27 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: fffffffe3ffba207 SigIgn: 0000000000001000 SigCgt: 000000018000466b CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000
ちなみに各種パラメータの意味は下記の通りです。
VmSize | : | このプロセスが使っている仮想メモリサイズ |
VmLck | : | ロックされている(スワップアウトされない)メモリのサイズ |
VmRSS | : | 実メモリ上に存在するページサイズ |
VmData | : | このプロセスの動的仮想メモリ領域のサイズ |
VmStk | : | スタックサイズ |
VmExe | : | 実行ファイル |
VmLib | : | ロードされたライブラリのサイズ |
VmPeak | : | このプロセスがある時点で使っていた最大仮想メモリサイズ |
VmHWM | : | このプロセスがある時点で使っていた最大物理メモリサイズ |
VmPTE | : | ページテーブルのサイズ |
Threads | : | このスレッドが属するプロセスのスレッド数 |
上記の内容から、仮想メモリ的には 300MB ほど瞬間的には使っている時間帯があることが判明します。
MaxClients が 300 になっているので、1 プロセスあたり 30 スレッドくらい起動して 300MB ほどメモリを食う計算でいくと、10 プロセスくらい立ち上がって 3GB ほどメモリを食う計算になります。まぁ若干適当な計算ですけど・・・だいたいあってると思います。
後は mod_status によるステータス表示を活用して、http://サイト名/server-status とにらめっこしつつ、OS のスワップ状況に気をつけながらチューニングを進めていけば、プロセス数の最適値は割り出せると思います。
より詳細は http://httpd.apache.org/docs/2.0/ja/mod/mod_status.html からどうぞ。
その他 mod_expires による画像などの静的コンテンツのキャッシュコントロール設定なども相当効果的ですが、それはまた別エントリで。
ちなみに pound 側の設定は、下記のような設定値で落ち着きました。
User apache Group apache ListenHTTP *,80 ListenHTTPS *,443 /var/pound/cert.pem ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP Client 300 Server 3600 Alive 10 ExtendedHTTP 1 UrlGroup "/cgi-bin/.*" BackEnd 127.0.0.1,8080,1 EndGroup UrlGroup ".*" BackEnd 127.0.0.1,10080,1 EndGroup
オライリージャパン
売り上げランキング: 52069
フロントエンド方面の最適化手法がわかる本
目からウロコでした。
これからのフロントエンド・エンジニアリングの重要性
簡単なWebサイトの高速化
コメントやシェアをお願いします!