Tags:, Posted in PHP 1 Comment

hint先だってのPHP高速化に関するポストの導入で、が物議をかもしている件を紹介しました。
先日、最初に疑問を投げかけたZendの技術者であるStanislav Malyshev氏が、自身のblog”PHP 10.0 Blog“上で、前述のGoogleのそれに対するアンチテーゼとして”More on PHP performance“という記事を書いています。つい小手先のシンタックスなどを期待してしまいがちな高速化Tipsですが、「初心者向けにまず」としながら、極めて本質的なパフォーマンスチューニング方法をまとめています。
とても良い記事だと思ったので、タイトルに沿ってまとめてみます。(翻訳ではないので注意して下さい)

Bytecode cache

バイトコードキャッシュを用いずしてパフォーマンスを語る無かれ(超意訳)

If you care about performance and don’t use bytecode cache then you don’t really care about performance.

というほど、まず重要としているのがこの部分。
まずは(Zend社員としては当然) Zend Serverの導入検討を奨めていますが、自分でPHPをコンパイルできる環境であるならばAPCなどを使えば良いでしょう。ちなみに、このblogを動かしているPHPもAPCを使っています。GUIの管理画面もあってステータス管理も簡単。キャッシュヒット率99.9%。プログラム中からmemcache的に変数を格納したりも出来るし、非常にありがたいモジュールです。

Profiling

最適化する前にプロファイルを!(意訳)

Profile you code before you start optimizing it!

どの関数がボトルネックになっているのか、ちゃんと把握してからチューニングしましょうということで。そのためのツールとしてZend Studio/DebuggerXdebugが挙げられています。

Caching

殆どのPHPは”shared nothing”でインストールされているわけで、リクエスト処理の終了と同時に作業内容は全部飛んでしまいます。これは処理の複雑さを回避するなどのメリットは大きいのですが、パフォーマンス的にはデメリットですよね。繰り返し処理はキャッシュに入れて、いいとこどりにしちゃいましょう。(意訳)

Most PHP installations run in “shared nothing” mode where as soon as the request processing ends, all the data associated with the request is gone. It has some advantages, but also one big disadvantage – you can not preserve results of repeated operations. That is, unless you use caching.

実際、DBへのアクセスや複雑な計算のような大きな処理はもちろん、XMLによる設定ファイルをパースしておくような簡易な処理でも、アクセス毎に発生するようであればDisk I/Oとあわせてトータルでかなりの軽量化になります。
キャッシュ先としては memcached や前述の APC などが挙げられます。用途によってはHDDでも良いでしょうが、基本的には高速なメモリでのキャッシュを考えるべきです。ポスト元では他にも、Zend Serverに含まれたZend Frameworkによるキャッシュ機能を奨めています。

Optimize your data

通常、PHPアプリケーションで最もコストのかかる処理は、データベースやファイルシステムのような外部データや、ネットワークにアクセスすることです。クエリーを減らすこと、データベース構造の改良、ファイルシステムへのアクセス減、データ取得のためのサービス呼び出しを複数回行わずに1度でまとめるなど、これらの最適化に注力しましょう。更に言えば、システムコールトレーサ(Unixであれば strace、Windowsであれば Process Explorer など)などを使い、スクリプトが呼び出しているシステムコールを減らせないかどうか検討しましょう。それらの全てを除くことは不可能だと思いますが、いくつかは検討の余地があるでしょう。(意訳)

Usually the most expensive places of the PHP application are where it accesses external data – namely, database or filesystem or network. Look hard into optimizing that – reduce number of queries, improve database structure, reduce filesystem accesses, try to bundle data to make one service call instead of several, etc. For more advanced in-depth look, use tools like strace (Unix) and Process Explorer (Windows) to look into system calls your script produces and think about ways to eliminate some of them. You would not be able to eliminate all of them but each of them is a worthy target.

ほぼ、そのまま。
下手にPHPでの処理をいじるより、RDBのチューニングを行った方が遥かに効果的なことは、非常によくあります。また、先述のキャッシュを使うような工夫は、ここにも繋がります。

Don’t try to outsmart the engine

世の中には”Tips”と呼ばれる「ああしたほうが速い」「こうすると遅い」というような話題があります。しかし特にビギナーのうちは、そういったものに惑わされない方がいいでしょう。十中八九は何も変わらず、残った1つも手持ちのコードに容易にあてることは出来ないか、費やした時間ほどの価値は無いというのがオチでしょう。確かにopcodesを軽くしたり、lookupsを減らしたりするような手法はありますが、他の全ての条件が整っていなければ無意味です。加えて、こういったアドバイスのいくつかは、寧ろコードを遅くしたり、堅牢性やセキュリティを失わせてしまったりします。特に初心者は、こういったトリッキーな手法に手を出さない方が良いでしょう。(意訳)

There are a lot of “tips” floating around about which constructs in PHP are faster or slower than others. I think you can safely ignore all of these tips, especially if you’re a beginner. Odd are, 9 cases out of 10 they won’t give you any improvement at all, and in the remaining one case it will be either not applicable in your code or not worth the time spent on it. Yes, there are ways to save couple of opcodes and remove couple of lookups here and there – but unless you’ve already done with all of the previous steps it is not worth it. And some of the advice out there will actually make you code slower, less robust and less secure without you even noticing. So I think for the beginners is better to stay away from trying to outsmart the engine altogether.

この辺が恐らく、Googleの(そして、その他「高速化Tips」と銘打つほぼ全ての)アドバイスに対する反発心に繋がっているのでは。
王道をきちんとおさえるのが近道というのは、何にでも言えることですよね。

