PHPのパフォーマンスを計ることができる、phptop_hook.phpを導入してレンタルサーバーのパフォーマンスを測定しました。本稿では解析結果とともに、Excel2010を使ったデータ処理の方法について書きたいと思います。フィルタやピボットテーブルなど、知っていると便利なEcxelの機能を使います。
尚、下記の結果は現在の私の環境(PHP、WordPress、プラグイン及びレンタルプランと割り当てサーバー)での結果です。それぞれのバージョンやプラン、実際にホスティングされたサーバー等で異なると思いますので、参考程度に留めてください。
解析結果
最初に解析結果から書きます。
概要
解析した期間は一週間です。平均値は以下の様になりました。
項目 | 平均値 |
時間 | 0.324 sec |
ピーク時のメモリ使用量 | 15.4 MB |
エラーなしアクセス件数 | 2588 |
エラー発生アクセス件数 | 1177 |
エラー率 | 31.3% |
エラー率30%はつらいですね。(;;
エラー率80%以上(普段において3回はリロードが必要)のURLを見てみると、/wp-admin/network/以下や/wp-admin/post.phpへのクエリでした。
ネットワークの管理や、記事の投稿自体が難しい現状を表しています。(プラグインの検索などは、最早行ってすらいません。^^;)
致命的なのは、サイトのトップページのエラー率が30%だったことです。これはユーザーの離脱につながりますので何とかしないといけません。
メモリ使用量とエラー率の関係
メモリ使用量とエラー率の関係をプロットしてみると上のようになりました。一プロットは、一URL(クエリー含む)に対応します。横軸の単位はMBです。
PHPがどのようにメモリを確保しているか知りませんが、メモリ使用量はおおよそ16MB近辺と22MB近辺に集中しています。そしてその2つのエリアでエラーが発生しています。
メモリを25MB以上使っているにも関わらず、エラーが発生していないURLをみると、wp-admin/options-general.phpとwp-admin/admin-ajax.phpでした。特にadmin-ajax.phpは20回ほど呼び出されています。
確かに16MB近辺より22MB近辺の方がエラー率が高めですが、メモリ使用量と相関があるとは言えません。
(エラー100%のURLについては、phptop_hook.phpがデータを吐き出す機会自体がありません。従ってメモリ使用量が0になって、左上に表示されてしまいます。)
実行時間とエラー率の関係
実行時間(システム時間+ユーザー時間)とエラー率をプロットしてみました。横軸の単位は秒です。CPU占有時間が長いとエラーが起きやすいというわけではありません。
結論は、サーバーが忙しいときはWordPressを使っている限り500エラーが出てしまうのではないでか、ということです。プラグインの見直しを行っても効果なさそうです。(もともとプラグインは最小限にしています。)
その他参考
上がメモリ使用量対実行時間、下がメモリ使用量対総時間(待ち時間も含む)です。サーバーのパフォーマンスや、DBサーバーも含めたシステムのパフォーマンスが比較できそうです。
phptop_hook.php
phptop_hook.phpの導入については、くにくにネットさん「さくらのレンタルサーバーでPHPのメモリ使用量を把握する方法」を参考にさせて頂きました。
その他多くのブロガーさんがphptopを紹介していますので、その導入方法は割愛いたします。
phptop_hook.phpはtime、sys、user、memの4つを出力します。それらの値が何で、単位は何なのか?phptop_hook.phpの中を見ると簡単にわかります。
まずtimeはphpファイルが呼び出されてから、実行し終わるまでの時間を秒で表しています。microtime(TRUE);という関数を使っています。
memは「システムが割り当てた実際のメモリの大きさ(Byte)」で、memory_get_peak_usage(TRUE);にて取得しています。
最後にsysとuserはシステム時間とユーザー時間(秒)で、getrusage();にて取得しています。システムファンクションコールなのでカーネルから取得しているようです。
これらをerror_log関数で、エラーログに出力しています。
私は、解析するに当たって始めてphptop_hook.phpのソースを見たのですが、最初にソースを改造していれば、以降のExcelの操作はもっとシンプルにできましたね。orz
Excelでのエラーログ解析
通常はphptopというperlのツールで集計するようですが、くにくにネットさん曰く「いろいろと面倒だったので使いませんでした。」とのことです。そこでExcel2010を使うことにしました。前述のようなグラフを書くことも目論んでの選択です。
この節ではExcel2010のフィルタ機能やピボットテーブルを使って、エラーログを解析する操作を詳説します。(世の中ビッグデータですが、Excelでもいろいろできます。^^)
Excel上でエラーログを開く
まずExcel上にエラーログを開き、適当な列に分割します。
レンタルサーバーのエラーログは/home/user/log(userは各ユーザー名)にありますので、必要な期間のerror_log_xxxxxxxx.gzをFTPでGETし解凍します。(各位の環境によって、パスやファイル名が異なります。)それらをテキストエディタで開き、Excelのシートににすべてコピペします。
この時点ではすべてA列にデータがありますので、適当な列に分割します。
A列を選択し、データリボンから「区切り位置」をクリックすると、「区切り位置ウィザード」が開きます。
「カンマやタブ…」をチェックして、「次へ」をクリックします。(固定位置でもよさそうですが、clientのIPアドレス以降がガタガタですので。)
区切り文字の「その他」をチェックし、’]’を指定します。そして完了をクリックします。
次にD列を選択し、再び「区切り位置」をクリックします。ウィザードの最初の画面では、先と同様に「カンマやタブ…」をチェックして、「次へ」をクリックします。
今度は区切り文字に「スペース」を選択して「完了」をクリックします。
必要なデータのみのシートの作成
次に、phptopの出力と、500エラーの出力と考えられる「Premature…」のエラーの行だけ、Excelの「フィルタ」機能を使って違うシートにコピーします。(「Premature…」エラーはPHPの実行時エラーでも出力されますので、そのような欠陥は除去されているという前提です。)
1列目に空行を挿入し、データリボンより「フィルタ」をクリックします。すると1行目の各セルに「▼」が表示されますので、E列の「▼」をクリックしてプルダウンを表示します。
「(すべて選択)」のチェックを外した後、「phptop」及び「Premature」をチェックし、「OK」をクリックします。すると「phptop」と「Premature」のレコードのみが表示された状態になります。
Ctrl+Gで「ジャンプ」を開きます。
「セル選択」をクリックします。
「可視セル」を選択し、「OK」をクリックします。すると表示されたセル(つまり「phptop」と「Premature」の行)のみが選択された状態になります。
Ctrl+Cでコピーし、別のシートにCtrl+Vでペーストします。(長時間かかる旨の警告がでたりします。)
このシートの名前を「source」とします。
データの整形
シート「source」を解析しやすいようにもう少し整形します。先ほどと同様に1行目にフィルタを作成します。
まずphptopのF列がURL、G-J列がデータなので、Prematureもそれに合わせたいと思います。
E列の「▼」をクリックしてプルダウンを開き、フィルタを操作してPrematureのみ表示します。
フィルタの直下に表示された行のF列をクリックし、’=’を入力します。その後同行のL列をクリックして、F列にURLが表示されるようにします。
そしてセルの右下をダブルクリックすると、以降の行がすべて同じ式になります。
続いてG-J列を選択しDeleteを押してクリアします。
再びE列のプルダウンから「(すべてを選択)」をチェックして、全ての行を表示させます。
次に、データのG-J列をもう少し分割します。各列の後ろに空列を挿入します。(列を選択後、右クリック>挿入で前に列が挿入されます。)
「mem:」の列の後ろには、もう一列挿入します。(後ろに’,’がついている場合があるので。)
このように、H、J、L、N、O列の空列が挿入されました。
G列を選択し、「データ」リボンの「区切り位置」をクリックし、「カンマやタブ…」をチェックしして次に進みます。
区切り文字に、カンマと、その他に’:’を選択し、「完了」をクリックします。同様にI、K、M列についても区切り位置を指定します。
このようになります。1行目のF、H、J、L、N列に、それぞれ’URL’、’time’、’user’、’sys’、’mem’のようにラベルを書いて、もはや必要のないG、I、K、M、O列は削除します。(列を選択し、右クリック>削除)
Prematureのデータに印があったほうがいいですね。再びE列のフィルタでPrematureだけ表示させます。
そしてフィルタの次に表示されている行のK列に’1’を入力し、右下をダブルクリックします。するとPrematureのK列がすべて’1’になります。
E列のフィルタを「(すべて選択)」に戻し、K1のセルにラベルを書きます。とりあえず「is Premature」としました。
以上で、データの整形は終了です。
ピボットテーブルの作成
次にピボットテーブルを作成して、URLごとに各データの平均を求めます。同時にエラー率のもととなる、成功数とエラー数を集計します。
「挿入」リボンの「ピボットテーブル」をクリックします。
「テーブル/範囲」の右のボタンをクリックします。
F-K列を選択し、ダイアログボックスの右のボタンをクリックします。
「新規ワークシート」を選択し「OK」をクリックします。
新しいシートが作成され、ピボットテーブルを作成する準備ができました。
パネル上部の「URL」を下の「行ラベル」のエリアにドラッグ&ドロップします。
表に行ラベルが追加されます。次に「time」を「Σ値」のエリアにドラッグ&ドロップします。
「データの個数」と表示されますので、クリックしてメニューを開き、「値フィールドの設定」をクリックします。
集計方法を「平均」にして、「OK」をクリックします。同様に、user、sys、memについても、「Σ値」に加えて平均にします。
最後に「is Premature」と、もう一つ「time」を「Σ値」に加えます。これらは「データの個数」のままで構いません。(それぞれ、エラーの発生数と正常終了数になります。)
URLのA列の幅が広すぎるのですが、スクロールさせるとピボットテーブルが完成しています。
例えば「平均/mem」の列のデータを右クリックし、「並べ替え>降順」をクリックすると、メモリ消費の大きい順に行が並び変わります。
以上でピボットテーブルが完成しました。
解析
ピボットテーブルで解析してもいいのですが、癖があるので別のシートに値をコピペして解析用にしたいと思います。
まずピボットテーブルのデータをCtrl+A、Ctrl+Cでコピーします。
そして空のシートを開きます。「ホーム」タブの「貼り付け」の下の▼よりプルダウンを開き、「値の貼り付け」の左のボタンをクリックします。
先頭の空行の削除し、一行目のラベルの整理をしました。そして、H2に「=F2/(F2+G2)」のような式を入力します。(エラー率です。)セルの右下ダブルクリックですべての行に展開します。
ざっとデータを見て、いらない行(URLがない行や、最後の総計の行)を削除します。
後は、time対memの散布図、mem体エラー率の散布図など書けば、解析できそうですね。
先の解析結果では実行時間「=C2+D2」を表示する列と、MB単位のメモリ使用量「=E2/1000000」を表示する列も作成しています。
まとめ
WordPressのサイトにおいて、phptop_hook.phpでパフォーマンスを1週間測定しました。そのエラーログをExcel2010に張り付けて解析しました。
恐らくですが、メモリ使用量を全て15MB以下に抑えることができれば、快適になるかもしれません。しかしWordPressを使っている限り難しそうです。(プラグインも現時点でそれほど使っていません。)