ホームページ  >  記事  >  バックエンド開発  >  APC で PHP を高速化

APC で PHP を高速化

WBOY
WBOYオリジナル
2016-06-23 13:46:451066ブラウズ

注: 赤でマークされている部分は、ご不明な点です。詳しい読者の方は、お気軽にアドバイスをお願いします

Cache Cow

Cache Cow (原文 Cache Cow, I'm Drinking, I don't)最初の単語の意味を知っておいてください。PHP をしばらく使用したことがある人なら、おそらく APC について聞いたことがあるでしょう。APC は、両方をキャッシュすることで PHP アプリケーションを大幅に高速化できるオペコード キャッシュです。 PHP コードとユーザー変数。APC をアプリケーションに追加すると、通常、アプリケーションの応答時間が改善され、サーバーの負荷が軽減され、ユーザーの満足度が向上します。 (代替 PHP キャッシュ)?? オプションの PHP キャッシュ。 APC は、PHP ソース コードとユーザー変数をキャッシュすることにより、PHP プログラムを効率的かつ大幅に高速化するオペコード キャッシュです。アプリケーションで APC を使用すると、通常、プログラムの応答時間が改善され、サーバーの負荷が軽減され、ユーザーが満足できるという効果が得られます。

この記事では、APC について紹介し、APC のインストールと構成のプロセスを説明し、その動作の例をいくつか示します。また、APC 管理者インターフェイスについても説明します。 APC のパフォーマンスをリアルタイムで表示し、Zend Framework でそれを使用する方法を示します。さあ、始めましょう!

この記事では、APC について紹介し、APC のインストールと構成について説明します。 、そして、彼女がどれほどコケティッシュであるかを確認するために、いくつかの例を味わってみましょう。同時に、APC 管理インターフェイスについて説明し、APC のパフォーマンスをリアルタイムで評価できるようにし、最後に APC を使用して Zend Framwork と連携する方法を示します。前の言葉はもう十分です。さあ!ヒーロー!一緒に行こう! ! !

はじめよう

上がって、頑張ってください!

まず、APC とは何か、そしてそれがどのように機能するかを簡単に説明します。

おそらくすでにご存じのとおり、PHP はインタープリタ型言語です (Java や C++ とは異なります)。クライアントが PHP ページをリクエストすると、サーバーはページのソース コードを読み取り、バイトコードにコンパイルして実行します。通常のシナリオでは、このプロセスはリクエストごとに実行されます…ただし、PHP は非常に高速であるため、おそらく気付かないでしょう!

もちろん、PHP が (Java や Java とは異なる) インタプリタ型言語であることはすでにご存知かもしれません。 C++)。顧客がいつ PHP ページをリクエストしても、サーバーはページのソース コードを取り出し、バイトコードをコンパイルして実行します。 PHP は目に見えないほど高速ですが、通常はこのプロセスが必要です。

ただし、1 分間に何百、何千ものリクエストが届くアプリケーションや Web サイトを実行している場合は、処理をできるだけ高速化したいと思うでしょう。そこで APC が役に立ちます。同社の Web サイトの言葉によれば、APC は「PHP 中間コードをキャッシュおよび最適化するための、無料でオープンで堅牢なフレームワーク」です。簡単に言えば、APC は各 PHP スクリプト実行のコンパイルされた出力をキャッシュし、それを後続のリクエストで再利用します。各リクエストを完全に満たすために必要な時間と処理サイクルが短縮され、パフォーマンスが向上し、応答時間が短縮されます。

アプリケーションや Web サイトに毎分何万ものトラフィックがある場合、すべてを高速化することを夢見ていると思います。良い赤ちゃん! APC があなたに手を振っています。 APC は自らを「PHP 中間コードのキャッシュと最適化のための、無料でオープンかつ堅牢なフレームワークである」と呼んでいます。先人は木を植え、子孫は木陰を楽しんでいます。 APC は、後続のリクエストで再利用および実行できるように、PHP スクリプトのコンパイルされた出力をキャッシュします。これにより、各リクエストの実行に必要な時間と処理サイクルが短縮され、パフォーマンスが向上し、応答時間が短縮されます。

うまくいきますか? (記事の最後にいくつかのベンチマークがあります)、セットアップも簡単です。以下に示すように、pecl コマンドを使用します。 ?どう思いますか (ドキュメントの後半にいくつかのベンチマークがあります)。さらに、APC のインストールと構成も非常に簡単です。pecl コマンドを使用したインストール例を見てみましょう:

shell> pecl install apc-3.1.4

PECL インストーラーがソース コードをダウンロードします。それをコンパイルし、システム上の適切な場所にインストールします。

