リクルートの中古車情報サイト「カーセンサーnet」を全面リニューアルした体験を基に、大規模サイトの性能改善作業の実態をレポートする。新システムはオープン2カ月前の時点で、目標性能に遠く及ばないことが判明。入社3年目の筆者をリーダーに性能改善プロジェクトがスタートした。第1回は「改善1」としてNFSマウントオプションを修正したが効果は見られなかった。
改善2 Apache
設定パラメーターを修正
明けて7月28日。昨日NFSオプションを修正した後も、CPU使用率が95%と高かったため、負荷を25PV/秒に抑えて試験した。レスポンスタイムは1.6秒と短くなり、スループットは、かけた負荷と同じ25PV/秒になった。
しかしWeb/APサーバーのCPU使用率が80%と高いままだった。内訳は、OSが利用するSYS*1が25%、ユーザープロセスが利用するUSRが55%である(図4)。特にSYSが想定より高いことが気になった。
もう1つ、高い数値を示しているものがあった。1秒当たりのプロセス生成数で120に達していた。
プロセスの生成数が多くてCPU負荷が高いので、アクセスを受けるたびに無駄にプロセスが生成されているのかもしれない。最初に疑ったのはWebサーバーソフト「Apache」の設定だった。
Apacheのプロセス生成に関連する設定パラメーターを調べると、「MaxRequestsPerChild」というものがあり、「100」に設定されていた。
そのパラメーターの意味を調べると、次のようなものだった。『1つのhttpdプロセスが複数の子httpdプロセスを起動した際、各子httpdプロセスが複数のユーザーリクエストを処理するときの設定項目。MaxRequestsPerChildは、各子プロセスが処理できる最大リクエスト数で、その数を処理した後、子プロセスは終了する』。
MaxRequestsPerChildのデフォルト値は「10000」だった。これが100に変更されていたため、100回リクエストを処理するたびに、子プロセスが終了・生成を繰り返していたのだ。なぜ設定をデフォルトから変更していたのだろうか。
メモリーリーク回避のため?
理由は、アプリケーションの「メモリーリーク」のリスクを軽減するためだと考えられた。メモリーリークは、アプリケーションの中で動的に取得したメモリー領域の解放を忘れた結果、メモリー使用量がどんどん増えていく現象である。アプリケーションの動作時間が長いほど、メモリー使用量が増える。MaxRequestsPerChildの数値を小さく設定すれば、頻繁にメモリーがプロセスごと解放されるため、メモリーリークの問題を回避できる。
メモリーリークが本当にあるのかどうかは分からなかったが、まずはその設定値を変えて試験することにした。MaxRequestsPerChildを100から10000に戻し、変更前と同じ負荷(25PV/秒)をかけた。
すると平均レスポンスタイムは0.9秒と短くなり、CPU使用率は50%にまで落ちた。ただしCPU使用率の内訳は予想外の結果になっていた。SYSは30%と逆に増え、USRが20%と下がったのだ。
とはいえ、性能面で改善があったことには違いない。設定変更後のメモリー使用量を調べると、メモリーリークは起きていないようだったので、この設定で進めることにした。
この試験ではCPU使用率が50%と目標を下回ったものの、元々目標の半分以下の負荷しかかけていない。まだまだパフォーマンスの改善が必要だ。