CakePHPでファイルキャッシュ、メモリキャッシュを使う | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

CakePHP2系でキャッシュを使いたい場合、ファイルキャッシュやメモリキャッシュなどいくつかの方法で実現することができます。

サイトの規模が大きくなってきてパフォーマンスを考慮するようになってきたら、キャッシュの導入を検討してみてもよいかもしれません。



CakePHPでファイルキャッシュを利用する


CakePHPのファイルキャッシュ(Viewキャッシュ)はデフォルトで提供されているキャッシュの仕組みで、その名の通りファイルにデータを一時的に保存して利用する仕組みです。

コントローラで様々な処理をし、テンプレートと組み合わせて出力する最終的なHTMLファイルをキャッシュさせることで、パフォーマンスを向上させるというようなことができます。

厳密に言うと、静的なHTMLを吐き出してキャッシュさせてというのではなく、CakePHPの構造上コントローラを通してキャッシュファイルが読込まれるため、コントローラがすばやく処理できるように必要最低限の処理をHTMLにくっつけて出力します。


肝心のファイルキャッシュの利用方法ですが、まずはキャッシュを利用する設定を行います。

設定変更するのはcore.phpです。


Configure::write('Cache.check', true);


デフォルトでは、コメントアウトされているので解除します。

次に、キャッシュを利用したいコントローラファイルを開きます。


<?php

App::uses('AppController', 'Controller');

class PagesController extends AppController {

    public $name = 'Pages';
    public $helpers = array('Common', 'Cache');
    public $cacheAction = TRUE;

    public function foo() {
    }
}


コントローラファイルでは2箇所編集し、1つ目はキャッシュのヘルパーを利用できるように$helpersの配列にCacheを追加、もう1つは$cacheAction変数にTRUEをセットし、このコントローラでキャッシュを生成することを定義します。


基本的には、この設定でキャッシュが生成されるようになります。

作られるキャッシュファイルは、以下のキャッシュディレクトリに保存されます。


$ ls -la /path/to/cakephp/app/tmp/cache/views/
合計 16
drwxrwxr-x 2 apache apache 4096 10月 18 04:47 .
drwxrwxr-x 5 apache apache 4096  7月  1 15:55 ..
-rw-r--r-- 1 apache apache 4297 10月 18 00:15 pages_display.php

キャッシュファイルは、「コントローラ名_アクション名_パラメータ.php」という形式で作られます。

もし特定のアクションを通ったときだけキャッシュを作りたい場合や、キャッシュの有効期限を細かく設定したい場合は、下記のようにコントローラーの$cacheActionに指定することで制御することもできます。


<?php

App::uses('AppController', 'Controller');

class PagesController extends AppController {

    public $name = 'Pages';
    public $helpers = array('Common', 'Cache');

    public $cacheAction = array("foo"  => "1 day",
                                "bar"  => "1 hour",
                                "hoge" => "3 minutes");

    public function foo() {
    }

    public function bar() {
    }

    public function hoge() {
    }

    public function fuga() {
    }
}


上記の場合、fooアクションのキャッシュは1日に、barアクションのキャッシュは1時間、hogeアクションのキャッシュは3分間、そして指定していないfugaアクションはキャッシュが行われません。

細かくキャッシュをする・しないを切り分けられるので、それぞれの処理内容に応じて変えることができます。


これは、ファイルキャッシュのやり方になるので、テンプレートファイルを加工した最終的な結果がキャッシュされます。

ですので、テンプレートをいじったりコントローラ内の処理を変えてもキャッシュが有効期限内であれば当然前回と同じ内容が表示されてしまうので注意が必要です。

キャッシュを無効にしたい場合は、キャッシュディレクトリの中身を消してしまうか(再度アクセスしたらキャッシュが作られますが)、core.phpで変更した「Cache.check」をコメントアウトするか、FALSEに変更します。



CakePHPでメモリキャッシュを利用する


例えば、DBから何度も同じ値を取得するような場合は、その値をキャッシュさせておきたいという場合があります。

こういった場合に、そのキャッシュデータをメモリ上に保存しておき、いつでも書き込み・読み込みができるようにしておければ、パフォーマンス的にもかなりメリットが出てきます。


CakePHPでメモリキャッシュを実装する方法は、幾つかのキャッシュエンジンを選択することができますが、ここではAPC(Alternative PHP Cache) を使うやり方を書きます。

