キャッシュによるパフォーマンスの向上

Phalcon は、頻繁に使用される、またはすでに処理されたデータに、高速なアクセスを行う Phalcon\Cache クラスを提供しています。 Phalcon\Cache は C で実装され、バックエンドからアイテムを取得する際にオーバーヘッドを減らし、高いパフォーマンスで動作します。 このクラスでは、フロントエンドとバックエンドのコンポーネントの内部構造を使用します。 フロントエンドコンポーネントは、バックエンドコンポーネントクラスにストレージオプションを提供しながら入力ソースまたはインターフェイスとして機能します。

いつキャッシュを実装する?

このコンポーネントは非常に高速ですが、必要でないケースで実装すると、利用することで得られるメリットよりも、パフォーマンスの低下によるデメリットの方が大きくなる可能性があります。 キャッシュを使用する前に確認をお勧めします。

  • 毎回同じ結果 (変更頻度の低い) を返す複雑な計算をしている
  • 多くのヘルパを利用し、生成される出力がほとんど同じである
  • 常にデータベースのデータにアクセスしており、これらのデータはほとんど変わらない

キャッシュの振る舞い

キャッシュ処理は、2 つの部分に分かれています。

  • フロントエンド: この部分は、キーが期限切れになっていないかどうかをチェックし、保存する前にデータに追加の変換を実行します。
  • バックエンド: この部分は、フロントエンドが必要とするデータの通信、書き込み、読み取りを行います。

ファクトリー

フロントエンドまたはバックエンドのアダプタをインスタンス化するには、次の2つの方法があります。

従来の方法

<?php

use Phalcon\Cache\Backend\File as BackFile;
use Phalcon\Cache\Frontend\Data as FrontData;

// 出力フロントエンドの作成。 ファイルを2日間キャッシュ。
$frontCache = new FrontData(
    [
        'lifetime' => 172800,
    ]
);

// 'Output'から'File'バックエンドにキャッシュするコンポーネントを作成する
// キャッシュファイルディレクトリを設定する - フォルダの値の最後に '/'を置くことが重要
$cache = new BackFile(
    $frontCache,
    [
        'cacheDir' => '../app/cache/',
    ]
);

または、次のようにFactoryオブジェクトを使用します:

<?php

use Phalcon\Cache\Frontend\Factory as FFactory;
use Phalcon\Cache\Backend\Factory as BFactory;

 $options = [
     'lifetime' => 172800,
     'adapter'  => 'data',
 ];
 $frontendCache = FFactory::load($options);

$options = [
    'cacheDir' => '../app/cache/',
    'prefix'   => 'app-data',
    'frontend' => $frontendCache,
    'adapter'  => 'file',
];

$backendCache = BFactory::load($options);

出力フラグメントのキャッシュ

出力フラグメントは、そのままの状態でキャッシュされ、HTML またはテキストの一部で、そのまま返されます。 出力は、ob_*関数またはPHP出力から自動的にキャプチャされ、キャッシュに保存されます。 次の例は、このような使用法を示しています。 PHPが生成した出力を受け取り、ファイルに格納します。 ファイルの内容は172,800秒(2日)ごとに更新されます。

このキャッシュ機構の実装では、コードの該当部分を呼び出すたびに、ヘルパー Phalcon\Tag::linkTo()を呼び出さないので、パフォーマンスが向上します。

<?php

use Phalcon\Tag;
use Phalcon\Cache\Backend\File as BackFile;
use Phalcon\Cache\Frontend\Output as FrontOutput;

// 出力フロントエンドの作成。 ファイルを2日間キャッシュ。
$frontCache = new FrontOutput(
    [
        'lifetime' => 172800,
    ]
);

// 'Output'から'File'バックエンドにキャッシュするコンポーネントを作成する
// キャッシュファイルディレクトリを設定する - フォルダの値の最後に '/'を置いておくことが重要です
$cache = new BackFile(
    $frontCache,
    [
        'cacheDir' => '../app/cache/',
    ]
);

// キャッシュファイルを ../app/cache/my-cache.html で取得/設定する
$content = $cache->start('my-cache.html');

// $contentがnullの場合、コンテンツはキャッシュ用に生成されます。
if ($content === null) {
    // 日付と時刻を表示する
    echo date('r');

    // サインアップアクションへのリンクを生成する
    echo Tag::linkTo(
        [
            'user/signup',
            'Sign Up',
            'class' => 'signup-button',
        ]
    );

    // 出力をキャッシュファイルに保存する
    $cache->save();
} else {
    // キャッシュされた出力をechoする
    echo $content;
}

