LAMP システムを調整する

第 2 回 Apache と PHP を最適化する

Apache を速度低下させるものは何か、またどうすれば PHP を最大限活用できるか

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: LAMP システムを調整する

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:LAMP システムを調整する

このシリーズの続きに乞うご期待。

Linux、Apache、MySQL、そして PHP (または Perl) は、Web アプリケーションのための LAMP アーキテクチャーの基礎を構成しています。LAMP のコンポーネントをベースにしたオープンソースのパッケージは数多くあり、それらをさまざまな問題の解決に利用することができます。一般にアプリケーションの負荷が増大すると、アプリケーションのベースであるインフラ部分でのボトルネックが、ユーザーから送られるリクエストに対する応答の遅れという形でより明らかになります。前回の記事では、Linux システムの調整方法と、LAMP およびパフォーマンス測定の基本について説明しました。今回の記事では、Web サーバーのコンポーネントである、Apache と PHP に焦点を当てます。

Apache を調整する

Apache は非常に柔軟な設定が可能なソフトウェアです。Apache には数多くの機能がありますが、それぞれの機能が適切な動作をするように調整するのは骨の折れる作業です。Apache の調整はリソースを適切に割り当てるための演習でもあり、設定から不必要なものを除き、必要なものだけに絞る作業でもあります。

MPM の設定をする

Apache はモジュール構成になっており、容易に機能を追加、削除することができます。このモジュール機能を Apache のコアの部分 (ネットワーク接続の管理やリクエストのディスパッチ) で提供しているのは MPM (Multi-Processing Module) です。MPM があるおかげで、Apache ではスレッドを使ったり、さらには Apache を異なるオペレーティング・システム間で移植したりすることさえできるのです。

MPM は同時に 1 つしかアクティブになることができません。MPM をコンパイルする際には --with-mpm=(worker|prefork|event) を付けて静的に行う必要があります。

1 つのリクエストに対して 1 つのプロセスという従来からの MPM のモデルは prefork と呼ばれます。prefork よりも新しい、スレッド型のモデルは worker と呼ばれます。worker は複数のプロセスを使い、各プロセスは複数のスレッドを持つことで、より小さなオーバーヘッドで高いパフォーマンスを実現します。そしてもうひとつの event という MPM は実験的なモジュールであり、さまざまなタスクに対してスレッド・プールを別々に保持します。現在どの MPM を使用しているかを知るためには、httpd -l を実行します。

どの MPM を使用するかの選択は数多くの要因に依存しますが (event MPM はまだ実験的なものであるため) event MPM を別にすると、スレッドを使うか、使わないかという選択になります。表面的にはスレッド化の方がフォークよりも適切なように思えますが、それは PHP が使用するすべてのライブラリーを含めて、基礎となるすべてのモジュールがスレッド・セーフならば、という前提です。worker を選択する場合には、注意深くテストを行わなければならず、それに比べると prefork は、より安全な選択です。どの程度パフォーマンスが向上するかも、ディストリビューションに付属のライブラリーとお使いのハードウェアに依存します。

どの MPM を選択するにせよ、その MPM を適切に設定する必要があります。一般的に言って、MPM を設定するためには、(ワーカーがスレッドであれプロセスであれ) 実行するワーカーの数をコントロールする方法を Apache に伝える必要があります。prefork MPM に関する重要な設定オプションをリスト 1 に示します。

リスト 1. prefork MPM の設定
StartServers       50
MinSpareServers   15
MaxSpareServers   30
MaxClients       225
MaxRequestsPerChild  4000

prefork モデルでは、新しいプロセスはリクエストごとに作成され、予備のプロセスは、受信するリクエストを処理するためにアイドル状態で維持されます。こうすることで起動にかかる時間を短縮することができます。リスト 1 の設定は Web サーバーが起動すると即座に 50 のプロセスを起動し、そして 10 から 20 台のサーバーを実行したままアイドル状態に維持しようとします。プロセス数に関するハード・リミットは MaxClients によって指定されます。あるプロセスが多数の連続したリクエストを処理できる場合であっても、接続数が 4,000 を超えると Apache はプロセスを強制終了します。これによってメモリー・リークのリスクを軽減することができます。

