Статьи

Кэширование Хет-трик: Zend Opcache, Etags и Query Caching

В этой статье мы рассмотрим некоторые распространенные методы кэширования в PHP: Opcache, Expires Headers и Query Caching в MySQL. Мы рассмотрим дополнительные подходы во второй части.

Abstract image with cache text

PHP-запрос жизненного цикла

Прежде чем мы продолжим, важно понять жизненный цикл запросов PHP. Что происходит за кулисами, когда вы получаете доступ к файлу PHP из браузера?

  1. Файл извлекается из файловой системы — не имеет значения, изменился ли он с момента последнего запроса.
  2. Лексический анализ — читаемый человеком код преобразуется во что-то (токены), которое может понять синтаксический анализатор.
  3. Разбор — машиночитаемые строки анализируются на предмет возможных ошибок. Это похоже на проверку грамматики.
  4. Создание кода операции — токены, которые мы получили на шаге 2, преобразуются в исполняемый код компьютера.
  5. Выполнение машинного кода — машинный код обрабатывается и затем выполняется.

Чтобы получить более подробное объяснение, ознакомьтесь с этой статьей о том, как PHP поддерживает Hello World .

Все эти шаги выполняются очень быстро, но на каждый запрос тратится много времени и ресурсов. Это связано с тем, что для каждого запроса каждого PHP-файла на сервере сервер должен пройти через все из них.

Методы кэширования, которые мы рассмотрим в этих двух статьях, помогают обойти шаги 2, 3 и 4. Это означает, что меньше времени и меньше ресурсов тратится, что приводит к более быстрому времени загрузки страницы для пользователя.

Zend Opcache

Первый инструмент кеширования, который мы рассмотрим, это Zend Opcache.

Он поставляется с предустановленным PHP 5.5 и новее. Если запуск php --version из вашего терминала даст вам что-то вроде следующего, все готово:

 Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies 

Кроме того, вы можете создать новый файл PHP, вызвать phpinfo() , а затем получить доступ к файлу из браузера. Ищите «Zend Opcache». Это должно дать вам что-то похожее на следующее:

zend opcache

активация

Убедившись, что Zend Opcache установлен, вы можете включить его, открыв файл php.ini , затем выполнив поиск термина «opcache», раскомментировав opcache.enable=0 и установив для него значение 1 :

 [opcache] ; Determines if Zend OPCache is enabled opcache.enable=1 

Не забудьте перезапустить PHP, чтобы активировать изменения.

Если вы используете версию PHP ниже 5.5, вы все равно можете воспользоваться Zend Opcache, установив его через PECL. Вы можете сделать это, выполнив следующую команду:

 pecl install zendopcache-beta 

конфигурация

Вы можете настроить Zend Opcache, отредактировав файл opcache.ini в /etc/php5/mods-available/ в дистрибутивах на основе Debian. По умолчанию файл конфигурации содержит следующее:

 ; configuration for php ZendOpcache module ; priority=05 zend_extension=opcache.so 

Вот наиболее важные параметры конфигурации, которые вы можете настроить по своему вкусу:

  • opcache.memory_consump — размер используемой памяти совместно используемой памяти. Это выражается в мегабайтах и ​​по умолчанию равно 64. Вы можете подняться выше, в зависимости от того, насколько мощны ваши серверные пакеты и сколько памяти, по вашему мнению, потребуется вашему приложению.

  • opcache.interned_strings_buffer — объем памяти, используемой для хранения интернированных строк, также в мегабайтах. Интернированная строка — это подход, в котором только одна копия каждой уникальной строки хранится в памяти.

  • opcache.max_accelerated_files — максимальное количество файлов, которое может быть ускорено с помощью opcache. Разрешены только цифры от 200 до 100000.

  • opcache.revalidate_freq — количество секунд, по истечении которых проверяются файлы PHP на наличие изменений. Задание значения 1 означает проверку изменений один раз в секунду, но только один раз за запрос. 0 означает, что он всегда будет проверять наличие изменений. Это оптимальный параметр для сред разработки.

  • opcache.max_file_size — позволяет исключать большие файлы из кэшируемых. По умолчанию он имеет значение 0 что означает, что все файлы кэшируются. Значение для этой опции выражается в байтах.

  • opcache.fast_shutdown — при включении деконструкторы получают повышение скорости в конце каждого запроса. Это означает, что последующий запрос становится быстрее. По умолчанию установлено 0 . Установка в 1 включит его.