任意データのキャッシュ

データのキャッシュは、あなたのアプリケーションの重要さと同じです。 キャッシュは、一般的に使用されるデータ(で更新されないもの) を再利用することで、データベースの負荷を減らすことができます。またあなたのアプリケーションを高速化します。

ファイルバックエンドの例

キャッシュのアダプターの1つは、Fileです。 このアダプターの唯一重要なところは、そのキャッシュファイルを保存する場所です。 これは、cacheDir オプションで制御できます。このディレクトリは、最後が バックスラッシュで終らなければなりません。

<?php

use Phalcon\Cache\Backend\File as BackFile;
use Phalcon\Cache\Frontend\Data as FrontData;

// Dataフロントエンドを使用して2日間ファイルをキャッシュする
$frontCache = new FrontData(
    [
        'lifetime' => 172800,
    ]
);

// 'Data'を'File'バックエンドにキャッシュするコンポーネントを作成する
// キャッシュファイルディレクトリを設定する - フォルダの値の最後に `/`を置くことが重要
$cache = new BackFile(
    $frontCache,
    [
        'cacheDir' => '../app/cache/',
    ]
);

$cacheKey = 'robots_order_id.cache';

// キャッシュされたレコードを取得してみる
$robots = $cache->get($cacheKey);

if ($robots === null) {
    // $robotsはキャッシュの有効期限が切れているか、データが存在しないためnull
    // データベースを呼び出して変数に代入
    $robots = Robots::find(
        [
            'order' => 'id',
        ]
    );

    // キャッシュに保存
    $cache->save($cacheKey, $robots);
}

// $robotsを使う:)
foreach ($robots as $robot) {
   echo $robot->name, '\n';
}

Memcached バックエンドの例

Memcachedバックエンドを使用するとき、上の例を少しだけ変更します(特に設定項目のあたり)。

<?php

use Phalcon\Cache\Frontend\Data as FrontData;
use Phalcon\Cache\Backend\Libmemcached as BackMemCached;

// データを1時間キャッシュする
$frontCache = new FrontData(
    [
        'lifetime' => 3600,
    ]
);

// 'Memcached'バックエンドに'データ'をキャッシュするコンポーネントを作成する
// Memcached接続設定
$cache = new BackMemCached(
    $frontCache,
    [
        'servers' => [
            [
                'host'   => '127.0.0.1',
                'port'   => '11211',
                'weight' => '1',
            ]
        ]
    ]
);

$cacheKey = 'robots_order_id.cache';

// キャッシュされたレコードを取得してみる
$robots = $cache->get($cacheKey);

if ($robots === null) {
    // $robotsはキャッシュの有効期限が切れているか、データが存在しないためnull
    // データベースを呼び出して変数に代入
    $robots = Robots::find(
        [
            'order' => 'id',
        ]
    );

    // キャッシュに保存
    $cache->save($cacheKey, $robots);
}

// $robotsを使う :)
foreach ($robots as $robot) {
   echo $robot->name, '\n';
}

キャッシュの確認

このキャッシュに加えられた要素はキーによって一意に特定できます。 ファイルバックエンドの場合、キーは実際のファイル名です。 キャッシュからデータを取得するため、一意のキーを使って呼び出さなければなりません。 もしキーが存在しない場合、getメソッドはnullを返します。

<?php

// キー'myProducts'で製品を取得する
$products = $cache->get('myProducts');

もしあなたがどのようなキーがそのキャッシュに保存されているのかが知りたい場合、queryKeys メソッドを呼びだすことができます。

<?php

// キャッシュで使用されているすべてのキーを照会する
$keys = $cache->queryKeys();

foreach ($keys as $key) {
    $data = $cache->get($key);

    echo 'Key=', $key, ' Data=', $data;
}

// 'my-prefix'で始まるキャッシュ内のクエリキー
$keys = $cache->queryKeys('my-prefix');

キャッシュからのデータ削除

(キャッシュされたデータの更新のために) キャッシュ エントリを強制的に無効にする必要があります。 唯一の要件は、データが格納されているキーを知ることです。

<?php

// 対象のキーを持つアイテムを削除する
$cache->delete('someKey');

$keys = $cache->queryKeys();

// キャッシュからすべてのアイテムを削除する
foreach ($keys as $key) {
    $cache->delete($key);
}

キャッシュ有無の確認

指定されたキーでキャッシュがすでに存在するかどうかを確認することができます。

<?php

if ($cache->exists('someKey')) {
    echo $cache->get('someKey');
} else {
    echo 'Cache does not exists!';
}