スレッド化した MPM を設定する場合もそれに似ていますが、使用するスレッドとプロセスの数を決めなければならない点が異なります。Apache のドキュメンテーションには、必要なすべてのパラメーターと計算が説明されています。

使用する値を決めるためには、少しばかり試行錯誤が必要です。最も重要な値は MaxClients です。MaxClients の値を決める際の目標は、サーバーが過度の切り替えを行うことなく、十分な数のワーカー・プロセスまたはスレッドを実行できるようにすることです。処理能力以上のリクエストが受信された場合には、それまでに受信されたリクエストは処理されますが、それ以外のリクエストはブロックされます。

MaxClients の値が大きすぎる場合は、すべてのクライアントに対してサービスが低下します。これは、Web サーバーがプロセスを次から次へと実行しようとして切り替えるためです。MaxClients の設定が小さすぎると、不必要にサービスを拒否することになります。負荷が高いときに実行しているプロセスの数と、その状態でのすべての Apache プロセスによるメモリー・フットプリントをチェックすることによって、この値をどう設定すればよいかの感覚をつかむことができます。MaxClients を 256 を超える値に設定する場合には、ServerLimit も同じ数に設定する必要があります。こうした設定に関する注意事項は、MPM のドキュメンテーションをよく読んでください。

起動するサーバーの数を何台にし、予備のサーバーを何台にするかは、そのサーバーの役割によって変わります。もしそのサーバーが Apache しか実行しないのであれば、そのマシンを最大限に利用できるため、リスト 1 に示すような控え目な値を使うことができます。もしそのシステムがデータベースや他のサーバーとの間で共有される場合には、予備で実行するサーバーの数を制限する必要があります。

オプション (Options) と AllowOverride を効果的に使う

Apache が処理する各リクエストは、一連の複雑なルールに従って処理が行われます。そのルールには、Web サーバーが従わなければならない何らかの制限事項や特別な命令が記述されています。例えば、フォルダーへのアクセスに関しては、IP アドレスによってアクセスできるフォルダーを制限することができます。あるいはユーザー名とパスワードを設定することで制限することもできます。こうしたオプションには、一部のファイルの処理も含まれます (例えば、ディレクトリー・リストが提供されている場合に、あるファイルタイプをどう処理するか、出力を圧縮するかどうか、など)。

こうしたオプションの設定は、httpd.conf 内でコンテナーの形式を取ります。例えば <Directory> は、<Directory> コンテナーに書かれている設定がディスク上のある場所に適用されることを示し、また <Location> は、<Location> コンテナーに書かれている内容が、ある URL のパスに適用されることを示します。リスト 2 は実際の Directory コンテナーを示しています。

リスト 2. root ディレクトリーに適用された Directory コンテナー
<Directory />
    AllowOverride None
    Options FollowSymLinks
</Directory>

リスト 2 では、Directory タグと /Directory タグで囲まれた設定内容が、指定されたディレクトリー (この場合は root ディレクトリー) と、そのディレクトリーの下にあるものすべてに適用されます。ここでは、AllowOverride タグは、ユーザーはどのオプションも無効にすることができないという設定になっています (これについては、後ほど詳しく説明します)。また FollowSymLinks オプションが有効にされており、これによって Apache は、たとえ対象のファイルが Web ファイルを含むディレクトリーの外にある場合でも、symlink の先を調べてリクエストを処理します。これはつまり、もし Web ディレクトリー内のファイルが /etc/passwd への symlink の場合、Web サーバーは、要求されれば当然そのファイルにアクセスします。FollowSymLinks オプションの代わりに -FollowSymLinks が使われている場合には、この機能は無効になり、同じリクエストはエラーとなってクライアントに返されます。

