PHP7でAPCuを使う

PHPは5.5以降、APCからZend OPcache+APCuに変わりました。
APCはインストールしてiniファイルを編集したりするだけでopecode cacheとdata cacheを勝手に上手い具合にやってくれましたが、APCuは自分で使うようなスクリプトを書かなければなりません。

APCがAPCuとZend OPcacheに取って代わられたワケ – Qiita

インストールしたり、iniの設定項目について解説している記事は多くありますが、実際にAPCuを利用する方法についてはあまり無いようです。
APCuはPHPスクリプト上でユーザーキャッシュを利用する関数で、PHPサイトにもリファレンスがあります。
要はPHPからメモリ領域でデータの読み書きをするための方法みたいです。

PHP: APC – Manual

処理に時間のかかるようなデータや、DBから取得するようなデータをキャッシュしておき、2回目以降のアクセスではそれを読むといったようにして、PHPやDBの負荷を下げることが出来るようになります。

例えば、DBに接続して任意のクエリでデータを取得するスクリプトでは、取得結果をAPCuのユーザーキャッシュに保存し、次回以降のアクセスで同じクエリが来たらキャッシュを返す、とすると、DB接続のコスト削減になるわけです。

インストールについて

PHP7をyumで入れていれば、おそらく同じリポジトリでAPCuもあるはずですので、yum installできます。

yum --enablerepo=remi-php70 install php-pecl-apcu

これでインストールできます。
iniファイルはこんな感じのところにできているはずです。

vim /etc/php.d/40-apcu.ini

設定関連については省略します。yumでインストールしていれば、とりあえず使えるようにはなっているはずです。

APCuの使い方

基本的に、apc_addまたはapc_storeでデータを記録し、apc_fetchでデータを取り出すだけです。

1
2
3
4
5
6
//データを記録
apc_add('hoge', "aaa");
//データを取り出す
$v = apc_fetch('hoge');
// $v === "aaa"

addとstoreの違いは、addは新規登録のみなのに対して、storeは既存のキーを指定しても上書きするようです。

先程の例で、DB(MySQL)からデータを取得する部分をキャッシュするとしたら、このようになると思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//検索したいテーブルのIDをGETで取得し、データを返すスクリプト。
//テーブルの中身はid,v,dateとします。
$qval = intval( $_GET["id"] );  //DBクエリの変数(ここではテーブルのIDとします)
$key = "query_key_".$qval//このクエリのAPCu用キー
//APCuにキャッシュがあるか確認
if ( apc_exists($key) ) {
  //キャッシュがあるので、それを変数に
  list( $id, $v, $date ) = apc_fetch($key);
} else {
  //キャッシュが無いのでDBに接続 ( mysqliの変数定義部分は省略してます )
  $con = new mysqli(HOST, USERNAME, PASS, DBNAME);
  $stmt = $con->prepare("select `id`,`v`,`date` from DBNAME.TABLE_NAME where `id` = ?");
  $stmt->bind_param("i", $qval);
  $stmt->execute();
  $stmt->bind_result( $id, $v, $date );
  $stmt->fetch();
  $stmt->close();
  //データがDBから取得できていたらAPCにキャッシュする
  if( !empty($id) ) {
    add_apc( $key, array( $id, $v, $date ) );
  }
}
//出力
echo "id:".$id."\n";
echo "v:".$v."\n";
echo "date:".$date."\n";

MySQLからの取得結果を配列にして任意のキーに格納しています。
最初にアクセスしたユーザーがAPCuにクエリ結果をキャッシュするので、次からアクセスしたユーザーはキャッシュのデータを取得するようになり、DBには接続しなくなります。

なお、DBのデータが更新・削除などされた場合は、キャッシュに反映させなくてはならなくなります。
先程のようなクエリでも、データ内容が変わるようなことがある場合は、そのタイミングでAPCuのデータを消すなどする必要があるのです。

1
2
3
4
$qval = 1;  //編集されたデータのID
$key = "query_key_".$qval//APCu用キー
//指定のキーのデータを消す
apc_delete( $key );

とりあえず削除すれば、また先程のスクリプトのアクセスユーザーがキャッシュを作るので、内容は更新され、その次のユーザーからまたキャッシュを参照するようになります。

こんな感じで、DB接続のキャッシュとしてAPCuを利用するようにできました。
クエリの内容によっては、だいぶ負荷を下げられると思いますので、誰がアクセスしても同じ結果になる、更新性のあまり無いページのデータなどは積極的にAPCuにキャッシュするといいですね。

コメント

  1. seiya より:

    >基本的に、acp_addまたはapc_storeでデータを記録し、

    acp_add -> apc_add

タイトルとURLをコピーしました