上記のコマンドを実行すると、pecl インストーラーはソース コードをダウンロードし、コンパイルして、システムの関連ディレクトリにインストールします。

または、ソース コード アーカイブ (現時点では v3.1.4) を手動でダウンロードし、phpize:

を使用してロード可能な PHP モジュールにコンパイルします。

偶然にも、ソース コード アーカイブ (この記事の執筆時点では v3.14) を手動でダウンロードします。 ) を取得し、phpize でロード可能な PHP モジュールにコンパイルします。 PHP ロード可能なモジュールのメソッドは次のとおりです:

shell> cd apc-3.1.4

shell# phpize

shell# ./configure

shell# make

shell# make install

この手順では、PHP 拡張ディレクトリに apc.so という名前のロード可能な PHP モジュールを作成する必要があります。php.ini 構成ファイルで拡張機能を有効にし、Web サーバーを再起動して、phpinfo を簡単に呼び出して拡張機能が有効になっていることを確認する必要があります。 ():

上記の手順により、apc.so という名前のロード可能なモジュールが生成され、PHP 拡張ディレクトリに保存されます。次に、PHP 構成ファイル php.ini を変更し、Web サーバーを再起動すると、phpinfo () を使用できるようになります。拡張機能がインストールされていて利用可能かどうかを数秒で確認できます。

さらに深く掘り下げる

奥深い!さらに深く進んでください!

APC ソース コード アーカイブには、apc.php という名前のスクリプトが含まれています。このスクリプトはキャッシュの管理者インターフェイスとして機能し、いつでもキャッシュ内を調べて使用状況を確認したり、キャッシュされた変数を検査したりできるようにすることをお勧めします。コードを書き始める前に、これがどのように機能するかをよく理解してください。

APC ソース コード パッケージには、キャッシュ管理インターフェイスを提供する「apc.php」という名前のスクリプトが含まれており、いつでも使用状況を表示したり、キャッシュ内の変数を監視したりできます。 。コードを記述する前に、それがどのように機能するかを理解することは素晴らしいことです。

まず、ソース コード アーカイブからスクリプトを抽出し、Web サーバーのドキュメント ルートにコピーします。次に、それをテキスト エディターで開き、管理者パスワードを設定します (スクリプトの先頭近くにあります)。それが完了したら、Web ブラウザからスクリプトにアクセスしてみてください。次のような内容が表示されるはずです。

まず、ソース コード パッケージからスクリプトを解凍し、Web ディレクトリに置き、テキストを編集します。サーバーを開き、パスワードを設定します (スクリプトの最初の数行で)。完了すると、ブラウザからスクリプトにアクセスできるようになります。

ご覧のとおり、スクリプトは現在のキャッシュ ステータスの概要を提供し、一般的なキャッシュを表示します。情報、使用状況、およびヒットとミスに関する統計情報は、システム キャッシュ (オペコードを処理する) とユーザー キャッシュ (ユーザー変数を処理する) の両方について表示されます。 1 秒あたりのキャッシュ リクエストの数、ヒット率とミス率。

ご覧のとおり、このページには、現在のシステム キャッシュ ステータス、一般的なキャッシュ情報、キャッシュの使用状況、キャッシュの成功と失敗の統計の概要が表示されます。この情報は、システム キャッシュ (オペコードを保持する) とユーザー キャッシュ (ユーザー変数を保持する) の両方を示します。残りの統計からも、興味深いデータがいくつか見つかります。たとえば、1 秒あたりのキャッシュ リクエストの数、ヒットとミスの確率などです。

この情報は、キャッシュがどの程度機能しているかを理解し、特に、キャッシュがいっぱいになる頻度を示すキャッシュ フル カウント値に注目します。 、これはキャッシュ チャーンが高いことを示しており、キャッシュにさらに多くのメモリを割り当てる必要があることを示唆しています

この情報から、キャッシュがどの程度適切に機能しているかを理解することができ、どの部分が最適化された状態にあるかを確認することもできます。キャッシュがいっぱいになる頻度を示すキャッシュ フル カウントの値に特に注意してください。この値が大きい場合は、キャッシュ チャーンの数が多いことを示し、キャッシュにさらに多くのメモリを割り当てる必要があります。

「システム キャッシュ エントリ」タブには、現在キャッシュされている PHP スクリプトが、そのファイル名、サイズ、ヒット数とともにリストされます。APC はスクリプトのオペコードを自動的にキャッシュすることに注意してください。

「システム キャッシュ エントリ」タブのリスト現在キャッシュされている PHP スクリプト (ファイル名、サイズ、キャッシュ リクエストの数など) を表示します。注: APC はスクリプトのオペコードを自動的にキャッシュします。