上述の例は、2 つの点で懸念があります。その 1 つ目はパフォーマンスの問題です。FollowSymLinks が無効にされている場合、Apache はそのファイル名のコンポーネント (ディレクトリーとファイル自体) を 1 つひとつチェックし、それらがシンボリック・リンクではないことを確認しなければなりません。これはディスク・アクティビティーという形での余分なオーバーヘッドを生じます。FollowSymLinks の仲間の、FollowSymLinksIfOwnerMatch と呼ばれるオプションは、そのファイルの所有者がシンボリック・リンクの所有者と同じ場合にシンボリック・リンクをたどります。このため、symlink を追跡する動作を無効にすることと同様のパフォーマンスの影響があります。最高のパフォーマンスを得るためには、リスト 2 のオプションを使います。

セキュリティー意識の高い読者は、ここまで読んで 2 つ目の懸念がセキュリティーであることに気付いたはずです。セキュリティーは、常に機能とリスクとのトレードオフなのです。この場合、機能はスピードであり、またリスクは、システム上のファイルに対する権限のないユーザーからのアクセスを許すことです。リスクの軽減になる 1 つの要素は、LAMP アプリケーション・サーバーは通常は特定の機能専用であるため、ユーザーは危険が潜在するシンボリック・リンクを作成できないということです。さらに、シンボリック・リンクのチェックを有効にすることが必須の場合には、そのチェックを、ファイルシステムの特定領域のみに制限します (リスト 3)。

リスト 3. FollowSymLinks をユーザーのディレクトリーに制限する
<Directory />
   Options FollowSymLinks
</Directory>

<Directory /home/*/public_html>
   Options -FollowSymLinks
</Directory>

リスト 3 では、ユーザーのホーム・ディレクトリーの中にあるすべての public_html ディレクトリーとその子ディレクトリーでは FollowSymLinks オプションが無効にされています。

これを見るとわかるように、メインのサーバー設定をとおして、ディレクトリー単位でオプションを設定することができます。ユーザーが (AllowOverrides ディレクティブによって管理者から許可されている場合に) このサーバー設定を無効にするには、.htaccess というファイルをディレクトリーの中に用意します。このファイルには、.htaccess ファイルが存在するディレクトリーへのリクエストごとにロードされる、追加のサーバー・ディレクティブが含まれており、そのディレクトリーへのリクエストはこのディレクティブに従った処理がされます。先ほどは、ユーザーはどのオプションも無効にすることができないという設定に関する説明をしましたが、多くの LAMP アプリケーションでは、この機能を使ってアクセス制御や URL の書き換えを行っています。そのため、この動作を理解しておくことが賢明です。

AllowOverrides ディレクティブを使うと、ユーザーによる望ましくない動作を防止できますが、Apache では、何か必要な作業がないかどうか .htaccess ファイルを調べる必要があります。親ディレクトリーでは、子ディレクトリーへのリクエストに対して適用することになるディレクティブを指定することができます。これは Apache が、要求されたファイルに至るディレクトリー・ツリーの各コンポーネントも検索する必要があることを示しています。当然ながら、これによって、リクエストがある都度、大量のディスク・アクティビティーが発生します。

最も簡単なソリューションは、メインのサーバー設定を一切無効にさせないことです。こうすることで、Apache は .htaccessをチェックする必要がなくなります。すると、特別な設定はすべて、直接 httpd.conf の中に置かれます。リスト 4 では、ユーザーのプロジェクト・ディレクトリーに対するパスワード・チェックを httpd.conf の中に追加して有効にしており、.htaccess ファイルの中で AllowOverrides を使ってはいません。

リスト 4. .htaccess での設定を httpd.conf で行うようにする
<Directory /home/user/public_html/project/>
  AuthUserFile /home/user/.htpasswd
  AuthName "uber secret project"
  AuthType basic
  Require valid-user
</Directory>

設定を httpd.conf の中で行うようにし、AllowOverrides を無効にすると、ディスクへのアクセスを減らすことができます。1 人のユーザーのプロジェクトにはたいした影響がないかもしれませんが、大量のアクセスがあるサイトに適用した場合、この手法がいかに強力かを考えてみてください。

場合によると、.htaccess ファイルを使わざるをえないこともあります。例えばリスト 5 では、オプションはファイルシステムの一部に限定されており、メインのサーバー設定を無効にする範囲を指定できています。

リスト 5. .htaccess チェックを範囲指定する
<Directory />
  AllowOverrides None
</Directory>

<Directory /home/*/public_html>
  AllowOverrides AuthConfig
