ホームページ >バックエンド開発 >PHPチュートリアル >PHP パフォーマンス分析パート 3: 実践的なパフォーマンス チューニング
注: この記事は、PHP パフォーマンス分析シリーズの第 3 部です。ここをクリックして、PHP パフォーマンス分析パート 1: XHProf および XHGui の概要、または PHP パフォーマンス分析パート 2: 詳細を参照してください。 XHGui の勉強。
このシリーズの最初の記事では、XHProf について紹介しました。第 2 回の記事では XHGui UI について詳しく学びました。前回の記事では、XHProf/XHGui の知識を活用してみましょう。
実行する必要のないコードが最良のコードです。残りは単なる良いコードです。したがって、パフォーマンスを調整するときの最善の選択肢は、まず実行するコードをできるだけ少なくすることです。
OpCode Cache
まず、最も速く簡単なオプションは、OpCode Cache を有効にすることです。 OpCode キャッシュの詳細については、ここを参照してください。
上の画像では、Zend OpCache が有効になっている場合に何が起こるかを示しています。最後の行は、キャッシュを有効にしていないベースラインです。
中央の行では、パフォーマンスがわずかに向上し、メモリ使用量が大幅に削減されていることがわかります。わずかなパフォーマンスの向上は (おそらく)、OpCode キャッシュではなく、Zend OpCache の最適化によるものです。
最初の行は、最適化と OpCode キャッシュ後の結果で、大幅なパフォーマンスの向上が見られます。
それでは、APC 前後の変化を見てみましょう。上の図に示すように、Zend OpCache と比較すると、キャッシュが確立されるにつれて、最初 (中央行) のリクエストのパフォーマンスが低下し、消費時間とメモリ使用量の点でパフォーマンスが大幅に低下することがわかります。
次に、オペコード キャッシュが作成されると同様のパフォーマンスの向上が見られます。
コンテンツのキャッシュ
次にできることはコンテンツのキャッシュです?? これは WordPress では簡単です。 WP Super Cache など、コンテンツ キャッシュ用のインストールが簡単なプラグインが多数提供されています。 WP Super Cache は、Web サイトの静的バージョンを作成します。このバージョンは、コメントなどのイベントが発生すると、Web サイトの設定に従って自動的に期限切れになります。 (たとえば、負荷が非常に高い場合、何らかの理由でキャッシュの有効期限を無効にすることができます)。
コンテンツ キャッシュは、書き込みが少ない場合にのみ効果的に動作しますが、読み取りは無効になりません。
API の可用性による遅延と依存関係を軽減するために、アプリケーションがサードパーティ API から受け取るコンテンツもキャッシュする必要があります。
WordPress には、Web サイトのパフォーマンスを大幅に向上させる 2 つのキャッシュ プラグイン、W3 Total Cache と WP Super Cache があります。
どちらのプラグインも、リクエストされるたびにページを生成するのではなく、Web サイトの静的な HTML コピーを作成するため、応答時間が短縮されます。
独自のアプリケーションを開発している場合、ほとんどのフレームワークにはキャッシュ モジュールがあります:
Zend Framework 2: ZendCache
Symfony 2:複数のオプション
Laravel 4:Laravel キャッシュ
ThinkPHP 3.2.3:ThinkPHP キャッシュ
クエリ キャッシュ
もう 1 つのキャッシュ オプションはクエリ キャッシュです。 MySQL の場合、一般的なクエリ キャッシュがあると非常に役立ちます。他のデータベースの場合、クエリ結果セットを Memcached や cassandra などのメモリ内キャッシュにキャッシュすることも非常に効果的です。
コンテンツ キャッシュと同様、クエリ キャッシュは、多数の読み取り操作が含まれるシナリオで最も効果的です。小さなデータ変更によってキャッシュの大部分が無効になる可能性があるため、この場合、特に MySQL クエリ キャッシュに依存してパフォーマンスを向上させることはできません。
クエリ キャッシュにより、コンテンツ キャッシュを生成する際のパフォーマンスが向上する可能性があります。
下の図に示すように、クエリ キャッシュをオンにすると、メモリ使用量は大幅に変わりませんが、実際の実行時間は 40% 短縮されます。
キャッシュ オプションには 3 種類あり、query_cache_type によって制御および設定されます。
キャッシュを無効にする場合は 0 または OFF に設定します
1 に設定します または ON は、SELECT SQL_NO_CACHE
で始まる選択を除くすべての選択をキャッシュします。値を 2 に設定します。または DEMAND は、SELECT SQL_CACHE で始まる選択のみをキャッシュします。ゼロ以外の値に設定します。これをゼロに設定すると、
query_cache_typeキャッシュのセットアップやその他のパフォーマンス関連の設定のヘルプについては、mysql-tuning-primer スクリプトを確認してください。 MySQL クエリ キャッシュの主な問題は、それがグローバルであることです。キャッシュされた結果セットを構成するテーブルに変更を加えると、キャッシュが無効になります。書き込み操作が頻繁に行われるアプリケーションでは、これによりキャッシュがほとんど効果がなくなります。
ただし、 Memcached 、 riak 、 cassandra 、 redis など、ニーズやデータセットに基づいて、よりインテリジェントなキャッシュを構築するためのオプションが他にもたくさんありますクエリの最適化
上で述べたように、プログラムの実行が遅い原因はデータベース クエリであることが多く、クエリの最適化はコードの最適化よりも直接的なメリットをもたらすことがよくあります。
クエリの最適化は、コンテンツ キャッシュを生成する際のパフォーマンスの向上に役立ち、キャッシュが不可能な最悪のシナリオでも有益です。
プロファイリングに加えて、MySQL には低速クエリの特定に役立つオプション (低速クエリ ログ) があります。スロー クエリ ログには、指定した時間よりも長いクエリと、インデックスを使用しないクエリ (後者はオプション) が記録されます。
my.cnf で次の設定を使用してログ記録を有効にできます。
[mysqld]log_slow_queries =/var/log/mysql/mysql-slow.log long_query_time =1log-queries-not-using-indexes
long_query_time (秒単位) よりも遅いクエリは、ログ ファイル log_slow_queries に記録されます。デフォルト値は 10 秒で、最小値は 1 秒です。
さらに、log-queries-not-using-indexes オプションを使用すると、ログのインデックスを使用しないクエリをキャプチャできます。
MySQL にバンドルされている mysqldumpslow コマンドを使用してログを確認できます。
WordPress をインストールするときにこれらのオプションを使用します。ホームページがロードされて実行されると、次のデータが取得されます:
$ mysqldumpslow -g "wp_" /var/log/mysql/mysql-slow.logReading mysql slow query log from /var/log/mysql/mysql-slow.logCount: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows=358.0(358), user[user]@[host] SELECT option\_name, option\_value FROM wp_options WHERE autoload ='S'Count: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows=41.0(41), user[user]@[host] SELECT user\_id, meta_key, meta_value FROM wp_usermeta WHERE user_id IN (N)
まず、すべての文字列値が S 、数値は N で表されます。 -a フラグを追加すると、これらの値を表示できます。
次に、どちらのクエリも 0.00 秒かかったことに注目してください。これは、クエリが 1 秒のしきい値を下回っており、インデックスを使用していないことを意味します。MySQL コンソールで EXPLAIN を使用して、パフォーマンス低下の原因を確認します。
mysql> EXPLAIN SELECT option_name, option_value FROM wp_options WHERE autoload = 'S'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: wp_options type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 433 Extra: Using whereここでは、
possible_keys が NULL であることがわかり、インデックスが NULL ではないことが確認されます。使用済み 。
EXPLAIN は、MySQL クエリを最適化するための非常に強力なツールです。詳細については、こちらをご覧ください。
PostgreSQL には EXPLAIN (MySQL とは大きく異なります) も含まれており、MongoDB には $explain メタ演算子があります。
コードの最適化
通常、(OpCode キャッシュを使用して) PHP 自体による制限がなくなり、可能な限り多くのコンテンツをキャッシュし、クエリを最適化した場合にのみ、その後初めてコードの調整を開始できます。コードとクエリの最適化により、追加のキャッシュを作成するのに十分なパフォーマンスの向上がもたらされ、最悪のシナリオ (キャッシュなし) でのコードのパフォーマンスが向上するほど、アプリケーションの安定性が高まり、キャッシュが高速になります。再建された。
WordPress のインストールを (潜在的に) 最適化する方法を見てみましょう。
まず、最も遅い関数を見てみましょう:
の最初の項目は MySQL ではありません (実際には mysql_query () は 4 番目) ですが、apply_filter() 関数です。
WordPress コードベースは、カーネル、プラグイン、またはコールバックによってデータが追加される順序で、イベントベースのフィルタリング システムを通じて実行されるさまざまなデータ変換を特徴としています。
apply_filter() この関数は、これらのコールバックが適用される場所です。
まず、この関数が 4194 回呼び出されていることに気づくでしょう。クリックして詳細を確認すると、「親関数」を「呼び出し数」の降順に並べ替えることができ、translate() が __apply_filter()__ 関数を 778 回呼び出していることがわかります。
それでは、詳細をクリックして
translate() 関数の動作を詳しく見てみましょう。
ここでは、2 つの興味深いことがわかります。まず、親関数には 773 回呼び出される関数、__() があります。この関数のソース コードを確認すると、これが
translate() のラッパーであることがわかります。
<?php /** * Retrieves the translation of $text. If there is no translation, or * the domain isn't loaded, the original text is returned. * * @see translate() An alias of translate() * @since 2.1.0 * * @param string $text Text to translate * @param string $domain Optional. Domain to retrieve the translated text * @return string Translated text */ function __( $text, $domain = 'default' ) { return translate( $text, $domain ); } ?>経験則として、関数呼び出しはコストがかかるため、避ける必要があります。
translate() の代わりに常に __() を呼び出すようになったので、下位互換性を維持するためにエイリアスを translate() に変更する必要がありますが、__() は不要な関数を呼び出しません。 。
しかし、実際には、この変更は大きな違いはなく、単なるマイクロ最適化です?? しかし、コードの可読性が向上し、呼び出しグラフが簡素化されます。次に、サブ関数を見てみましょう:
がこれまでのところであることがわかります。最も時間がかかる通話。 コードの表示:
このコードの機能は、翻訳オブジェクトを取得し、$translations->translate() の結果を
<?php function translate( $text, $domain = 'default' ) { $translations = get_translations_for_domain( $domain ); return apply_filters( 'gettext', $translations->translate( $text ), $text, $domain ); } ?>apply_filter() に渡すことです。 )
。 $translations が NOOP_Translations クラスのインスタンスであることがわかります。 仅根据名称(__NOOP__),再经代码中的注释证实,我们发现翻译器实际上没有任何动作! 因此,也许我们完全可以避免这种代码! 通过在代码上进行小规模调试,我们看到当前使用的是默认的域,我们可以修改代码以忽略翻译器: 接下来,我们再次分析,确保要运行至少两次??确保所有缓存都建立,才是公平的对比! 这次运行的确更快!但是,快多少?为什么? 使用 XHGui 的比较运行这一特性就能找到答案。回到我们最初的运行,点击右上角的 “比较此处运行” 按钮,并从列表中选择新的运行。 我们发现,函数调用的次数减少了3% ,包容性实际运行时间减少 9% ,包容性CPU时间减少12%! 之后,可以按调用次数降序排列细节页,这证实(如同我们的预期) get_translations_for_domain() 和 NOOP_Translations::translate() 函数的调用次数减少。同样,可以确认没有预料之外的变化发生。 30 分钟的工作带来9 - 12% 的性能提升,这非常可喜。这就意味着真实世界的性能收益,即便是在应用了 opcache 之后。 现在我们可以对其函数重复这个过程,直到找不到更多优化点。 注意:此更改已提交到 WordPress.org 并已获更新。你可以在 WordPress Bug Tracker 跟踪讨论,查看实践过程。此更新计划包含在 WordPress 4.1 版本中。 除了出色的 XHProf/XHGui,还有一些很好的工具。 New Relic & OneAPM New Relic 与 OneAPM 均提供前后端性能分析;洞察后台堆栈讯息,包括 SQL 查询与代码分析,前端 DOM 与 CSS 呈现,以及 Javascript 语句。__OneAPM__ 更多功能请移步 (OneAPM 在线DEMO) uprofiler uprofiler 是目前还未发布的 Facebook XHProf 分支,该分支计划删除 Facebook 所需的 CLA。目前,两者具备相同的特性,只有一些部分重命名了。 XHProf.io XHProf.io 是 XHProf 的另一种用户界面。XHProf.io 在配置文件存储使用 MySQL ,用户友好性方面不及 XHGui。 Xdebug 在 XHProf 出现之前,Xdebug 早已存在??Xdebug 是一种主动的性能分析器,这意味着它不应该用于生产环境,但可以深入了解代码。 然而,它必须与另一个工具配合使用以读取分析器的输出 , 比如 KCachegrind)。但是 KCachegrind 很难安装在非 linux 机器上。另一个选择是 Webgrind。 Webgrind 无法提供 KCachegrind 的那些特性,但它是一个 PHP Web 应用程序,在任何环境都易于安装。 若搭配 KCachegrind ,你可以轻易探索并发现性能问题。(事实上,这是我最喜欢的剖析工具!) 分析和性能调优是非常复杂的工程。有了对的工具,并理解如何善用这些工具,我们可以很大程度地提高代码质量??即使是对我们不熟悉的代码库。 花时间去探索和学习这些工具是绝对值得的。 注意:本文是我们的 PHP 性能分析系列的第三篇,阅读 PHP 性能分析第一篇: XHProf & XHGui 介绍 ,和 PHP 性能分析第二篇: 深入研究 XHGui 。(本文系应用性能管理领军企业 OneAPM 工程师编译整理) <?php /** * Provides the same interface as Translations, but doesn't do anything */ class NOOP_Translations { ?>
<?php function translate( $text, $domain = 'default' ) { if ($domain == 'default') { return apply_filters( 'gettext', $text, $text, $domain ); } $translations = get_translations_for_domain( $domain ); return apply_filters( 'gettext', $translations->translate( $text ), $text, $domain ); } ?>
其他工具
结语