PHPコードのチューニング

はじめに

こんにちは、イメージ・マジックのもあいです。

最近はサッカーを見るときには2つのチームがどのように動こうとしているのかを観察することによって、より面白く観戦できるようになってきました。日本代表チームがアジアカップの決勝でどのような戦い方をするのかが楽しみではありますが、相手チームであるカタールにも気をつけてみるとさらに面白くなります。

今回はPHP(Symfony4)のパフォーマンスチューニングについての記事になります。

記事の前提
 OS: Ubuntu 18.04
 PHP:7.2.10
 nginx:1.14.0
 PhpStorm:2018.3.3
 ※全てのソフトウェアはaptコマンドでインストールしています

Xdebugのプロファイラ機能

PHPで関数/メソッドの処理時間を測定するのにXdebugをインストールします。

sudo apt install php-xdebug

php.iniを編集して有効にします。
/etc/php/7.2/fpm/conf.d/20-xdebug.ini は下記の通り

xdebug.remote_enable=On
xdebug.remote_autostart=On
xdebug.remote_host=192.168.33.1
xdebug.profiler_enable=On
xdebug.profiler_output_dir=/tmp
xdebug.profiler_enable_trigger = 1;
xdebug.max_nesting_level=1000
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_timeout=2000

ポイントとしては、xdebug.profiler_enableをOnにするのと、xdebug.profiler_output_dirに測定結果を出力するディレクトリを指定してphp-fpmをreloadします。測定が終わったら xdebug.profiler_enable を Offにしてphp-fpmをreloadします。常にOnにするのは処理が非常に重たくなるのでおすすめできません。

プロファイラを有効にして測定したいURLを実行すると下記のようなファイルが作成されます
-rwxrwxrwx 1 moai moai 42986908  1月 17 17:09 cachegrind.out.26276
-rwxrwxrwx 1 moai moai     2644  1月 17 17:09 cachegrind.out.26276.0c892b
この2つのファイルをPhpStormをインストールしているマシンにコピーします。

PhpStormでプロファイル結果を解析

PhpStormでプロファイル結果を読み込みます。

Tool → Analyze Xdebug Profiler Snapshot…

ファイル選択ダイアログが開かれるので、ファイルサイズの大きいファイルを選択します。
デフォルトで処理時間の多い順番に表示されますが、これだけだとわかりにくいので、Call Treeタブをクリックして実行順表示にしてから処理に時間がかかっているのをドリルダウンして探します。

遅い部分を探して比較を行うと下記のような状態にすることができます。
改修前
DlvryController->jsonが19657msかかっています。ここで全体の53%の処理時間がかかってル事がわかります。ローカルの仮想マシンで測定しているとはいえ遅すぎます。
jsonが何を行っているかというと、Symfony4のEntityをjsonに変換しています。フレームワークの処理で遅くなっているのであれば手の施しようが無いような気もしますが、よくよく調べるとクライアント側で使っていない情報も返却していました。送る情報が少なくなればそれなりに速くなるのでは無いかという課程のもと、返却する情報を必要最低限の情報に絞った改修を行いました。

プロファイル結果は下記の通り。
改修後
3603msになりました。4.5倍速くなったことになります。
ここに出てくる処理時間はプロファイルを行っているため実際よりも大分遅いですし、VirtualBox上の仮想マシンで実行していますので、本番環境よりもさらに遅くなっていますが、どこで遅くなったかを把握するにはちょうど良い事になります。

最後に

プロファイルを行うことによりどこが遅いのかが一目瞭然でわかったのと、使っていないデータまで送ると遅くなる事がはっきりしました。

開発をしていると、面倒だからといってデータ取得の便利メソッドを使ってデータを取得し、そのままクライアントに返却することをやってしまうのですが、そういう事をすると最後にしっぺ返しが返ってくる良い例でした。