[ユーザー キャッシュ エントリ] タブには、キャッシュに保存されているユーザー変数がその識別子、サイズ、作成時間と変更時間とともにリストされます。これらのエントリのいずれかを選択して、キャッシュ エントリの内部を確認することができます。ユーザー キャッシュ エントリは PHP スクリプトで手動で作成する必要があることに注意してください。その方法については次のページで説明します。

[ユーザー キャッシュ エントリ] タブには、ID やサイズなどのキャッシュされたユーザー データがリストされます。作成時間と変更時間。任意の項目を選択すると、キャッシュ全体の内容を確認できます。しかし、これらのユーザー データ キャッシュは PHP を通じて手動で作成する必要があります。この問題については後で説明します。



ページの右上隅にある [キャッシュのクリア] ボタンを使用していつでもオペコード キャッシュまたはユーザー キャッシュをクリアできることを覚えておいてください。

オペコード キャッシュまたはユーザー キャッシュをクリアできることを覚えておいてください。ページの右上隅にある「キャッシュのクリア」ボタンを使用すると、いつでもユーザー キャッシュを削除できます。オペコード キャッシュとユーザー データ キャッシュはクリアされます。

遥か彼方の銀河

遥か彼方の銀河


APC の仕組みについてよく理解できたので、APC でのユーザー変数のキャッシュは主に、変数の追加と取得を可能にする apc_add() メソッドと apc_fetch() メソッドを通じて行われます。これを説明する簡単な例を次に示します。

APC がどのように機能するかを明確に理解したので、コードを書き始めることができます。ユーザーデータは、主に apc_add() と apc_fetch() の 2 つのメソッドによってキャッシュされます。前者は追加に使用され、後者は抽出に使用されます。初めてこのスクリプトを実行すると、ページが最初から生成され、次のような内容が表示されます:

初めてこのスクリプトを実行すると、ページが最初から生成され、'次のようなものが表示されます:

このスクリプトを実行すると、次の画面が表示されます:


次に、ページを更新してみてください。キャッシュ:

次に、ページを更新してみます。今度は、出力変数がキャッシュからフェッチされます:

キャッシュを使用するためのビジネス ロジックは非常に単純です。最初のステップは、次のことを確認することです。必要なデータがすでにキャッシュに存在する場合は、元のデータ ソースから生成し、後で使用できるようにコピーをキャッシュに保存する必要があります。ファイルを外部プログラムにパイプするか、クライアントに出力します。


キャッシュを使用するビジネス ロジックは非常に単純です。最初のステップは、必要なデータがキャッシュに保存されているかどうかを確認することです。保存されていない場合は、後で使用できるようにコピーをキャッシュに保存します。ファイルに書き込みます。パイプから外部プログラムへの出力、またはクライアントへの直接出力。

前の例では、データがキャッシュに既に存在するかどうかの確認は apc_fetch() メソッドで行われ、新しいスナップショットのキャッシュへの書き込みは apc_add() メソッドで行われます。どちらのメソッドも ID を必要とすることに注意してください。この ID はキャッシュ内のオブジェクトを一意に識別し、キャッシュ データを保存および取得するためのキーとして機能します。また、apc_add() メソッドを使用すると、キャッシュが有効な期間 (秒単位) を指定できます。

前の例では、データがキャッシュされているかどうかの確認は apc_fetch() メソッドを通じて行われ、新しいスナップショットのキャッシュへの書き込みは apc_add() メソッドを通じて行われます。どちらの方法でも、キャッシュに格納されているオブジェクトを一意に識別し、データにアクセスするためのキー値として機能する ID が必要であることに注意してください。 apc_add() メソッドを使用すると、キーのタイムアウト期間 (秒単位) を設定することもできます。

管理者インターフェースを見ると、キャッシュされたデータとキャッシュのヒットとミスに関する統計が表示されます:

管理者インターフェースを見ると、キャッシュされたデータとキャッシュに関する統計が表示されるはずです。ヒットとミス: 統計:

Sunshine の配列


配列には spring もあります


文字列のキャッシュに加えて、APC では配列、オブジェクト、関数、参照をキャッシュすることもできます。値の配列をキャッシュする次の例を考えてみましょう。

なんと! APC は文字列のみをキャッシュできると思いますか?いいえ!配列、オブジェクト、メソッド、参照をキャッシュすることもできます。 ! !配列の値をキャッシュする次の例を考えてみましょう:


<?phpif ($quote = apc_fetch('starwars')) {  echo $quote;  echo " [cached]";} else {   $quote = "Do, or do not. There is no try. -- Yoda, Star Wars";    echo $quote;   apc_add('starwars', $quote, 120);}?>

