PHPアプリケーションを高速化

みんな大好き高速化。
このところ仕事でPHPアプリの性能を改善に取り組んできたので、覚えている範囲で記録しておく。WebサーバやDBサーバ等のチューニングの話はなし。小ネタ多し。

環境

やったこと

コードキャッシュ

APC とか eAccelerator ね。今回は eAccelerator を使用。

拡張モジュールの使用

PHPで書かれている機能よりも、PHP拡張モジュールで提供されている機能があればそちらを使用する。
今回、暗号化で Blowfish を使う箇所があった。当初は PEARCrypt_Blowfish を使っていた。これがすごく遅い。mcrypt 拡張モジュールをインストールすると PEAR の内部で mcrypt 関数を使うようになるので、格段に速くなる。
ただ、PEAR のコードの中にはファイルを相対パスで include している箇所が幾つかあり、後述の lstat64 の問題が発生する。今回はPEAR の Crypt_Blowfish に頼らずとも、自分で mcrypt 関数を使って機能を満たすことができるので、PEAR の Crypt_Blowfish は使わないことにした。
欲しい機能を持っている拡張モジュールがなければ、自分で作ってみるのもあり?

require_once より require

_once が付くとチェックが入るので重い。なるべくなら _once を付けない方向で。
ファイルが多くなってどこでどのファイルを読み込んでいるのか把握しづらくなってきた場合に require_once を使いたくなるけど、そんなときには __autoload() を使えばスッキリ。ただし、クラス名と require するファイルを結びつけられなければいけないけど。

必要なクラスだけ require

余分なクラスは require しない。
State パターンを使っている箇所がある。状態が 20 コくらいあり、各状態ごとにフィアルを作るのが面倒だったので、1 フィアル内に全状態分のクラスを記述していた*1
そのファイルの require だけ他のフィアル*2に比べて読み込み時間がかかっていたので、フィアルをクラスごとに分割し、そのときに必要なクラスのファイルだけ require するようにした。

絶対パスで require

絶対パスで require しないと システムコールの lstat64*3 が頻繁に呼ばれる。strace コマンドで確認するとよくわかる。

Realpath Cache

PHP: コア php.ini ディレクティブに関する説明 - Manual によると、PHP 5.1 以降から realpath キャッシュなるものが存在する。キャッシュの設定をは可変で php.ini で変更できる。ちょっと多めにしてみた。
どの値を設定するのが最適なのかは調べてないけど...。

リソースは必要最低限

DB等のコネクションは、使用する直前に作成し、不要になったらすぐ解放。プロセスの終了時に自動的に解放されるのを待つよりも、自発的に。
トランザクション処理が終わったら、すぐにコミットする。トランザクション外でもできるロジックはコミット後に。
これらは PHP が高速化するというわけでないけど、同時アクセス数が多くなったときのため。

まとめ

大きく効果があるのは、コードキャッシュの使用と、拡張モジュールの使用だった。これだけで十分じゃないかな。
意外にだったのは require まわりの改善。require_once は思っていたよりもコストがかかる処理だった。require するファイルの数が多い場合は手を付けてもいいと思う。
日ごろから気をつけてコーディングしていれば、わざわざ性能改善とか言って作業せずに済むような内容ばかり。もうすこしがんばりましょう。

*1:1ファイルに1クラスだけにするというコーディング規約はなかった

*2:1 ファイル中に 1 クラス

*3:環境によっては lstat とか?