</Directory>

リスト 5 を実装すると、やはり Apache は親ディレクトリーの中の .htaccess ファイルを探しますが、public_html で停止します。これは、ファイルシステムの他の部分ではこの機能が無効になっているためです。例えば、/home/user/public_html/project/notes.html にマッピングされるファイルへのリクエストがある場合、public_html ディレクトリーと project ディレクトリーのみが検索されます。

ディレクトリーごとに設定を行うことに関する最後の注意点が、順序です。Apache の調整に関するどのドキュメンテーションでも、HostnameLookups off ディレクティブを使うことで DNS ルックアップを無効にするように指示しています。これは、サーバーに接続されるすべての IP アドレスを逆引きにより解決しようとすることはリソースの無駄であるためです。しかしホスト名に基づいて何らかの制限をすると、そのホスト名の信憑性を検証するために、クライアントの IP アドレスに対する逆引きとその結果に基づく正引きを行うことを Web サーバーに対して強要することになります。従って、クライアントのホスト名に基づくアクセス制御を行わないようにし、必要な場合に範囲指定する方が賢明です。

永続的な接続

クライアントが Web サーバーに接続する際には、クライアントは同じ TCP 接続を使って複数のリクエストを発行することができ、それによって複数の TCP 接続に伴って発生するレイテンシーを抑えることができます。これは Web ページがいくつかの画像を参照している際に便利です。つまりクライアントは、ページを要求し、さらにそのページ上のすべての画像を要求する動作を 1 つの接続で行うことができます。この方法の欠点は、サーバー上のワーカー・プロセスはクライアントがセッションを閉じるまで待たないと次のリクエストに進めないことです。

Apache では、永続的な接続 (keepalives と呼ばれます) をどのように扱うかの設定を行うことができます。httpd.conf のグローバル・レベルで KeepAlive 5 とすると、サーバーは 1 つの接続に対して 5 つのリクエストを扱うことができ、それ以上になると強制的に接続が閉じられます。この数字を 0 に設定すると、永続的な接続を使用できなくなります。同じくグローバル・レベルでの KeepAliveTimeout によって、Apache がセッションを閉じるまでに別のリクエストを待つ時間の長さを決定することができます。

永続的な接続を扱う場合は、1 つの設定ですべてに対応できるような設定にすることはできません。一部の Web サイトは keepalives を無効 (KeepAlive 0) にした方が適切に動作し、また一部の Web サイトは keepalives をオンすることで大幅に動作が向上します。唯一のソリューションは、両方を試し、自分自身で調べてみることです。ただし助言として、もし keepalives を有効にする場合には、タイムアウトの値を低くした方が賢明です (例えば KeepAliveTimeout 2 を使って2 秒にするなど)。そうすることで、別のリクエストを行おうとするクライアントには十分な時間ができ、また、来ないかもしれない別のリクエストを待ってワーカー・プロセスがアイドル状態になることがありません。

圧縮

Web サーバーは、出力を圧縮してからクライアントに返送することができます。こうすることで、Web サーバーの CPU サイクルを犠牲にすれば、インターネット上に送信されるページを小さくすることができます。CPU にオーバーヘッドを持たせる余裕のあるサーバーでは、これはページのダウンロードを高速にするための素晴らしい方法です。圧縮するとページのサイズが 3 分の 1 になることも珍しくありません。

画像は通常、既に圧縮されているため、圧縮を行う対象はテキスト出力に限定する必要があります。Apache では mod_deflate を使って圧縮を行うことができます。mod_deflate をオンにするのは簡単ですが、マニュアルの説明をよく読まないと理解できない複雑な部分がたくさんあります。この記事では圧縮の設定については説明しませんが、適切なドキュメンテーションへのリンクを提供しておきます (「参考文献」セクションを参照してください)。

PHP を調整する

PHP はアプリケーション・コードを実行するエンジンです。使う予定のあるモジュールのみをインストールする必要があり、またスクリプト・ファイル (通常は .php で終わるファイル) にのみ PHP を使用し、すべての静的ファイルに PHP を使うことがないように Web サーバーを構成する必要があります。

オペコードのキャッシング

PHP スクリプトが要求されると、PHP はそのスクリプトを読み取り、それを Zend オペコード (実行対象コードのバイナリー表現) と呼ばれるもへとコンパイルします。そしてこのオペコードは PHP エンジンによって実行され、廃棄されます。オペコード・キャッシュは、このコンパイルされたオペコードを保存し、そのページが次回呼び出されたときにそのオペコードを再利用します。これによって大幅に時間を節約することができます。入手可能なオペコード・キャッシュはいくつかありますが、私は eAccelerator を使って非常にうまくいっています。

eAccelerator をインストールするためには、コンピューターに PHP の開発ライブラリーがインストールされている必要があります。ファイルを置く場所は Linux のディストリビューションによって異なるため、インストール方法に関する説明を直接 eAccelerator の Web サイトから入手することが最も確実です (「参考文献」セクションにリンクがあります)。また、皆さんの使用しているディストリビューションには既にオペコード・キャッシュがパッケージされており、それをインストールするだけでよいという可能性もあります。

eAccelerator をどのようにシステムにインストールするかによらず、いくつかの設定オプションがあることに注意する必要があります。設定ファイルは通常、/etc/php.d/eaccelerator.ini です。eaccelerator.shm_size は、コンパイルされたスクリプトが保存される共有メモリー・キャッシュのサイズを定義します。この値の単位はメガバイトです。その適切なサイズはアプリケーションによって変わってきます。eAccelerator はキャッシュの状態を示すスクリプトを提供しており、この状態にはメモリーの使用状況も含まれています。最初に設定する共有メモリー・キャッシュのサイズとしては 64 メガバイト (eaccelerator.shm_size="64") が適切です。また、もし指定した値が受け入れられない場合には、カーネルの最大共有メモリー・サイズを調整する必要もあるかもしれません。/etc/sysctl.conf に kernel.shmmax=67108864 を追加し、sysctl -p と実行して設定を有効にします。kernel.shmmax の値の単位はバイトです。

共有メモリーの割り当てが指定のサイズを超過する場合は、eAccelerator はメモリーから古いスクリプトをパージする必要があります。この動作はデフォルトで無効になっています。eaccelerator.shm_ttl = "60" は、eAccelerator の共有メモリーが足りなくなったときに、その時点までの 60 秒以内に利用されていないスクリプトをすべてパージするように指定します。

eAccelerator に変わる、もう 1 つの一般的なオペコード・キャッシュが APC (Alternative PHP Cache) です。Zend のメーカーも、さらに効率を高めるための最適化プログラムを含んだ商用のオペコード・キャッシュを提供しています。

php.ini

PHP の設定は php.ini で行います。PHP が利用できるシステム・リソースを制御するための重要な設定項目は以下の 4 つです (表 1)。

表 1. リソースに関連する php.ini での設定
設定説明推奨値
max_execution_timeスクリプトが利用できる CPU 秒数30
max_input_timeスクリプトがデータ入力を待てる時間 (秒数)60
memory_limitスクリプトが強制終了されずに使用できるメモリーのバイト数32M
output_bufferingクライアントに送信する前にバッファーするデータのバイト数4096