Дополнительные параметры конфигурации доступны здесь: OPCache Runtime Configuration .

Чтобы проверить, работает ли opcache правильно, вы можете установить opcache-gui , выполнив следующую команду из терминала

 composer require amnuts/opcache-gui 

После установки вы можете скопировать файл index.php из каталога vendor/amnuts/opcache-gui в корневой каталог нужного проекта и получить к нему доступ через браузер. Затем он покажет вам что-то похожее на следующее:

Он покажет вам использование памяти, частоту обращений и параметры конфигурации, которые вы установили. Вы также можете сбросить кэш или сделать файлы недействительными вручную.

Истекает Заголовки

Мы также можем использовать Apache для кэширования (инструкции для Nginx в конце этого раздела). С помощью Apache мы можем в основном кэшировать статические файлы, такие как таблицы стилей, файлы сценариев, изображения и другие медиа-файлы.

По умолчанию Apache использует etags. Это хэши файла, которые отправляются в заголовке ответа. Браузер не делает запрос на этот файл снова, если etag совпадает, и использует вместо этого кэшированную версию, пока значение по умолчанию для заголовка expires не станет больше или равно времени на компьютере клиента. Но когда вы вносите изменения в файл, etag изменяется, и браузер должен будет снова запросить файл у Apache. Это все хорошо, но мы можем пойти дальше, указав срок годности. Таким образом, браузер может дольше сохранять кешированную версию файла.

Указание заголовка expires через Apache заставляет браузеры кэшировать статические ресурсы в течение определенного периода времени.

Чтобы включить использование этой функции, вы должны сначала включить модуль expires . Вы можете сделать это, выполнив следующие команды из терминала:

 sudo a2enmod expires sudo service apache2 restart 

Первая строка включает модуль expires, а вторая строка перезапускает Apache, чтобы изменения вступили в силу.

Как только это будет сделано, вы можете использовать заголовки expires из файла конфигурации вашего виртуального сервера, обычно находящегося в etc/apache/sites-available или что-то подобное — проверьте документацию по установке.

Откройте файл конфигурации сервера и найдите директиву Directory чтобы найти каталог, соответствующий проекту, для которого вы устанавливаете etags. Там вы можете начать использовать модуль expires:

 <IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 1 day" ExpiresByType image/png "access plus 10 days" ExpiresByType text/css "access plus 25 days" </IfModule> 

Первая и последняя строка — это оболочка, в которой мы проверяем, включен ли модуль mod_expires . Во второй строке мы указываем, что мы хотим начать использовать модуль. С третьей по пятую строчку мы устанавливаем правила. Вот описание того, что делает каждый параметр:

  • ExpiresDefault — позволяет указать правило истечения по умолчанию для всех статических файлов. Это принимает максимальный период времени, в течение которого вы хотите, чтобы браузер удерживал файл.

  • ExpiresByType — позволяет указать время истечения в зависимости от типа файла. Это принимает тип MIME в качестве первого аргумента и время истечения в качестве второго.

Теперь вы можете проверить с помощью вкладки «Сеть» в Chrome Developer Tools, что она действительно изменила значение для заголовка Expires на основе заданного вами параметра. Снимок экрана ниже — это таблица стилей. Страница просматривается 1 февраля 2015 года, поэтому мы просто добавляем к ней 25 дней и получаем дату окончания срока действия:

expires header

Чтобы настроить заголовки срока действия для Nginx, см. Этот отличный пост .

MySQL Query Caching

Для веб-приложений, которые в основном считывают данные из базы данных, вы можете воспользоваться кэшированием запросов. Это помещает проанализированную версию запроса SQL и соответствующий ему набор результатов в кэш, который, в свою очередь, делает последующие запросы страниц, использующие тот же набор запросов, быстрее получает результаты. Это связано с тем, что вашему приложению больше не нужно идти в базу данных для анализа запроса и получения результатов.

Для версий MySQL ниже 5.6.8 кэширование запросов включено по умолчанию. Вы можете проверить, какую версию вы установили, выполнив следующую команду из вашего терминала:

 mysql --version mysql Ver 14.14 Distrib 5.5.41, for debian-linux-gnu (x86_64) using readline 6.3 

Настройка Query Cache

