В своем первом посте из этой серии я рассмотрел несколько основных советов по оптимизации производительности в приложениях php . В этом посте мы немного углубимся в принципы и практические советы по масштабированию PHP.
Ведущие инженерные организации считают производительность не просто приятной вещью, а важной характеристикой своего продукта. Эти организации понимают, что эффективность напрямую влияет на успех их бизнеса.
В конечном счете, масштабируемость касается всей архитектуры, а не незначительной оптимизации кода. Часто люди ошибаются и наивно думают, что им следует сосредоточиться на крайних случаях. Твердые архитектурные решения, такие как блокирование работы в фоновом режиме с помощью задач, упреждающее кэширование дорогостоящих вызовов и использование обратного прокси-кэша, помогут вам гораздо дальше, чем спорить об одинарных или двойных кавычках.
Просто напомним некоторые основные принципы для эффективных приложений PHP:
- Обновление до PHP 5.5 с Zend OpCache с использованием PHP-PFM + Nginx
- Будьте в курсе ваших фреймворков + зависимостей (используя Composer )
- Оптимизируйте свое хранилище сеансов для использования подписанных файлов cookie или базы данных с кэшированием
- Кэшируйте вашу базу данных и доступ к веб-сервисам с помощью Memcache или Redis.
- Блокируйте работу в фоновом режиме с помощью очередей и задач, используя Resque
- Используйте HTTP-кеширование и обратный прокси-кеш, как Varnish.
- Профилируйте код с помощью Xdebug + Webgrind и следите за производительностью
Первые несколько советов на самом деле не требуют проработки, поэтому я сосредоточусь на том, что имеет значение.
Оптимизируйте свои сессии
В 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:
- Часть 1: Введение
- Часть 2: система очередей
- Часть 3: Установка
- Часть 4: Рабочий
- Часть 5: Класс работы и реализация
- Часть 6: Интеграция Resque в CakePHP с CakeResque
- Часть 7. Запуск и остановка рабочих с помощью Fresque
- Часть 8. Взгляд на php-resque-ex, форк с большим количеством функций
- Часть 9: Resque аналитика с ResqueBoard
Мониторинг производительности производства
Я использую AppDynamics , программное обеспечение для управления производительностью приложений, предназначенное для помощи разработчикам в устранении проблем производительности в сложных производственных приложениях. Карта потоков приложений позволяет легко отслеживать обращения к базам данных, кэшам, очередям и веб-службам с детализацией на уровне кода для решения проблем производительности:
Если вы предпочитаете формат слайдов, эти посты были вдохновлены недавним техническим докладом: