2014年2月24日月曜日

worker MPMの設定

MPMは、Apache 2.4でのデフォルトは event MPMになる。
event MPMは Apache 2.2で追加になったが、長らくexperimentalという位置づけだった。
機能的には worker MPMの改善版となるので、 機能的/性能的にはもっとも優位となるだろう。
問題は品質面の評価だが、少なくとも実績という観点では他のMPMに劣ると考えられる。

デフォルトであるevent MPMの設定から見ていきたいが、event MPMはほとんどの設定がworker MPMと共通だ。
そこで、歴史的な順序に従い、まず、worker MPMの設定から見ていく

まず、前提として、Apacheの設定と言うのは、設定ファイルに書く。
普通はインストールしたディレクトリの conf/httpd.conf とかいったファイルだ。
テキストファイルで、普通のテキストエディタで編集すればよい。
たとえば、下記。

DocumentRoot    /usr/local/apache/htdocs

最初の "DocumentRoot" が設定する項目名で、ディレクティブ、と呼んでいる。
つづく、"/usr/local/apache/htdocs" はその設定値。
ディレクティブがとる値は、1つだったり2つだったり、ディレクティブによって異なる。

設定の話では、このディレクティブの説明をしていく。


worker MPMの設定


Apacheプロジェクトのドキュメントのページはここ。


ThreadsPerChild

1プロセス内に生成するリクエスト処理用ワーカスレッドの数。
指定しない場合のデフォルトは25。
ThreadLimitで指定された値以下でなくてはならない。
ThreadLimit以上の値を指定すると、その値は無視されてThreadLimitの値で上書きされる。
また、負の値を指定した場合にも、その値は無視されて1が設定される。

MaxRequestWorkers

同時に処理できるリクエストの上限数。
これは全体のリクエスト処理用ワーカスレッド数ということになる
1プロセスにはThreadsPerChildのワーカスレッドが作られるので、MaxRequestWorkersはThreadsPerChild以上であることが必要となる。
そして、MaxRequestWorkers÷ThreadsPerChild(個)の子プロセスが生成される。
もし、MaxRequestWorkersがThreadsPerChildの倍数になっていなければ、内数に丸められる。
MaxRequestWorkerが99で、ThreadsPerChildが10なら、MaxRequestWorkerがThreadPerChildの倍数で、指定した値のより小さい値に丸められ、この場合なら、90になる。
そして、リクエスト処理用に最大で、90÷10=9(個)の子プロセスが生成される。

簡単にいえば、この値が大きい程、大勢のクライアントに対応できる訳だが、
同時というのが曲者で、たとえば、この上限値が1であっても、いくつかのブラウザが同時に行ったリクエストにレスポンスを返すことは、だいたいできる。
最初に受け取ったリクエストの処理中、次のリクエストがリクエスト受付用のソケットのバックログで受付待ちの状態で待機するからだ。この場合も、TCPの状態としてはESTABLISHEDかSYN_RECV状態になっている。
先のリクエストがレスポンスを返すと、この待ち状態のリクエストが直ちに受け付けられて、次に処理される。
処理性能は、リクエストの処理に要する時間であるとか、この待ち受け状態のキューに溜っていられるリクエストの数だとか、あるいは、ブラウザ側がリクエストを行ってレスポンスを受け取るまでどのくらい待つとかいった条件の中から、1秒あたりに処理可能なリクエスト数、とか、1リクエストの処理にかかる時間という形で、MaxRequestWorkesの値とは別に決まっていく。
大体、今時のWebシステムは、ApacheがHTMLを返すだけで終わることは珍しいので、実際にレスポンスを作成するWebアプリケーションの処理能力に見合う数の上限数を定めるのがよい気がする。

StartServers

起動時に生成する、リクエスト処理用の子プロセス数。
MaxRequestWorkersを越えるワーカスレッドを生成することはできないので、そのような大きな値を指定しても指定の通りには動かない。
しかし、大きな値を指定してもエラーとかは出ないようだ。
ただ、負の値を指定した場合には、1が設定される。
デフォルトは3。

MaxSpareThreads

リクエストを処理するワーカスレッドのうち、リクエスト処理中でないワーカスレッドをアイドル状態という。
実行中のApacheはいくつかのアイドル状態のワーカスレッドを用意してリクエストを待っていることができる。

スレッド型のMPMの場合は、1つの子プロセスにThreadsPerChild個のワーカスレッドがあるので、子プロセスが1つ実行されていれば、
最大でThreadsPerChild個のアイドル状態のワーカスレッドを持つことになる。

アイドル状態のワーカスレッドがいると、リクエストを受信したときに直ちにそのリクエストの処理が可能だが、アイドル状態のワーカスレッドがいない場合、つまり全てのワーカスレッドがリクエスト処理中の場合、リクエストを処理するには新しい子プロセスを生成して新しいワーカスレッドを用意しなければ。処理できないことになる。
つまり、アイドル状態のワーカスレッドがいると、リクエストの受付から処理実行までがスムーズに行えて都合がよい
そのための、アイドル状態のワーカスレッドを常時どのくらい用意しておくかという設定がこのMaxSpareThreadsと、MinSpareThreadsだ。