Benchmark in real life

ここまでに話題に挙げたアドバイスの多くは、証拠としてベンチマークを使っています。問題は、これらのベンチマークはいつも、ほんの数行の部分的なコードで書かれていることです。しかしながら、実際に実行されなければいけないコードは大きなアプリケーションで、そのような一行コードではありません。(意訳)

Many of the advices I mentioned above have benchmarks as a proof. The problem is these benchmarks always test only a short piece of code. However, you would not be running that one-liner – you would be running the whole big application.

これに続けて筆者は、「勝ち馬を予想するために真空状態でのモデルを使う科学者のジョーク」を引き合いにだしています。
確かに条件が複合的に絡む場合は多く、数行のベンチマーク結果を妄信することを危惧する必要はあります。しかし、現実に「A/Bどちらの方法が速いのか?」と確かめるには、むしろ他の要因を取り払って調べる必要がある場合もあるように思います。ここに関しては、「最終的なパフォーマンスチューニングは、実際のアプリケーションを用いるべき」というアドバイスと捉えれば良いのではないでしょうか。

Leverage the extensions

あまりにも自明のことを言うようですが、それでもPHP extensionで可能となる機能を重複して作っているようなコードを数多く見かけます。PHPには多くの関数があるので、誰か他の人がやっていそうなものを作る前に、マニュアルをチェックしてみて下さい。DOM/SimpleXML拡張も、JSONパーサも、SOAP送受信のための拡張なども、利用することができます。serialize/deserialize関数が使えないのでなければ、独自のものを作ったりするのは止めましょう。
もしパフォーマンスが非常に重要で、あなたがCプログラムを書けるなら(PHP初心者が、全てにおいて初心者だということを意味しませんよね)、独自のPHPエクステンションを作ることを検討してみてください。それは、それほど難しくはありません。(意訳)

That seems too obvious, but I have seen a lot of code that duplicates functions available in some PHP extension. There are a lot of functions in PHP and if you do something that others may have done before, check in the manual. You have DOM/SimpleXML extensions for XML, JSON extension for JSON, SOAP extension for doing SOAP, etc., etc. Do not create custom serialization/deserialization if serialize()/deserialize() would work for you.
If you have some very performance-sensitive bit of script and you can do C programming (beginner in PHP doesn’t mean beginner in everything , consider even making your own extension, it’s not that hard.

Avoid extra notices/errors/etc.

PHPでエラーを抑止することが大変だったとしても、noticeやstrict notice、warningなどが出ないコードを書くよう挑戦してみて下さい。その際、全てのエラーが出力されるように設定したいと思いますが、実運用環境ではエラー表示を決してしないようにしましょう。恥を大っぴらにするだけですから。(意訳)

Even suppressed errors have cost in PHP, so try and write your code so it would not produce notices, strict notices, warnings, etc. You may want to enable logging of all errors to examine that. Never enable displaying errors in production though – it will only lead to a major public embarrassment.

変数の未定義や配列に添え字が無い場合など、noticeエラーを出しておくことは、タイポなどの単純で気付きにくいバグを回避するのに有効です。ちゃんと無くしましょう…と心から思うのですが、一方で「それってスクリプト言語の手軽さ」を失うことでもあるのかなと考えてしまいます。
いっそ変数型宣言必須の”strict mode”みたいなのが欲しいような。

Use php.ini-production as a start

もしphp.iniの設定をするのに、PHPのソースコードに含まれる php.ini-production を参考にしましょう。include pathなど幾つかの項目は変更が必要でしょうが、土台にするには最適です。(意訳)
If you need a set of php.ini settings which would not hurt your performance and not break anything, look into php.ini-production in PHP source. You may need to change a couple of details (e.g. include path) but it’s a good starting point.
マニュアルによると、PHP5.3.0からはphp.ini-development(開発環境用)、php.ini-production(運用環境用)の2つが同梱されているようです。自分はまだPHP5.3を落としていませんが、以前のrecommendedなどとどの辺が違うのか、確認してみようと思います。

Use big realpath cache

リアルパス・キャッシュは、ファイル名や相対パスからユニークなフルパスを取得する際に非常に有用です。初期設定ではこのキャッシュサイズは16kですが、多くの長いパス名のファイルを扱うのであれば、この値を増やすのが良いでしょう。これはディスクアクセスという重い処理を軽減します。(意訳)

Realpath cache is very useful for the engine when it tries to find the unique full name of the file from just filename or relative path. By default, it’s 16K but if you have a lot of files with long pathes, it’s better to increase the size – it would save the expensive disk accesses.

この機能はPHP5.1から実装されたものですが、ちょっと大きい規模のアプリケーションになると、16kという値はすぐに超えてしまうかもという話は、よく聞きます。よほどメモリに困窮していなければ(そんな場合は既にパフォーマンスを云々言っていられないと思いますが)、64kくらい確保してしまうのが良いようです。

最後に、次のように締められています。

ここに挙げた以外にも、もっと多くのことが挙げられると思いますが、既にちょっと長くなりすぎました。一旦ここで終わりますが、あなたの考えをコメント欄で追加してくれると嬉しいです。

There are probably more things that could be said, but this post is pretty long already, so I will end it here and you are welcome to add your opinion in comments.

同じ言葉で、終わりたいと思います。

このエントリーをはてなブックマークに追加
Bookmark this on Yahoo Bookmark
Bookmark this on Livedoor Clip
Share on FriendFeed
Share on StumbleUpon
Newsing it!

No related posts.

2009 年 7 月 17 日