対象のシステム
はじめに
- PHPを使っててPHP重いなーとかサーバのメモリ使いすぎだよなーとかいろんな不満を抱えていました
- PHP自体はそこまで古くないのになーとかFWのversionも上げてるしなーとかざっくり思って見たり
- でもPHPが本当に原因なのかなーっと疑問を感じながらずっと過ごしてた
- チームの他のエンジニアが
pmapを使ってプロセス (群) のメモリマッピングを表示してくれて、anonという匿名メモリー?へのメモリ割り当てが多く存在する事が分かった。
んーこれは少々ばかりDeep Driveして向き合わねばならん
まずは調査
Newrelicを使ってるんですが、契約のplanとNewrelic側の対応FWでfulephpが非対応になってて、詳細が分からずという状態だったので別の解析ツールが必要だったので色々ググった
ただ、一つのツールだけではちょっと分かりづらく、結局下記の2つのツールを活用することがよさげと思って試した
- xhprof
- fuelphpのprofiling
- fuelphp特有のものではなく、
php-quick-profilerなんですが - Particletree » PHP Quick Profiler
- fuelphp特有のものではなく、
その他
xhgui使うとxhprofの結果を見やすい用に表示してくれるGUIツールなんですが、ストレージにMongoDB使ってて自分の環境ではうまく動かず一旦断念…
調査結果~考案
自分のローカルマシンで調査しました
一応色々数値自体は隠しておきます。🙇🏽
php-quick-profiler

- どの画面でprofilingしてもMemory Usedが高い😨
- アクセスをさばく時に毎度通るロジックの部分が怪しいと分かった
xhprofのグラフから
一番ボトルネックになってる箇所を見つけた。下記グラフの赤くなってる箇所

- でもここFWのcore部分で手つけづらい…😨
- その手前の赤マルで記した部分がアクセスの度に必ず通過するメソッドで黄色くなって指摘されてた
- ここに改善の余地があるのではないかと考えた🤔
xhprofの表から

EWall%でソートして表示しています
項目
Calls… 呼びされて回数Incl Wall Time… その関数全体の処理時間IWall%… 全体の実行時間に対する割合Excl Wall Time… その関数から呼ばれた関数の実行時間を除外した、関数の純粋な処理時間EWall%… 全体の実行時間に対する割合(関数の純粋な処理時間 version)
赤で囲った部分はExcl Wallの%で、わりと高いと指摘されてる。且つ手の入れやすい部分。アクセスがある度に動くロジックの部分でもある。
xhprofのグラフの赤マルで囲ったfunctionだった🙄
こいつを改善できれば良いんじゃないかと思った🤔
それより上位はPHPのネイティブ関数の部分だったり、そのPHPのネイティブ関数をFWのcoreクラスで使ってたりでちょっと深い部分。
ここを改修となると影響範囲が大きいのでちょっと一旦パス。
以上を踏まえて主な対策方針
- アクセスされる度に動く共通のロジックの部分を見直した方が効果が高いのでやろう
- いきなりFWのCore部分に手をいれるとそれなりのリスクがあるので、Coreから切り離せる部分がまずは良いだろう
対策した内容
- アクセスがある度に毎回動くクラスAがfuelphpの
Autoloaderに設定されていて、クラスAはCoreクラスをextendしていたが、extendを止めた- xhprofの表の赤で囲ったfunctionです
- なぜかと言うと
- 親クラスのメソッドを全く使っていなかったので必要無いだろうと
- fuelphpの仕様で
Autoloaderで設定されてるクラスを辿り、_initメソッドが存在した場合はそれを動作させるみたい。つまり、クラスAの親クラスの_initメソッドが毎回動いていた- 無駄な処理で且つ、中身を見ると結構重そうな処理だった…😰
preg_match関数じゃなくても良い部分はstrposに置き換えた- 下記の公式に書いてるように
strposで置き換え可能な場合は置き換えた方が早くなるよって - PHP: preg_match - Manual
Tip Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() instead as it will be faster.
- 下記の公式に書いてるように
cookieを活用して
preg_matchの判定する場面を減らした- どうしても
preg_matchを使わなければ行けない部分はあって、cookieを活用することで効率的に処理するようにした
- どうしても
対策してみた結果
Newrelic

😀
Latency

😀
CPUの数値

😀
LoadAverage

😀
もちろん
xhprof,php-quick-profilerの数値も改善が見られました😀
まとめ
- 施策を3つほどやりましたが、結局は
アクセスがある度に毎回動くクラスAのチューニングが一番効果が高かった🙌 - xhprofで指摘された処理の中で一番遅く時間が掛かってるものをチューニングしたのが良かった(FWのcoreを除外して) 😀
- あえてcore部分を一度除外したことで影響範囲も限定されるし、リードタイム短くリリースまでいける❗❗何気にここ良かったと思ってる😀
- やっぱり時間を取って絶対改善するという心意気重要💪🏽
- 思ったよりもいろんな数値の改善が見られたのでインスタンスのタイプ一つ下げれるなぁーと思った
- このシステムが動いているサーバは4台あるので削減できる金額も結構でかく見えると思われる💰
- やった事はそんなに難しい事ではないので早くやればよかったという結果論😅
- どんどん改善していきましょー🚀