以下に示すように、ネストされた配列または多次元配列をキャッシュすることもできます:

配列、お見せしましょう:


すごいです

オブジェクトのレッスン

次のレッスン: オブジェクトのキャッシュ

説明のために、APC では、単純なオブジェクトを初期化する次の例を考えてみましょう。ユーザー オブジェクトをキャッシュに保存し、キャッシュから取得します。

配列のキャッシュに加えて、APC はオブジェクトをキャッシュすることもできます。これを説明するために、次の例を考えてみましょう。User オブジェクトを初期化し、それをキャッシュに保存し、使用するためにキャッシュから取得します。

すごいです

出力は次のようになります:

出力は次のようになります:

最初のロードページ:


2 番目の読み込みページ:


同じ結果を得る別のアプローチは、オブジェクトを文字列にシリアル化し、その文字列をオブジェクトの代わりにキャッシュに保存することです。これは次のようになります:

同じ目的の別のアプローチでは、オブジェクトをシリアル化します。オブジェクトを直接キャッシュするのではなく、文字列に変換してキャッシュに保存します。例は次のとおりです。


<?php// if available, use cached array// if not, create and cache arrayif ($data = apc_fetch('heroes')) {  echo 'Cached data: ';} else {   $data = array('Spiderman', 'Superman', 'Green Lantern', 'Human Torch');  apc_add('heroes', $data, 120);}echo $data[1];  // Superman?>

Getting Closure

Cache Closure

APC を使用して参照をキャッシュすることもできます。少し調整して) 匿名関数を見てみましょう:

你也可以使用APC来缓存引用和匿名函数,看下面:

<?phpclass Calendar {  public $year = 2001;  public function &getYear() {    return $this->year;  }}$obj = new Calendar;$a = &$obj->getYear();  // 2001$obj->year = 2010;      // 2010apc_add('ref', $a, 60);$ref = apc_fetch('ref');$ref++;                 echo $ref;              // 2011?>


Anonymous functions or closures, new in PHP 5.3, offer an easy way to define functions “on the fly”. By default, however, closures cannot be cached with APC, as the Closure class does not implement serialization. Here’s a simple example that illustrates the problem:

匿名函数,或称为闭包,是 PHP5.3 的新特性,提供一种简单的悬空的方式来定义函数。默认情况下,APC无论如何是不能缓存闭包的,因为闭包没有实现序列化。这儿有一个简单的示例说明该问题:

<?php// check if closure exists in cache// if yes, retrieve and use// if not, define and add to cacheif (!apc_exists('area')) {  // simple closure  // calculates area from length and width  $area = function($length, $width) {      return $length * $width;  };  apc_store('area', $area);  echo 'Added closure to cache.';  } else {  $func = apc_fetch('area');  echo 'Retrieved closure from cache. ';  echo 'The area of a 6x5 polygon is: ' . $func(6,5);  }?>


When you try accessing this script, you’ll see an error about serialization, as shown below:

执行这个脚本,你会看到下面这个关于序列化的错误:

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed'


What’s the solution? Well, Jeremy Lindblom has extended the Closure class and created a custom SuperClosure class that supports both serialization and reflection. If you implement your closure using this class, you will be able to cache it. Here’s a revision of the previous script that demonstrates:

有什么解决办法呢?有的,Jeremy Lindblom 扩展了增长包类并且创建了 a custom SuperClosure class 来同时支持序列化和反射。如果你是使用这个类实现的闭包,那么就可以缓存它了。下面是对上文脚本的改进:

<?php// include SuperClosure classinclude 'SuperClosure.class.php';// check if closure exists in cache// if yes, retrieve and use// if not, define and add to cacheif (!apc_exists('area')) {  // simple closure  // calculates area given length and width  $area = new SuperClosure(    function($length, $width) {      return $length * $width;    }  );  apc_store('area', $area);  echo 'Added closure to cache.';  } else {  $func = apc_fetch('area');  echo 'Retrieved closure from cache. ';  echo 'The area of a 6x5 polygon is: ' . $func(6,5);  }?>


Here’s what the output looks like:

显示如下:

第一次浏览:


第二次浏览:


Note that these examples use apc_store() instead of apc_add(). In most cases, you can use these two functions interchangeably. The primary difference lies in how they behave when you attempt to store a value using an identifier that already exists in the cache: apc_add() will return false, while apc_store()will overwrite the previous value with the new value.

注意,这些实例使用apc_store() 代替 apc_add()。大多数情况下,你可以互换着这两个函数使用。主要的不同之处在于,当你使用一个缓存中已有的ID来存储数据时:apc_add()会返回 false,而 apc_store() 会使用新的值覆盖之前的值。