有効期間

有効期間は、期限が切れるまでキャッシュが存続できる時間(秒)です。 デフォルトでは、作成されたすべてのキャッシュは、フロントエンドの作成時に設定された有効期間を使用します。 キャッシュからのデータの作成または取得では、特定の有効期間を設定できます。

取得時の有効期間の設定:

<?php

$cacheKey = 'my.cache';

// 結果を取得するときにキャッシュを設定
$robots = $cache->get($cacheKey, 3600);

if ($robots === null) {
    $robots = 'some robots';

    // キャッシュに格納
    $cache->save($cacheKey, $robots);
}

保存時の有効期間の設定:

<?php

$cacheKey = 'my.cache';

$robots = $cache->get($cacheKey);

if ($robots === null) {
    $robots = 'some robots';

    // データを保存するときにキャッシュを設定
    $cache->save($cacheKey, $robots, 3600);
}

マルチレベルキャッシュ

キャッシュコンポーネントの機能によって、開発者はマルチレベルキャッシュを実装できます。 この新しい機能は、同じデータを複数のキャッシュに保存することができるため、データの有効期限が切れるまで一番速いアダプタで読み込み、最も遅いもので終了するため、非常に便利です:

<?php

use Phalcon\Cache\Multiple;
use Phalcon\Cache\Backend\Apc as ApcCache;
use Phalcon\Cache\Backend\File as FileCache;
use Phalcon\Cache\Frontend\Data as DataFrontend;
use Phalcon\Cache\Backend\Memcache as MemcacheCache;

$ultraFastFrontend = new DataFrontend(
    [
        'lifetime' => 3600,
    ]
);

$fastFrontend = new DataFrontend(
    [
        'lifetime' => 86400,
    ]
);

$slowFrontend = new DataFrontend(
    [
        'lifetime' => 604800,
    ]
);

// バックエンドは、早いものから遅いものへと順番に登録される
$cache = new Multiple(
    [
        new ApcCache(
            $ultraFastFrontend,
            [
                'prefix' => 'cache',
            ]
        ),
        new MemcacheCache(
            $fastFrontend,
            [
                'prefix' => 'cache',
                'host'   => 'localhost',
                'port'   => '11211',
            ]
        ),
        new FileCache(
            $slowFrontend,
            [
                'prefix'   => 'cache',
                'cacheDir' => '../app/cache/',
            ]
        ),
    ]
);

// すべてのバックエンドに保存
$cache->save('my-key', $data);

フロントエンド アダプター

インターフェイスとして使用される使用可能なフロントエンドアダプタ、またはキャッシュへの入力ソースは次のとおりです:

アダプター 説明
Phalcon\Cache\Frontend\Output 標準のPHP出力から入力データを読み込みます。
Phalcon\Cache\Frontend\Data あらゆる種類のPHPデータ(大きな配列、オブジェクト、テキストなど)をキャッシュするために使用されます。 データは、バックエンドへ保存する前にシリアライズされます。
Phalcon\Cache\Frontend\Base64 バイナリ データのキャッシュに使用します。 データは、バックエンドに格納される前にbase64_encodeを使用してシリアル化されます。
Phalcon\Cache\Frontend\Json データは、バックエンドへ保存する前にJSON形式にエンコードされます。 取得後にデコードします。 このフロントエンドは、他の言語やフレームワークとのデータ共有に便利です。
Phalcon\Cache\Frontend\Igbinary あらゆる種類のPHPデータ(大きな配列、オブジェクト、テキストなど)をキャッシュするために使用されます。 データは、バックエンドに格納される前にIgbinaryを使用してシリアル化されます。
Phalcon\Cache\Frontend\None あらゆる種類のPHPデータをシリアル化せずにキャッシュするために使用されます。

独自フロントエンドアダプターの実装

独自のフロントエンドアダプタを作成するか、既存のフロントエンドアダプタを拡張するには、Phalcon\Cache\FrontendInterfaceインタフェースを実装する必要があります。

バックエンドアダプター

キャッシュデータを格納するために使用できるバックエンドアダプタは次のとおりです:

アダプター 説明 情報 必須エクステンション
Phalcon\Cache\Backend\Apc Alternative PHP Cache (APC) にデータを格納します。 APC APC
Phalcon\Cache\Backend\Apcu データをAPCuに格納します(オペコードキャッシングなしのAPC) APCu APCu
Phalcon\Cache\Backend\File ローカルのプレーンファイルにデータを格納します。
Phalcon\Cache\Backend\Libmemcached memcachedサーバーにデータを格納します。 Memcached Memcached
Phalcon\Cache\Backend\Memcache memcachedサーバーにデータを格納します。 Memcache Memcache
Phalcon\Cache\Backend\Mongo データをMongoデータベースに保存します。 MongoDB Mongo
Phalcon\Cache\Backend\Redis Redisにデータを格納します。 Redis Redis
Phalcon\Cache\Backend\Xcache XCacheにデータを格納します。 XCache XCache