Apacheは、アイドル状態のワーカスレッド数が、MinSpareThreads個以上MaxSpareThreads個以下になるように、子プロセスを追加生成したり、実行中の子プロセスに終了指示をあたえたりしている。
MaxSpareThreadsはアイドル状態のワーカスレッドの最大値、ということだ。
この設定値以上のアイドル状態のワーカスレッドが実行中だった場合、Apache子プロセスに終了指示を出す。
1つの子プロセスが終了すれば、アイドル状態のワーカスレッド数がThreadPerChild個少なくなることになる。

もともとMaxRequestWorkers個のワーカスレッドが実行中で、しかも全てがリクエストを処理中だということあれば、それ以上のワーカスレッドは生成できないので、どこかのワーカスレッドが処理を終えるまでリクエストは受け付けられないことになる)

MinSpareThreads

アイドル状態のワーカスレッドの最小値となる。
Apacheはアイドル状態のワーカスレッド数がこの設定値を下回ると、新しい子プロセスを生成する。
1つの子プロセスが生成されると、ThreadPerChild個のアイドル状態のワーカスレッドが増えることになる。

アイドル状態のワーカスレッドは、その時点では必要のないスレッドなので、リソース的な観点を重視すると、あまり無駄なスレッドは用意したくない。その場合、アイドル状態のワーカスレッド数を低く抑えるように設定するだろう。
しかし、リクエストを受け付けて直ちに処理に移れない状態というのも、スループットという点ではあまりうれしくはない。
リソース面で許容可能範囲で、多めに用意しているのが良さそうだ。
とは言っても、実際のリクエスト数が1時間あたり100件程度というような場合に、リソースに余裕があるからと言ってMinSpareThreadsを1000にしてみてもあまり意味はなさそう。

ServerLimit

子プロセス数の最大値。
実際に生成される子プロセス数の上限は、MaxRequestWorkers÷ThreadsPerChild(個)で、この値が、ServerLimitを越えないこと、という値だ。
デフォルトでは16なので、MaxRequestWorkers÷ThreadsPerChildが16を越える場合には、この設定で値を変更する必要がある。
ただし、20000(MAX_SERVER_LIMIT)を越えることはできない。

ThreadLimit

1プロセスあたりのワーカスレッド数の最大値。
1プロセスに実際に生成されるワーカスレッド数は、ThreadPerChild個なので、この値が、ThreadLimitを越えないこと、と言う値となる。
デフォルトでは64なので、これを越える場合には、この設定で値を変更する必要がある。
ThreadLimitで指定可能な最大値はworkerMPMで20000。event MPM では100000まで可能なようだ。
なぜ、ThreadsPerChildをそのまま使わないのかというのが、私には直感的には理解できないが(ServerLimitも)、プログラム内では、ワーカスレッドやプロセスを管理するテーブルサイズをこのServerLimit、ThreadLimitで決めている。
つまり、メモリ上の管理領域のサイズは、この設定値で決まっていて、実際に利用される領域というのがThreadsPerChildやMaxRequestWorkersなどの値で決まってくる。
なぜそんな二重管理をしているのか、やはりよく分からない。
Apacheのドキュメントにも書かれているが、このServerLimitとThreadLimitは「再起動」で変更が反映されない設定だが、ThreadsPerChildなどは再起動で設定の変更が反映される。
再起動の前後で管理テーブルは連続的に利用されるので、たぶん処理の都合があったのだろう。

MaxConnectionsPerChild

1つの子プロセスが処理する最大の接続数を指定する。
1つの子プロセスがこの指定された数の接続を処理し終えると、その子プロセスは終了する。
もし、指定値が0であった場合は、無制限に処理することを意味する。デフォルトは0だ。

ここで言う接続数は、クライアントとサーバの間で繋がるTCP接続の数のことだ。
Apache 2.2では、MaxRequestsPerChildという名称だったが、変更になった(ただし、MaxRequestsPerChild も使用できる)。
HTTP keep-alive通信の場合、一度TCP接続がサーバ-クライアント間で確立すると、複数のリクエストがこの接続でやり取りされる。
しかし、この一つの接続で何回リクエストのやり取りがあろうとも、接続数は1となる。
MaxRequestsPerChildと言う名称は、このような接続でやりとりされるリクエストの数を対象とするような響きがあるので、変更されたのかもしれない。
調べれば分かりそうだが、調べていない。

この値は、私のまわりでは 0 で問題は出ていない。
私の理解では、この設定は、何か行儀の悪いモジュールを使っていて、メモリがリークしているとか続けて長期間使うことに問題があるような事情がある場合に、一定の処理を経てプロセスを終わらせることで問題が顕在化することを避けるための機能だ。
私のまわりではたいてい、毎日か毎週かの間隔でApacheを再起動しているので、何らかの問題があってもこのわざわざこの設定を加える必要まではない、というところか。

モジュールって何だ、という話はまだ書いていない。


0 件のコメント:

コメントを投稿