You can download the SuperClosure class definition from Jeremy Lindblom’s Github account.

你可以从 Jeremy Lindblom’s Github 账户上下载SuperClosure 这个类的定义。(注:刚浏览了下这个页面不存在,不过还可以从http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/上面直接拷贝一份使用)。

Utility Belt

实用技能

The APC extension also comes with a few other methods of note. For example, there’s the apc_inc() and apc_dec() methods, which can be used to increment or decrement cached values respectively:

APC扩展还有一些其余的方法和备注。例如:apc_inc()  和 apc_dec() 方法分别作用缓存值的自增和自减。

<?php// store a valueapc_store('a', 20);// increment and decrement stored valueapc_inc('a');         // 21apc_inc('a');         // 22apc_inc('a');         // 23apc_dec('a');         // 22// retrieve final valueecho apc_fetch('a');  // 22?>


The apc_bin_dump() method dumps the current contents of the cache in binary form, while the apc_bin_load() method loads a binary dump into the cache. Consider the following example, which illustrates:

apc_bin_dump()方法从缓存中把当前内容导出为二进制形式,而apc_bin_load() 方法则反之。仔细考虑以述实例:

<?php// clear cacheapc_clear_cache();apc_clear_cache('user');// store some valuesapc_store('a', 20001);apc_store('b', 7494);// dump cache in binary form$dump = apc_bin_dump();// clear cacheapc_clear_cache();apc_clear_cache('user');// try accessing a stored valueif (apc_fetch('a')) {  echo apc_fetch('a');} else {  echo 'Nothing in cache'; }// reload cache from binary dumpapc_bin_load($dump);// try accessing a stored valueif (apc_fetch('a')) {  echo apc_fetch('a');     // 20001} else {  echo 'Nothing in cache'; }?>


The apc_clear_cache() method can be used to clear the opcode cache or the user cache:

apc_clear_cache() 方法可以用来清除opcode 缓存或者用户缓存:

<?php// clear opcode cacheapc_clear_cache();// clear user cacheapc_clear_cache('user');?>


The apc_cache_info() method presents information on current cache status and memory allocation:

apc_cache_info() 方法能够提供当前缓存状态和内存分配信息

<?phpprint_r(apc_cache_info());?>


Here’s what the output looks like:

执行上述脚本能看到:


Tweet Tweet

推倒!推倒!

With all this background information at hand, let’s try APC with a real-world example. This next script uses APC to cache the result of a Twitter search:

Get 到这些新技能之后,让我们来现实世界里走你一个。接下来这个脚本用APC来缓存推特的搜索结果 :

<html>  <head>    <style type="text/css">      div.outer {      border-bottom: dashed orange 1px;      padding: 4px;      clear: both;      height: 50px;      }              div.img {        float:left;        padding-right: 2px;      }      span.attrib {        font-style: italic;      }    </style>    </head>    <body>    <h2>Twitter Search</h2>    <form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">    Search term: <input type="text" name="q" />    <input type="submit" name="submit" />    </form>   <?php    // if form submitted    if (isset($_POST['submit'])):      // sanitize query terms      $q = strip_tags($_POST['q']);            // generate cache id from query term      $id = md5($q);            // check if this search already exists in cache      // use if yes, generate fresh results and add to cache if no      if (apc_exists($id)) {        $records = apc_fetch($id);              } else {        // search Twitter for query term        $result = simplexml_load_file("http://search.twitter.com/search.atom?q=$q&lang=en");              // process Atom feed of search results        $records = array();        foreach ($result->entry as $entry) {          $item['image'] = (string)$entry->link[1]['href'];           $item['owner'] = (string)$entry->author->name;          $item['uri'] = (string)$entry->author->uri;          $item['tweet'] = (string)$entry->content;          $item['time'] = date('d M Y, h:i', strtotime($entry->published));           $records[] = $item;        }                // cache for 5 minutes        apc_store($id, $records, 300);      }                // display search results?>    <h2>Twitter Search Results for '<?php echo $q; ?>'</h2>      <?php foreach ($records as $r): ?>      <div class="outer">        <div class="img"><img width=48" height="48" src="<?php echo $r['image']; ?>" /></div>        <div><?php echo $r['tweet']; ?><br/>         <span class="attrib">By <a href="<?php echo $r['uri']; ?>"><?php echo $r['owner']; ?></a>         on <?php echo $r['time']; ?></span></div>      </div>       <?php endforeach; ?>    <?php endif; ?>  </body></html>   


