一つの制御用プロセス(親)が子プロセスを起動します。子プロセスはThreadsPerChildディレクティブで指定された一定数のサーバスレッドと接続をlistenするスレッドを一つ作ります。Listenerスレッドは接続が来たときにサーバプロセスに渡します。
子プロセスの位置づけだ。子プロセスは、親プロセス(制御用に起動された子プロセスを管理するプロセス)によって起動される。起動された子プロセスはさらに複数のスレッドを作成する(とりあえず今回は単位を子プロセスまでに絞るのでスレッドのことは調べなかった)。
Apacheはスペアの、つまりアイドルなサーバスレッドのプールを常に維持していて、それらは入ってくるリクエストに答えられるように待機しています。このようにして、クライアントはリクエストの応答が得られるようになるために新しいスレッドやプロセスが生成されるのを待たなくてもよいようになっています。起動初期時のプロセス総数は、StartServersディレクティブで設定されます。その後の稼働中に、Apacheは全プロセスのアイドルスレッドの合計数を見積もって、MinSpareThreadsとMaxSpareThreadsで指定された範囲の中にこの数が収まるようにforkしたりkillしたりします。この操作は非常に自律的なので、これらのディレクティブをデフォルト値から変更する必要はめったにないでしょう。同時に応答することのできるクライアント数の最大数(つまり全プロセス中の総スレッド数の最大値)はMaxClientsディレクティブで決定されます。活動中の子プロセス数の最大値はMaxClientsをThreadsPerChildで割ったものになります。
子プロセスはリクエストのたびに起動されるのではなく(そういうこともあるかもしれないが)、apache起動時(親プロセス起動時)に、設定(httpd.conf等)にしたがって複数の子プロセスを起動する(当然起動直後はアイドル状態だ)。その後、apache(親プロセス)は、アイドル状態にあるスレッド(子プロセス下で動いている)の合計数を見積もって、設定されている上限値と下限値の間で、自動でfork(起動)とkill(破棄)をする。
いちおうapacheがprefolkである(もしくは1.3系である)という前提で調査を進めた。apacheのマニュアルを見る。
http://httpd.apache.org/docs/2.2/ja/mod/prefork.html
一つのコントロールプロセスが、コネクションに対してlistenして、しかるべき時に応答する子プロセスを起動します。Apacheは常に幾つかのスペアかアイドルなサーバプロセスを維持していて、それらは入ってきたリクエストに応答できるように待機しています。このようにしてクライアントは、リクエストが応答される前に、新しい子プロセスがforkされるのを待たなくてもよいようになっています。
つまり親プロセスがポートをlistenしていて、リクエストがあると子プロセスに処理をさせるといった具合。といっても子プロセスはリクエストのたびに生成(fork)されるのではなく、親プロセスによって、サーバ設定に従い、自動的に適切な数の子プロセスをforkしたりkill(破棄)したりする。
持続的接続とは関係ないけれど、PHPに関連する部分を一つ見つけた。
通常Unixでは親プロセスは80番ポートにバインドするためにrootで起動されますが、子プロセスやスレッドはもっと低い権限のユーザでApacheによって起動されます。UserとGroupディレクティブはApacheの子プロセスの権限を設定するのに用いられます。子プロセスはクライアントに送るコンテンツ全てを読めないといけませんが、可能な限り必要最小限の権限のみを持っているようにするべきです。
apacheはrootで起動するのに、なぜapacheで(PHPで)作成したファイルの所有者がapacheになるのか(httpd.confで設定したユーザになるのか)ということに関連している。apache自体(親プロセス)はrootが起動するのだが、その親プロセスが、より権限の小さい(httpd.confで設定された)ユーザやグループの権限で子プロセスを起動する。そういう権限で動作している子プロセスの元で動いているPHPなわけだから、PHPで作成したファイルの所有者はapacheになる。
今までは「httpd.conf」でUserとGroupで設定するから、と単純に思っていたけど、動作を紐解くとそういう原理になっていたわけか。意外と面白いかも。