他のキャッシュエンジンに関しても、導入さえすればおそらく同様のやり方で扱えると思います。(設定方法などは、CakePHPの設定ファイルであるbootstrap.phpも確認してみてください)


まず、APCをメモリキャッシュのエンジンとして利用する方法(APCの導入方法は割愛します)ですが、bootstrap.phpにて利用するキャッシュエンジンをAPCで動かすように設定します。

デフォルトは、ファイルキャッシュになっているため、そのまま使っていると思っていたパフォーマンスのメリットは得られないので注意が必要です。


Cache::config('default', array(
    'engine' => 'Apc', //[required]
    'duration'=> 3600));


bootstrap.phpには、各キャッシュエンジンごとの設定ファイルのサンプルがあるので、それをそのままコメントアウトを解除して使うのが手っ取り早いと思います。

ちなみに、durationはキャッシュの有効期限(秒)です。

次に、デフォルトの設定になっているファイルキャッシュを無効にする(コメントアウト)しておきます。


//Cache::config('default', array('engine' => 'File'));


あとは、キャッシュの書き込みや読み込みとして使えます。


<?php

App::uses('AppController', 'Controller');

class PagesController extends AppController {

    public $name = 'Pages';

    public function display() {
        if (($str = Cache::read("cache_str_name")) === FALSE) {
            $str = "no cache";
            Cache::write("cache_str_name", $str);
        } else {
            $str = "cache";
        }
        $this->set("str", $str);
    }
}


Cache::readでキャッシュの中身を読込み、Cache::writeでキャッシュへデータを書き込みます。

それぞれ、第一引数で指定しているのはキャッシュ名です。

キャッシュは設定ファイルで指定したdurationの秒数だけ有効になりますが、意図的に削除したい場合はCache::delete("cache_str_name");のように指定して削除もできます

今回はAPCでメモリキャッシュしているので、Apacheを再起動してもキャッシュデータはクリアされてしまいます。


ここまでは、メモリキャッシュのお話でしたが、APCなどのキャッシュエンジンを導入していなくても、ファイルキャッシュとして同様にデータを一時的に保存することも可能です。

これは、デフォルトのキャッシュエンジンをそのままFileにして利用するだけです。

この場合、キャッシュディレクトリの直下にキャッシュファイルができ、キャッシュの読み込みはのこのキャッシュの中身をunserializeして復元されます。


/path/to/cakephp/app/tmp/cache/cake_cache_str_name

中身は、下記のようになっています。


1350831674
s:8:"no cache";


APCのようなキャッシュエンジンを使っていても使っていなくてもプログラム自体の処理は変わりません。

逆に、APCを導入していてメモリキャッシュされているつもりがファイルキャッシュで動いててパフォーマンスが出ないというようにはまってしまう可能性はあります。

そうした場合は、きちんとキャッシュの設定を確認しておいた方がよいでしょう。

キャッシュの設定の確認は、設定ファイルを確認する以外に、以下のようにして設定を見ることができます。


$config = Cache::config('default');
[ 出力例 ]
array(2) {
  ["engine"]=>
  string(3) "Apc"
  ["settings"]=>
  array(5) {
    ["engine"]=>
    string(3) "Apc"
    ["duration"]=>
    int(3600)
    ["probability"]=>
    int(100)
    ["prefix"]=>
    string(4) "app_"
    ["groups"]=>
    array(0) {
    }
  }
}


また、かなり余談ではありますが、利用するキャッシュエンジンをコントローラーの中で切り替えて利用することもできます。


<?php

App::uses('AppController', 'Controller');

class PagesController extends AppController {

    public $name = 'Pages';

    public function display() {
        Cache::config('apc_cache', array(
                      'engine' => 'Apc',
                      'duration'=> 100,));
        if (($str = Cache::read("cache_str_name", "apc_cache")) === FALSE) {
            $str = "no cache";
            Cache::write("cache_str_name", $str, "apc_cache");
        } else {
            $str = "cache";
        }
        $this->set("str", $str);
    }
}


Cache::configで、任意の識別子(apc_cache)に利用するキャッシュエンジンを指定し、Cache::readの第二引数やCache::writeの第三引数でその識別子を指定して利用します。

デフォルトで、ファイルキャッシュを利用していてもこの識別子の指定があれば、その部分だけがAPCでメモリキャッシュが動作するという具合です。