ファクトリー

多くのバックエンドアダプタがあります (バックエンドアダプターを参照)。 使用するものはアプリケーションのニーズに応じて異なります。 次の例では、adapterオプションを使用してBackend Cache Adapterクラスをロードし、フロントエンドが配列として提供される場合はFrontend Cache Factoryが呼ばれます。

<?php

use Phalcon\Cache\Backend\Factory;
use Phalcon\Cache\Frontend\Data;

$options = [
    'prefix'   => 'app-data',
    'frontend' => new Data(),
    'adapter'  => 'apc',
];
$backendCache = Factory::load($options);

独自のバックエンドアダプターを実装

独自のバックエンドアダプタを作成したり既存のバックエンドアダプタを拡張するには、Phalcon\Cache\BackendInterfaceインタフェースを実装する必要があります。

ファイルバックエンドのオプション

このバックエンドは、キャッシュされたコンテンツをローカル サーバー内のファイルに格納されます。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。
cacheDir キャッシュされたファイルが置かれる書き込み可能なディレクトリ。

Libmemcachedバックエンドのオプション

このバックエンドは、memcached サーバー内のキャッシュされたコンテンツを 格納します。 デフォルトでは永続的な memcached 接続プールが使用されます。 このバックエンドの使用可能なオプションは次のとおりです。

一般設定

オプション 説明
statsKey キャッシュされたキーの追跡に使用されます。
prefix キャッシュキーの前に自動的に付加される接頭辞。
persistent_id リクエストの間に存続するインスタンスを作成するには、persistent_idを使用してインスタンスの一意のIDを指定します。

サーバー設定

オプション 説明
host memcachedホスト。
port memcachedポート番号。
weight weightパラメータは、キーを読み書きするサーバを決定するために使用されるコンシステントハッシュ法に影響します。

クライアント設定

Memcached のオプションの設定に使用されます。 詳細については、Memcached::setOptionsを参照してください。

<?php
use Phalcon\Cache\Backend\Libmemcached;
use Phalcon\Cache\Frontend\Data as FrontData;

// データを2日間キャッシュ
$frontCache = new FrontData(
    [
        'lifetime' => 172800,
    ]
);

// memcachedの接続オプションを設定するキャッシュを作成する
$cache = new Libmemcached(
    $frontCache,
    [
        'servers' => [
            [
                'host'   => '127.0.0.1',
                'port'   => 11211,
                'weight' => 1,
            ],
        ],
        'client' => [
            \Memcached::OPT_HASH       => \Memcached::HASH_MD5,
            \Memcached::OPT_PREFIX_KEY => 'prefix.',
        ],
        'persistent_id' => 'my_app_cache',
    ]
);

Memcacheバックエンドのオプション

このバックエンドは、memcached サーバー内のキャッシュされたコンテンツを 格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。
host Memcachedホスト。
port memcachedポート番号。
persistent memcachedへの永続的な接続を作成するかどうか。

APCバックエンドのオプション

このバックエンドは、Alternative PHP Cache (APC) にキャッシュされたコンテンツを格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。

APCUバックエンドのオプション

このバックエンドは、Alternative PHP Cache (APCU) にキャッシュされたコンテンツを格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。

Mongoバックエンドのオプション

このバックエンドは、キャッシュされたコンテンツをMongoDBサーバー (MongoDB) に格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。
server MongoDB接続文字列。
db Mongoデータベース名。
collection データベースのMongoコレクション。

XCacheバックエンドのオプション

このバックエンドは、XCache (XCache) にキャッシュされたコンテンツを格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。

Redisバックエンドのオプション

このバックエンドは、キャッシュされたコンテンツをRedisサーバー (Redis) に格納します。 このバックエンドの使用可能なオプションは次のとおりです。

オプション 説明
prefix キャッシュキーの前に自動的に付加される接頭辞。
host Redisホスト。
port Redisポート。
auth パスワードで保護されたRedisサーバーに認証するためのパスワード。
persistent Redisへの永続的な接続を作成するかどうか。
index 使用するRedisデータベースのインデックス。

Phalcon Incubator には、このコンポーネントを利用するための複数のアダプターが用意されています。