Despite its length, this is actually a very simple script. It begins by creating a search form for the user to enter search terms into. Once this form is submitted, it connects to the Twitter Search API, retrieves an Atom-formatted list of search results matching the search term, process the Atom feed and render the final output as an HTML table. The results of the search are cached for five minutes, so that they can be used for subsequent searches containing the same search terms. Notice that each search query is assigned a unique identifier in the APC cache, by using its MD5 signature as key.

尽管不算长(估计是这意思),但确实是一个简单的脚本。开始处创建了一个表单给用户输入需要搜索的词条。一旦表单提交之后,连接推特的搜索接口,检索出Atom 格式化过的匹配搜索条目的结果列表,处理 Atom 格式提取出最终数据输出为html表格渲染到页面上。这些结果将被缓存五分钟,以备后续有相同搜索条止的请求使用。注意每一次搜索条件查询都会分配到通过md5签名成键作为唯一的APC缓存ID。

You will realize that there are two levels of caching in this script. First, APC’s opcode cache is automatically caching the compiled bytecode of the script, and using this cached bytecode for subsequent requests instead of recompiling it a new. Second, APC’s user cache is caching the results of each Twitter search, and reusing these results (instead of connecting to Twitter afresh) for subsequent searches containing the same query terms. As a result, subsequent searches for the same term will be served from the cache, leading to a noticeable reduction in load time (try it for yourself and see).

你会发现在这个脚本中做了两层缓存。首先,APC的opcode缓存是自己缓存脚本的编译过的字节码的,并且在后续的请求中使用这些字节码而不是重新编译一份。其次,APC的用户缓存是缓存推特的搜索结果,然而在后续有相同检索条目的请求中使用这些结果(而不是重新连接推特)。这就能使得后续相同的搜索服务于缓存,为我们赢来更少的加载时间(请知行合一)。

Here’s an example of what the output looks like:

请看示例:(刚刚看了下推特的这个api已经停用了,就不管他了)


In The Frame

框架中使用


If you’re a fan of the Zend Framework, you’ll be happy to hear thatZend_Cache comes with built-in support for APC, allowing you to begin using it out of the box. To illustrate, consider the following Zend Framework controller, which revises the previous example into a Zend Framework controller:

如果你是Zend Framework 迷。那么你将会喜闻乐见Zend_Cache 已经内建支持APC,你可以开始使用它原装的了。好好研究下面这个使用Zend Framework 控制层的实例,我们将用Zend Framwork 控制层来改进上一个例子的实现向你阐明APC 在Zend Framework 中的使用:

<?phpclass IndexController extends Zend_Controller_Action{    public function indexAction()    {        // action body    }    public function searchAction()    {      // initialize cache      $cache = Zend_Cache::factory( 'Core',                                     'APC',                                     array('lifeTime' => 300, 'automatic_serialization' => true));      // create form and attach to view                                                $form = new SearchForm();      $this->view->form = $form;                   // validate input            if ($this->getRequest()->isPost()) {        if ($form->isValid($this->getRequest()->getPost())) {          // get sanitized input          $values = $form->getValues();                            // calculate MD5 hash          $id = md5($values['q']);                    // look for records in cache          if (!$records = $cache->load($id) ){                                   // if not present in cache            // search Twitter for query term            $result = simplexml_load_file("http://search.twitter.com/search.atom?q=" . $values['q'] . "&lang=en");                        // process Atom feed of search results            $records = array();            foreach ($result->entry as $entry) {              $item['image'] = (string)$entry->link[1]['href'];               $item['owner'] = (string)$entry->author->name;              $item['uri'] = (string)$entry->author->uri;              $item['tweet'] = (string)$entry->content;              $item['time'] = date('d M Y, h:i', strtotime($entry->published));               $records[] = $item;            }                        // save to cache            $cache->save($records, $id);          }                    // assign results to view          $this->view->records = $records;          $this->view->q = $values['q'];        }                 }           }}// search formclass SearchForm extends Zend_Form{  public function init()  {    // initialize form    $this->setMethod('post');             // create text input for search term    $q = new Zend_Form_Element_Text('q');    $q->setLabel('Search term:')         ->setOptions(array('size' => '35'))         ->setRequired(true)         ->addValidator('NotEmpty', true)         ->addFilter('HTMLEntities')                     ->addFilter('StringTrim');                    // create submit button    $submit = new Zend_Form_Element_Submit('submit');    $submit->setLabel('Search');                    // attach elements to form    $this->addElement($q)         ->addElement($submit);  }}?>


Here, the searchAction() method first sets up the Zend_Cache instance, with the Core frontend and the APC backend. The form object, which extends Zend_Form, is then added to the view, together with all necessary validators and filters, and the view is rendered.

本例中,searchAction() 方法首先生成一个以Core为前端和以APC为后端的Zend_Cache实例,继承自Zend_Form的表单对象,添加到页面中,还带有验证和过滤的功能,接着渲染页面。

When the user submits the form, control transfers back to the action controller, which checks the input and retrieves the filtered values. It then checks the cache to see if a search result already exists for this search term, and uses it if available; if not, it connects to the Twitter Search API, retrieves a result set, and saves it to the cache for future use. The results are then rendered through the view script. On subsequent searches for the same term, the cached result set will be used, producing a much faster response.

用户提交表单后,控制转移到后面的控制层,用以验证输入和提取过滤后的内容。接下来检查一下缓存中是否有相同搜索条目的存储,如果有取出使用,如果没有,连接推特的搜索API,取出结果集,并且保存一份到缓存中以备后用。然后通过脚本把结果渲染到页面上。后来的搜索如果是相同的词条,这些缓存里的结果集就可以用上了,这就大大提升了响应速度。

Here’s the code for the view script:

下面是页面代码:

<style type="text/css">  div.outer {  border-bottom: dashed orange 1px;  padding: 4px;  clear: both;  height: 50px;  }          div.img {    float:left;    padding-right: 2px;  }  span.attrib {    font-style: italic;  }</style><h2>Twitter Search</h2<?php echo $this->form; ?><?php if ($this->records): ?>  <h2>Twitter Search Results for '<?php echo $this->q; ?>'</h2>  <?php foreach ($this->records as $r): ?>  <div class="outer">    <div class="img"><img width=48" height="48" src="<?php echo $r['image']; ?>" /></div>    <div><?php echo $r['tweet']; ?><br/>     <span class="attrib">By <a href="<?php echo $r['uri']; ?>"><?php echo $r['owner']; ?></a>     on <?php echo $r['time']; ?></span></div>  </div>   <?php endforeach; ?><?php endif; ?>


And here’s a sample of the output:

渲染结果:(由于推特这么接口关了,此处省略一张图)


The Need For Speed

速之所需


At this point, there’s only one question left to answer: does APC’s opcode caching really deliver the goods and produce a verifiable increase in performance?

到了这个点上,还有最后一个问题了:APC 的opcode 缓存是否真能不负众望,为我们带来可见的性能上的提升?

A good way to test this is by benchmarking a PHP script with and without APC, and evaluating the performance differential if any. ApacheBench (ab) is my tool of choice for this test, and my testbed will be the default welcome page of a new Zend Framework project. You can create this by installing the Zend Framework and then using the zf command-line tool to initialize a new, empty project, like this:

最好的办法就是对同一个脚本使用和不使用APC做基准测试,评估所有性能的差异。我选择ApacheBench(ab)作为测试工具,Zend Framework 项目默认欢迎页为测试脚本。你安装好 Zend Framework 之后,你可以使用它的命令行工具zf来初始化一个新的空项目,例如:

shell> zf create project example

Now, turn off APC, by   the extension in your php.ini configuration file and restarting the Web server. Then, use ab to benchmark the application welcome page by sending it 1000 requests with a concurrency level of 5, as follows:

现在,通过配置php.ini 来禁用APC并且重启web服务器。然后,使用ab做一个基准测试:向该欢迎页做1000次请求,并发级别为5,如下:

shell> ab -n 1000 -c 5 http://example.localhost/default/index/index

On my development system, this produces output like the following:

在我的开发系统上,这个命令产生的结果如下:

This is ApacheBench, Version 2.3 <$Revision: 655654 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient)Completed 100 requestsCompleted 200 requestsCompleted 300 requestsCompleted 400 requestsCompleted 500 requestsCompleted 600 requestsCompleted 700 requestsCompleted 800 requestsCompleted 900 requestsCompleted 1000 requestsFinished 1000 requestsServer Software:        nginx/1.5.3Server Hostname:        localhostServer Port:            1234Document Path:          /php/apc/exam12/public/index.phpDocument Length:        1042 bytesConcurrency Level:      5Time taken for tests:   10.206 secondsComplete requests:      1000Failed requests:        0Write errors:           0Total transferred:      1189000 bytesHTML transferred:       1042000 bytesRequests per second:    97.98 [#/sec] (mean)Time per request:       51.031 [ms] (mean)Time per request:       10.206 [ms] (mean, across all concurrent requests)Transfer rate:          113.77 [Kbytes/sec] receivedConnection Times (ms)              min  mean[+/-sd] median   maxConnect:        0    1   1.3      0       9Processing:    31   50   8.4     48      96Waiting:       31   50   8.4     48      96Total:         31   51   8.3     49      96Percentage of the requests served within a certain time (ms)  50%     49  66%     52  75%     54  80%     55  90%     63  95%     69  98%     74  99%     79 100%     96 (longest request)


The main numbers to look at here are the requests per second and the average time per request. The lower the average time per request, the better the performance. Similarly, the greater the number of requests served, the better the performance.

主要关注的数据是requests per second(每秒处理次数) 和 the average time per request(每个请求平均用时)。平时请求时长越短,性能越好。同理,每秒处理次数越大,性能越好。

Next, re-enable APC, restart the Web server and try the test again. On my development system, this produces output like the following:

下面,打开APC,重启WEB服务器,再试一次,我的开发机上效果是这样子的:

This is ApacheBench, Version 2.3 <$Revision: 655654 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient)Completed 100 requestsCompleted 200 requestsCompleted 300 requestsCompleted 400 requestsCompleted 500 requestsCompleted 600 requestsCompleted 700 requestsCompleted 800 requestsCompleted 900 requestsCompleted 1000 requestsFinished 1000 requestsServer Software:        nginx/1.5.3Server Hostname:        localhostServer Port:            1234Document Path:          /php/apc/exam12/public/index.phpDocument Length:        0 bytesConcurrency Level:      5Time taken for tests:   3.917 secondsComplete requests:      1000Failed requests:        996   (Connect: 0, Receive: 0, Length: 996, Exceptions: 0)Write errors:           0Non-2xx responses:      4Total transferred:      1184908 bytesHTML transferred:       1037832 bytesRequests per second:    255.32 [#/sec] (mean)Time per request:       19.583 [ms] (mean)Time per request:       3.917 [ms] (mean, across all concurrent requests)Transfer rate:          295.44 [Kbytes/sec] receivedConnection Times (ms)              min  mean[+/-sd] median   maxConnect:        0    0   0.7      0       7Processing:     4   19   5.2     18      42Waiting:        4   19   5.2     18      42Total:          5   20   5.2     18      43Percentage of the requests served within a certain time (ms)  50%     18  66%     22  75%     23  80%     24  90%     26  95%     28  98%     33  99%     36 100%     43 (longest request)


As you can see, enabling APC has resulted in an almost 185% increase in performance, with the server now being able to handle 71 requests per second (up from 25 earlier) and the average time per request coming down to 69 ms (from 194 ms earlier).

看见没有!开启APC的结果就是提升200%多的性能!看看吧,现在每秒请求次数和平时请求时长分别优化了多少?自!已!!算!!!

The above test was run with APC’s default settings. However, APC comes with a number of configuration settings that you can tweak further to squeeze even better performance from it. Here are some of the important ones:

上述测试都是基于APC默认配置的。但是,APC是有着大把专属的配置的,你可以慢慢调整来压榨出更高的性能。现在先来看看几个比较重置的配置项:

  • ‘apc.shm_size’ controls the size of the APC memory cache;
  • ‘apc.shm_size’ 控制APC缓存的容量;
  • ‘apc.stat’ controls whether APC checks each script to see if it has been modified and needs to be recompiled and recached;
  • ‘apc.stat’ 控制APC是否挨个脚本检查变更以否和是否需要重新编译重新缓存;
  • ‘apc.optimization’ determines the degree of optimization to apply;
  • ‘apc.optimization’ 决定应用的优化程度;
  • ‘apc.filters’ specifies which files should be cached;
  • ‘apc.filters’ 指定哪些文件需要缓存;
  • ‘apc.write_lock’ places an exclusive lock for caching compiled script bytecode;
  • ‘apc.write_lock’  置入脚本编译的字节码的独占锁;
  • ‘apc.lazy_functions’ and ‘apc.lazy_classes’ enables lazy loading for functions and classes.
  • ‘apc.lazy_functions’ 和 ‘apc.lazy_classes’ 开启函数和类的延迟加载。
  • You can read more about these and other configuration directives here.

    猛戳这里获取更多配置信息。

    That’s about all I have for the moment. I hope this tutorial has given you some insight into how APC works, and how you can use it to improve the performance of your PHP applications. Try it out the next time you have a performance optimization problem, and see what you think!

    これらは私がこれまでに知っていることです。このチュートリアルにより、APC がパンツを脱いだ状態でどのように動作するか、また APC を使用して PHP アプリケーションのパフォーマンスを向上させる方法が明確に理解できることを願っています。次回、パフォーマンスの最適化に関する問題が発生したら、ぜひ試してみてください。そうすれば、それを理解し、知識と行動が一体化した状態を達成できるでしょう。

    著作権 Melonfire, 2010.All Rights Reserved.

    著作権は私に属します。無断転載を禁じます。 2010年の本。






    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。