Статьи

Ускоренный курс по производительности PHP, часть 2: глубокое погружение

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

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

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

Просто напомним некоторые основные принципы для эффективных приложений PHP:

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

Оптимизируйте свои сессии

В PHP очень легко переместить хранилище сессий в Memcached:

1) Установите расширение Memcached с помощью PECL

pecl install memcached

2) Настройте свою конфигурацию php.ini, чтобы изменить обработчик сеанса

session.save_handler = memcached
session.save_path = "localhost:11211"

Если вы хотите поддерживать пул экземпляров memcache, вы можете разделить их запятой:

session.save_handler = memcached
session.save_path = "10.0.0.10:11211,10.0.0.11:11211,10.0.0.12:11211"


Расширение Memcached имеет множество доступных вариантов конфигурации, см. Полный список на Github . Идеальная конфигурация, которую я нашел, используя пул серверов:

session.save_handler = memcached
session.save_path = "10.0.0.10:11211,10.0.0.11:11211,10.0.0.12:11211" 

memcached.sess_prefix = “session.”
memcached.sess_consistent_hash = On
memcached.sess_remove_failed = 1
memcached.sess_number_of_replicas = 2
memcached.sess_binary = On
memcached.sess_randomize_replica_read = On
memcached.sess_locking = On
memcached.sess_connect_timeout = 200
memcached.serializer = “igbinary”

Это оно! Обратитесь к документации для полного объяснения этих директив конфигурации.

Использование кэширования

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

Использование компонента Symfony2 HttpFoundation для встроенной поддержки http-кэширования

Я не буду пытаться объяснить кеширование http. Просто прочитайте удивительный пост Райана Томако, Things Caches Do или более подробное руководство по кэшированию http от Марка Ноттингема . Оба — звездные посты, которые должен прочитать каждый профессиональный разработчик.

С компонентом Symfony2 HttpFoundation легко добавить поддержку кэширования в ваши ответы http. Компонент полностью автономен и может быть добавлен в любое существующее php-приложение для предоставления объектно-ориентированной абстракции вокруг спецификации http. Цель состоит в том, чтобы помочь вам управлять запросами, ответами и сессиями. Добавьте «symfony / http-foundation» в ваш файл Composer, и вы готовы начать работу.


 use Symfony\Component\HttpFoundation\Response;
$response = new Response(‘Hello World!’, 200, array(‘content-type’ => ‘text/html’));

$response->setCache(array(
‘etag’ => ‘a_unique_id_for_this_resource’,
‘last_modified’ => new \DateTime(),
‘max_age’ => 600,
‘s_maxage’ => 600,
‘private’ => false,
‘public’ => true,
));

Если вы используете запрос и ответ от http-базы, вы можете легко проверить свои условные валидаторы из запроса:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();

$response = new Response(‘Hello World!’, 200, array(‘content-type’ => ‘text/html’));

if ($response->isNotModified($request)) {
$response->send();
}

Найдите больше примеров и полной документации из очень подробной документации Symfony .

Кэширование результатов с помощью Doctrine ORM

Если вы не используете ORM или какую-либо форму абстракции базы данных, вы должны рассмотреть это . Doctrine — наиболее полнофункциональный уровень абстракции базы данных и объектно-реляционный картограф, доступный для PHP. Конечно, добавление абстракций происходит за счет производительности, но я считаю, что Doctrine очень быстро и эффективно при правильном использовании. Если вы используете Doctrine ORM, вы можете легко включить наборы результатов кэширования в Memcached :

$memcache = new Memcache();
$memcache->connect('localhost', 11211);

$memcacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
$memcacheDriver->setMemcache($memcache);

$config = new \Doctrine\ORM\Configuration();
$config->setQueryCacheImpl($memcacheDriver);
$config->setMetadataCacheImpl($memcacheDriver);
$config->setResultCacheImpl($memcacheDriver);

$entityManager = \Doctrine\ORM\EntityManager::create(array(‘driver’ => ‘pdo_sqlite’, ‘path’ => __DIR__ . ‘/db.sqlite’), $config);

$query = $em->createQuery(‘select u from \Entities\User u’);
$query->useResultCache(true, 60);

$users = $query->getResult();

Найдите больше примеров и полную документацию из очень подробной документации Doctrine .

Кэширование ответов веб-сервиса с помощью HTTP-клиента Guzzle

Взаимодействие с веб-сервисами очень распространено в современных веб-приложениях. Guzzle — наиболее полнофункциональный http-клиент, доступный для PHP. Guzzle избавляет от боли при отправке HTTP-запросов и избыточности при создании клиентов веб-служб. Это структура, которая включает в себя инструменты, необходимые для создания надежного клиента веб-службы. Добавьте «жрет / жрет» в ваш файл Composer, и вы готовы начать.

Guzzle не только поддерживает различные методы аутентификации (OAuth 1 + 2, HTTP Basic и т. Д.), Но также поддерживает лучшие практики, такие как повторные попытки с экспоненциальным откатом, а также кэширование http .

$memcache = new Memcache();
$memcache->connect('localhost', 11211);

$memcacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
$memcacheDriver->setMemcache($memcache);

$client = new \Guzzle\Http\Client(‘http://www.test.com/’);

$cachePlugin = new \Guzzle\Plugin\Cache\CachePlugin(array(
‘storage’ => new \Guzzle\Plugin\Cache\DefaultCacheStorage(
new \Guzzle\Cache\DoctrineCacheAdapter($memcacheDriver)
)
));
$client->addSubscriber($cachePlugin);

$response = $client->get(‘http://www.wikipedia.org/’)->send();

// response will come from cache if server sends 304 not-modified
$response = $client->get(‘http://www.wikipedia.org/’)->send();

Следование этим советам позволит вам легко кэшировать все ваши запросы к базе данных, запросы веб-служб и ответы http.

Перемещение работы на задний план с помощью Resque и Redis

Любой процесс, который медленен и не важен для немедленного http-ответа, должен ставиться в очередь и обрабатываться с помощью неблокирующих фоновых задач. Типичными примерами являются отправка социальных уведомлений (таких как Facebook, Twitter, LinkedIn), отправка электронных писем и обработка аналитики. Существует много систем, доступных для управления слоями сообщений или очередями задач, но я считаю Resque for PHP очень простым. Я не буду давать подробное руководство, так как Wan Qi Chen’s уже опубликовал отличную серию постов в блоге о начале работы с Resque. Добавьте «chrisboulton / php-resque» в свой файл Composer, и вы готовы начать работу. Очень простое введение в добавление Resque в ваше приложение:

1) Определить бэкэнд Redis

Resque::setBackend('localhost:6379');

2) Определить фоновое задание

class MyTask
{
public function perform()
{
// Work work work
echo $this->args['name'];
}
}

3) Добавить задачу в очередь

Resque::enqueue('default', 'MyTask', array('name' => 'AppD'));

4) Запустите задачу командной строки, чтобы обработать задачи с пятью рабочими из очереди в фоновом режиме

$ QUEUE=* COUNT=5 bin/resque

Для получения дополнительной информации прочитайте официальную документацию или посмотрите очень полное руководство от Wan Qi Chen:

Мониторинг производительности производства

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

Если вы предпочитаете формат слайдов, эти посты были вдохновлены недавним техническим докладом:

Как всегда, пожалуйста, не стесняйтесь комментировать, если вы думаете, что я что-то пропустил или если у вас есть запрос на контент в следующем сообщении.