Apache2 - worker MPM のプロセス&スレッド数のチューニング

前エントリ pound と apache をバランスよくチューニングする必要性について の続きです。Apache2 のチューニングによる高負荷(大量アクセス)対策を考えてみます。

ここまできてやっと、そもそも高負荷時に apache2 のプロセス数が足りていなく、静的コンテンツの応答時間が遅延しているのかも?という仮説を立てることができました。図解するとこんな感じです。

Apache2 はもちろん worker MPM で動作させています。worker MPM ってなんぞ?という方は、このブログを読んで頂けている方にはいらっしゃらないかと思いますが http://httpd.apache.org/docs/2.0/mod/worker.html あたりを読むと良いでしょう。

このマルチプロセッシングモジュール (MPM) は、マルチスレッドとマルチプロセスのハイブリッド型サーバを 実装しています。リクエストの応答にスレッドを使うと、 プロセスベースのサーバよりも少ないシステム資源で、 多くのリクエストに応答することができます。 さらに、多くのスレッドを持った複数のプロセスを維持することで、 プロセスベースのサーバの持つ安定性を保持しています。
一つの制御用プロセス (親) が子プロセスを起動します。 子プロセスは 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 -n 8192
ulimit -i 8192

img002.png

前述したそれぞれのパラメータの意味は下記の通りとなります。一番重要なパラメータは、全プロセス中の総スレッド数の最大値を決定する 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


ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール
Steve Souders スティーブ サウダーズ
オライリージャパン
売り上げランキング: 52069
おすすめ度の平均: 4.5
5 仕事で作る人、趣味で作る人、両方にためになります
4 フロントエンド方面の最適化手法がわかる本
5 目からウロコでした。
5 これからのフロントエンド・エンジニアリングの重要性
4 簡単なWebサイトの高速化
- スポンサーリンク -