これらの数字は、ほとんどアプリケーションに依存します。もしユーザーから大きなファイルを受け付ける場合には、php.ini の中で、あるいはコードの中で上書きすることで、max_input_time の値を増やす必要があるかもしれません。同様に、CPU 負荷あるいはメモリー負荷の高いプログラムも、より大きな値に設定する必要があるかもしれません。こうした設定の目的は、実行したままになってしまうプログラムが他のプログラムに及ぼす影響を軽減することです。そのため、こうした設定をグローバルで無効にしてしまうのはお奨めできません。また、max_execution_time に関するもう 1 つの注意として、この値はプロセスの CPU 時間を表すのであり、絶対的な時間を表すわけではありません。従って、大量の I/O を行い、計算はほとんど行わないプログラムは、max_execution_time よりもずっと長時間実行されるかもしれません。同じ理由から、max_input_timemax_execution_time よりも長いこともあり得ます。

PHP で行うロギングは、ログに残す対象を設定することで、ログとして記録される量を調整することができます。また実動環境では、最も重要なログ以外のログを無効にすることで、ディスクへの書き込みを減少させることができます。問題のトラブルシューティングにログが必要な場合には、必要に応じてロギングの対象を増やすことができます。error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR を使うと、問題を発見するのに十分なロギングが行える一方、スクリプトによる大量の無駄なログを避けることができます。

まとめ

この記事では Web サーバーの調整に関して、Apache と PHP の両方を中心に説明しました。Apache に関する一般的な考え方としては、Web サーバーが行う必要のある余分なチェック (例えば .htaccess ファイルの処理など) を削減することです。また、皆さんが使用している Multi-Processing Module を調整し、使用されるシステム・リソースと、受信するリクエストのためにアイドル状態にあるワーカーの可用性とをバランスさせる必要があります。PHP に関する調整として最も効果的なことは、オペコード・キャッシュをインストールすることです。また、いくつかのリソース設定に注意し、スクリプトがリソースを占有して他のすべてのシステム応答が遅くなってしまうことがないようにする必要もあります。

次回は最終回として、MySQL データベースの調整について説明します。ご期待ください。


ダウンロード可能なリソース


関連トピック

  • Quantify performance changes using application tracing」(developerWorks、2006年7月) は、Apache での構成変更の効果を示すためのアプリケーション・トレースの使い方を解説しています。
  • PHP V5.2 の新機能、第 1 回: 新しいメモリー・マネージャーの使用方法」(developerWorks、2007年3月) は、メモリーの処理に関する PHP 5.2 での最新の変更を解説しています。PHP はシステム・リソースの使い方を常に改善し続けています。
  • mod_deflate は即時動作で出力を圧縮できる、Apache のモジュールです。出力の圧縮は PHP で行うこともできます。
  • JavaScript コードなど静的ファイルの圧縮ファイルをプリキャッシングすることでパフォーマンスを改善することができます。CSS も、パフォーマンスを改善するための、もう 1 つの方法です。すべての JavaScript コードと CSS を圧縮して連結する方法は、さらに良い方法です。
  • Multi-Processing Module の各モジュールの機能について学ぶために、Multi-Processing Module に関する Apache のドキュメンテーションは読む価値があります。リンクをたどり、皆さんが選択した MPM に対応するドキュメンテーションを読んでください。
  • developerWorks の Linux ゾーンには、Linux 開発者のための資料が他にも豊富に用意されています。
  • もし皆さんの使用しているディストリビューションにeAccelerator が含まれていない場合には、Install From Source の説明が役立ちます。
  • Alternative PHP CacheZend Platform は eAccelerator に代わる手段です。
  • Siege はユーザーをシミュレートすることができます。これを利用すると、サイトが処理できるトラフィックの量を知ることができます。
  • 遅かれ早かれ、サイトの一部の要素をキャッシュし、複数の Web サーバーに負荷を分散したくなるものです。アクセラレーター・モードでの Squid (別名リバース・プロキシー) または Linux Virtual Server Project は、素晴らしいツールです。
  • developerWorks から直接ダウンロードできる IBM trial software を利用して、皆さんの次期 Linux プロジェクトを構築してください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, Open source, Web development
ArticleID=291589
ArticleTitle=LAMP システムを調整する: 第 2 回 Apache と PHP を最適化する
publish-date=04302007