В этом случае версия 5.5.41, поэтому я знаю, что кэширование запросов включено. Если у вас версия 5.6.8 и выше, вам нужно включить ее. Вы можете сделать это, отредактировав файл конфигурации. В Ubuntu это находится в /etc/mysql/my.cnf .

Открыв файл, попробуйте найти строку # * Query Cache Configuration . Если он существует, поместите свою конфигурацию под ним. Если нет, то перейдите в конец файла и добавьте его:

 # * Query Cache Configuration query_cache_type = ON query_cache_min_res_unit = 4096 query_cache_limit = 1M query_cache_size = 16M query_cache_wlock_invalidate = OFF 

Обратите внимание, что значения в приведенном выше примере являются конфигурацией по умолчанию в MySQL версии 5.5, поэтому вам придется изменять их в зависимости от ваших потребностей и мощности вашего сервера. Общее правило для настройки конфигурации — не использовать действительно высокие значения, если ваша база данных часто обновляется, так как потребуется больше времени, чтобы сделать недействительными элементы в кэше после их обновления. Чтобы дать вам представление о том, сколько вы можете установить для каждого элемента, вот краткое описание каждого. Обратите внимание, что когда используется целочисленное значение без добавления единицы, такой как M (для MB), тогда оно выражается в байтах:

  • query_cache_type — позволяет указать, следует ли включать кэширование запросов или нет. Вы можете установить значение ON или OFF .
  • query_cache_limit — максимальный размер результирующего набора, который можно кэшировать для каждого запроса. Обратите внимание, что если у определенного запроса набор результатов превышает значение, указанное в этом параметре, он вообще не будет включен в кэш запросов.
  • query_cache_min_res_unit — минимальный объем памяти, который может быть выделен для хранения запроса.
  • query_cache_size — общий размер кеша запросов.
  • query_cache_wlock_invalidate — позволяет указать, следует ли делать недействительным кеш запроса, когда конкретная таблица заблокирована для записи. Вы можете установить значение ON или OFF .

Закончив настройку конфигурации кэша запросов, вы можете проверить, действительно ли он работает, выполнив следующий запрос:

 show variables like 'query%'; 

Это тогда возвратит результаты, подобные следующему:

is query caching enabled?

Обратите внимание, что результаты, возвращаемые для всех целочисленных значений, выражаются в байтах.

Тестирование кеша запросов

Выполните запрос SELECT в одной из баз данных, которые у вас есть на компьютере, на котором вы работаете.

Далее выполните следующий запрос:

 SHOW STATUS LIKE "qcache%"; 

Это показывает вам что-то похожее на следующее:

query cache stats

Запишите полученные значения и затем выполните тот же запрос SELECT который вы выполняли ранее. Если вы используете phpmyadmin, вы можете просто нажать на ссылку обновления под окном запроса.

Вы также можете сделать то же самое для запроса SHOW STATUS . Теперь он должен был Qcache_free_memory значения для Qcache_free_memory , Qcache_hits , Qcache_inserts , Qcache_not_cached , Qcache_queries_in_cache и Qcache_total_blocks . Если эти значения увеличились, то кеширование запросов работает.

Query Cache Gotchas

Вот некоторые вещи, которые следует помнить при использовании кэша запросов:

  • Работает только с запросами SELECT . SHOW запросы не кэшируются, поскольку они обычно используются для получения значений конфигурации или общей информации о самом сервере.

  • Запросы должны быть точно такими же, чтобы кеш работал. Это означает, что если вы обновите хотя бы один символ одного и того же запроса, он будет считаться другим запросом, что означает, что он не попадет в кэш.

  • Только детерминированные запросы могут воспользоваться кешем. Это означает, что такие функции, как RAND() или CONNECTION_ID() или любая другая функция, которая изменяет результаты при каждом последующем выполнении одного и того же запроса, не могут использовать кэш запроса.

  • Обновления таблицы, такие как вставка новых строк, обновление схемы таблицы или обновление строки, автоматически делают недействительным кэш запроса.

Вывод

В этой части мы рассмотрели некоторые распространенные методы кэширования, которые можно использовать с PHP и MySQL. Далее мы рассмотрим некоторые другие программы, которые могут еще больше ускорить наши приложения — Varnish, Memcached и некоторые библиотеки PHP-кэширования. Будьте на связи!