01 Кэш
Улучшение производительности с помощью кэширования
Phalcon предоставляет класс Phalcon\Cache
, дающий быстрый доступ к часто используемым или уже сгенерированным данным. Phalcon\Cache
написан на языке C, поэтому он предоставляет высокую производительность и пониженный расход ресурсов. Этот класс использует два компонента: frontend и backend. Frontend компонент является входным источником или интерфейсом, в то время как backend предоставляет опции хранения данных.
Где применять кэширование?
Хотя этот компонент очень быстрый, его реализация в случаях, которые не нужны, может привести к потере производительности, а не к увеличению. Мы рекомендуем вам проверять эти случаи перед использованием кеша:
- Вы делаете сложные расчеты, которые каждый раз возвращают один и тот же результат (или результат редко изменяется)
- Вы используете много хелперов и результат генерации почти всегда одинаковый
- Вы постоянно обращаетесь к базе данных и редко изменяете эти данные
Поведение системы кэширования
Процесс кэширования разделена в 2 части:
- Frontend: Эта часть отвечает за проверку времени жизни ключа и выполняет дополнительные преобразования над данными, до операции сохранения или извлечения их из backend
- Backend: Эта часть отвечает за коммуникацию, запись/чтение данных по запросу frontend.
Factory
Создание фронтэнд и бэкэнд адаптеров может быть достигнуто двумя способами:
Традиционный путь
<?php use Phalcon\Cache\Backend\File as BackFile; use Phalcon\Cache\Frontend\Data as FrontData; // Создание frontend для выходных данных. Кэширование файлов на 2 дня $frontCache = new FrontData( [ 'lifetime' => 172800, ] ); // Создаем компонент, который будем кэшировать из "Выходных данных" в "Файл" // Устанавливаем папку для кэшируемых файлов - важно указать символ "/" в конце пути $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 и сохраняются в кэш. Следующий пример демонстрирует такое использование. Он получает сгенерированные выходные данные и сохраняет их в файл. Кэш обновляется каждые 172800 секунд (двое суток).
Реализация этого механизма позволяет нам повысить производительность за счет исключения работы помощника Phalcon\Tag::linkTo()
, который вызывается каждый раз в этом участке кода.
<?php use Phalcon\Tag; use Phalcon\Cache\Backend\File as BackFile; use Phalcon\Cache\Frontend\Output as FrontOutput; // Создание frontend для выходных данных. Кэшируем файлы на двое суток $frontCache = new FrontOutput( [ 'lifetime' => 172800, ] ); // Создаем компонент, который будем кэшировать из "Выходных данных" // в файловый бэкэнд. // Устанавливаем папку для кэшируемых файлов - важно указать символ '/' // в конце пути $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 $content; }
Кэширование произвольных данных
Кэширование только данных одинаково важно для вашего приложения. Кэширование позволяет снизить нагрузку на базы данных за счет повторного использования обычно используемых (но не обновленных) данных, что ускоряет ваше приложение.
Пример файлового бэкенда
Существует файловый адаптер кэширования (File
). Единственным параметром для него является место, где будут храниться закэшированные файлы. Это контролируется параметром cacheDir
, который должен содержать завершающий слеш.
<?php use Phalcon\Cache\Backend\File as BackFile; use Phalcon\Cache\Frontend\Data as FrontData; // Кэшируем данные на двое суток $frontCache = new FrontData( [ 'lifetime' => 172800, ] ); // Создаем компонент, который будем кэшировать из "Выходных данных" в "Файл" // Устанавливаем папку для кэшируемых файлов // Важно сохранить символ "/" в конце пути $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'; }
Пример использования бэкэнда Memcache
Для этого нам достаточно немного изменить вышестоящий пример. В частности изменится конфигурация.
<?php use Phalcon\Cache\Frontend\Data as FrontData; use Phalcon\Cache\Backend\Libmemcached as BackMemCached; // Кэшируем данные на 1 час $frontCache = new FrontData( [ 'lifetime' => 3600, ] ); // Создаем компонент, который будет кэшировать данные в Memcache // Настройки подключения к Memcache $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'; }
Запрос данных из кэша
Все элементы добавляемые в кэш идентифицируются по ключам. В случае с файловым бэкэндом, ключом является название файла. Для получения данных из кэша нам необходимо выполнить запрос к кэшу с указанием уникального ключа. Если ключа не существует, метод вернет значение 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 'Данных в кэше не существует!'; }
Время жизни
lifetime
— это время, исчисляемое в секундах, которое означает, сколько будут храниться данные в бэкэнде. По умолчанию все данные получают “время жизни”, которое было указано при создании фронтэнд компонента. Вы можете указать другое значение при сохранении или получении данных из кэша:
Задаем время жизни при получении:
<?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 | It's used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized before stored in the backend. |
Phalcon\Cache\Frontend\Base64 | It's used to cache binary data. The data is serialized using base64_encode before be stored in the backend. |
Phalcon\Cache\Frontend\Json | Data is encoded in JSON before be stored in the backend. Decoded after be retrieved. This frontend is useful to share data with other languages or frameworks. |
Phalcon\Cache\Frontend\Igbinary | It's used to cache any kind of PHP data (big arrays, objects, text, etc). Data is serialized using Igbinary before be stored in the backend. |
Phalcon\Cache\Frontend\None | Используется для кэширования любых типов данных без сериализации. |
Реализация собственных фронтэнд адаптеров
Для создания фронтэнд адаптера необходимо реализовать интерфейс 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 | 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
. Если опция frontend будет представлена в виде массива, фронтэнд адаптер будет инициализирован при помощи соответствующей фабрики.
<?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 , чтобы указать уникальный идентификатор для экземпляра. |
Параметры сервера
Параметр | Описание |
---|---|
host |
Хост memcached сервера. |
port |
Порт memcached сервера. |
weight |
Весовой коэффициент для заданного сервера по отношению к общему весу всех серверов в пуле. |
Параметры клиента
Используется для установки параметров Memcached. Подробнее см. Memcached::setOptions.
Пример
<?php use Phalcon\Cache\Backend\Libmemcached; use Phalcon\Cache\Frontend\Data as FrontData; // Кэшируем данные на двое суток $frontCache = new FrontData( [ 'lifetime' => 172800, ] ); // Инициализация Libmemcached бэкэнда $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 |
Название базы данных. |
collection |
Коллекция в базе данных. |
Параметры XCache бэкэнда
Этот бэкэнд будет хранить кешированный контент на XCache (XCache). Доступными опциями для этого бэкэнд являются:
Параметр | Описание |
---|---|
prefix |
Префикс, который будет автоматически добавляться к ключам кэша. |
Redis Backend Options
Этот бэкэнд будет хранить кешированный контент на сервере Redis (Redis). Доступными опциями для этого бэкэнд являются:
Параметр | Описание |
---|---|
prefix |
Префикс, который будет автоматически добавляться к ключам кэша. |
host |
Хост Redis сервера. |
port |
Порт Redis сервера. |
auth |
Пароль для авторизации на защищенном паролем Redis сервере. |
persistent |
Создавать постоянное соединение к Redis серверу. |
index |
Индекс для использования в базе данных Redis. |
Для этих компонентов доступно больше адаптеров. Phalcon Incubator