Apache MPMとはなんぞやという話

Apache のチューニングにあたって MPM について知ったときのメモ、なんとなくの概要。
Apache MPM is 何か、ざっくりと。

Webサーバの実装モデルの話

MPMの話に入る前に、Webサーバの基本的な並行処理のモデルをおさえておきます。

Webサーバに接続するクライアントが1人だけであれば、並行処理について考えることは少ないでしょう。しかし、多くの場合は同時に複数人のクライアントに対応しなければなりません。 そういった状況でリクエストを並行処理するためのWebサーバの実装モデルがいくつかありまして、代表的なものを簡単におさらいします。

マルチプロセスモデル

クライアントからのリクエストごとに fork をして子プロセスを生成し、その子プロセスに処理を委ねる方式です。

プロセスの fork では、メモリ上の親プロセスのアドレス空間を、生成した子プロセスのアドレス空間にコピーします。したがって、その分のコストが発生し、低速と言われています。また、リクエストが増えれば増えるほど、子プロセスの数とそれに伴うメモリ消費量も増えてしまいます(すべての子プロセスがPHPインタプリタおよび関連ライブラリをロードする)。

この方式の利点として、メモリ空間がプロセスごとに独立しているためスクリプト言語などを組み込みやすい、後述のマルチスレッドモデルと違い資源の競合について考慮しなくてよい、などが挙げられます。

マルチスレッドモデル

クライアントからのリクエストごとにスレッドを生成する方式と、あらかじめスレッドを生成しておくモデルがあります。

マルチプロセスモデルとは違い、プロセスではなくスレッドを使用します。このため、プロセスの fork の際に発生するコピー作業が発生しません(各スレッドはメモリ空間を共有する)。このため、プロセスの生成よりもオーバヘッドが小さいと言われています(メモリ消費量についても同様)。

また、この方式ではメモリ空間を共有するので、コンテキストスイッチの際に発生するメモリ空間の切り替えや、それに伴うキャッシュの削除を省略できるというメリットもあります。メモリ空間を共有することのデメリットとして、スレッド間での資源の競合を考慮したプログラムを書く必要があり、実装が難しくなりコードも複雑なものになりやすい、などが挙げられます。

イベント駆動モデル

1つのプロセスで複数のリクエストを処理する方式です。

上記2つのモデルでは、クライアントからの要求を受けてレスポンスを返すという一連の流れに対してを1つのプロセス or スレッドが割り当てることで、それぞれのリクエストに対応していました。 イベント駆動モデルでは、リクエスト数に関係なくイベント発生のタイミングで処理を切り替え、1つのプロセスがすべてのリクエストを処理します。

プロセスが1つしか無いということは、CPUコアを1つしか活用できないことを意味します。Nginx などでは、イベント駆動のプロセスをCPUコアそれぞれに起動しておくなどして、この欠点に対応しているみたいです。

このモデルは、リクエスト数が増えてもプロセスやスレッドの数が増えることがないので、メモリ消費量やコンテキスト切り替えのオーバヘッドなどのコストを抑える事ができるという利点があります。

ところで MPM って?

MPM は (Multi Processing Module) の略で、Webブラウザからのリクエストを Apache がどのように並行処理するか、という部分の処理をモジュール化したものです。
先にWebサーバのモデルに関して記述しましたが、Apache ではそのようなモデルの中からどの実装を使用するかをこの MPM によって選択することができます。
Apache そのものにこれらの処理が組み込まれずにモジュール化されていることによって、各々のWebサイト向けにカスタマイズすることが容易になっています。
Apache2.2までは MPM は静的にリンクしなければなりませんでしたが、Apache2.3 からは LoadModule ディレクティブで動的に選択することが可能になりました。

MPM の種類

代表的なものをまとめます。

prefork

マルチプロセスモデルです。

prefork という名の通り、クライアントからリクエストが来る前にあらかじめ一定数の子プロセスを fork して待機させておきます。これにより、fork の回数を減らしてパフォーマンス向上を図ります。リクエストごとにプロセスが分かれているため、あるプロセスの障害が他のプロセスに影響を及ぼすことがありません。したがって、安定した通信をすることが可能です。

worker

マルチスレッドモデルとマルチプロセスモデルのハイブリッドモデルです。

制御用の親プロセスがいくつかの子プロセスを作成し、その子プロセスそれぞれがマルチスレッドモデルでリクエストを捌きます。スレッド1つが1つのクライアントの処理を担当します。

prefork に比べ生成されるプロセスの数を抑えることができるので、資源の節約が可能です。しかし、スレッドを使用するモデルなので、mod_php などの非スレッドセーフなモジュールを利用する際には使用できません。

event

worker をベースとしたマルチスレッドモデルとマルチプロセスモデルとイベント駆動モデルのハイブリッドモデルです。

KeepAlive の処理を別のスレッドに割り振って通信を処理することによって、パフォーマンスの向上を図っています。また、クライアントとのネットワークI/Oのみイベント駆動モデルで実装されています。

こちらもスレッドを使用するモデルなので、非スレッドセーフなモジュールを利用する際には使用できません。

おわり

以上 Apache MPM についてでした。運用しているサーバの MPM を prefork から event に変更してみたところ、僕の環境では実際にメモリの消費量をかなり低減できました。Apche をチューニングする際はこの MPM について検討してみてもいいかもしれません。event への変更方法については以下の記事で書いています。おわり。

norikone.hatenablog.com