Оптимизация клиентской стороны на php. Ускорение PHP-программ. Не лечи руку, если хромой на ногу

  • Как оптимизировать сайт и ускорить его работу?
  • С какой скоростью будет и может работать сайт, в соответствии с теми технологиями на которых он будет запущен?
  • Какие технологии следует использовать настраивая сервер или VPS?

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

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

И если говорить о серверах для PHP, то такой проблемой является способ исполнения php кода, ровно как и другие значимые настройки окружения на сервере.
Не зависимо от того, есть ли проблема в вашем коде или её нет, высокая у вас посещаемость или нет, от настроек сервера зависит очень многое. Что бы все сказанное не звучало пустыми словами и была написана эта статья.

В этом обзоре я протестирую только что установленный сайт на одном из самых распространённых движков управления контентом Drupal 7.33 .

Для теста выбрана лишь одна составляющая php-хостинга. Мы будем тестировать web-серверы Nginx и Apache2 , модули mod_php и php-fpm , версии php php53 и php56 , посмотрим, как влияют оптимизаторы apc и opcache на скорость работы сайта.


Конечно, эти параметры лишь часть настроек от которых зависит скорость сайта. Но мы умышлено
ограничиваемся этим, что бы не делать обзор бесконечным.

Дано:
  • Операционная система Centos 6.7
  • Сервер баз данных: MariaDB 10.21
  • Все сессии сайтов хранятся в memcache, чтобы убрать влияние скорости установки сессии на скорость работы сайта.
  • На всех тестах в качестве frontend выступает web-server nginx 1.93. В случае с Apache2, Nginx выступает в качестве балансировщика, а также для отдачи статики. В конфигурациях без использования Apache2 - непосредственным web-сервером является Nginx
  • Конфигурация Nginx и MariaDB содержат множество оптимизаций, направленных на достижение максимальной производительности, но для всех участников теста эти настройки одинаковые и поэтому их влиянием следует пренебречь
  • Параметры opcache и apc взяты из рекомендаций Bitrix, так как они оптимальны и универсальны для большинства сайтов
Как будем тестировать?

В локальной сети есть сервер zabbix и его задачи каждую минуту:

  • Открывать главную страницу испытуемого сайта, дожидаться определенного содержимого на странице, убеждаться, что ответ от сервера - код 200.
  • Следующим шагом идет авторизация в админку сайта, это происходит отправкой соответсвующего POST запроса. Сверка текста и кода ответа на странице с заложенным эталоном. Этот шаг касается почти всех подсистем web-сервера, и во многом его скорость зависит от скорости взаимодействия с базой данных
  • Последним шагом является выход из админки сайта, сверка кода ответа и текста на странице выхода
  • По итогам каждого шага, zabbix будет скрупулезно замерять и записывать скорость рендеринга php-кода в html понятный браузеру и демонстрировать нам графики полученных результатов
  • Для каждого испытуемого будут записываться значения в течение одного часа и в качестве результата будет выступать средние значения за этот час
  • Тестирование будет происходить внутри локальной сети, так что влияние на результат скорости интернет-соединения исключено
  • Для удобства восприятия, все результаты показываю в порядке возрастания. Т.е. самый первый результат - это самый медленный. Все конфигурации были вынесены под условный номер, это позволит лучше ориентироваться в результатах
  • Верхние графики - скорость генерации кода, чем выше значение, тем лучше. Нижние графики - время ответа сервера и чем ниже значение, тем лучше
  • Тестируемые сайты живут своей жизнью, в них происходят регулярные операции с базами данных и выполняются задания по расписанию, именно поэтому кривая на графиках может иметь взлеты и падения

Тестирование:

1. Nginx + php-fpm56 без оптимизатора opcache

По архитектуре - это один из самых передовых вариантов. По производительности - наибольшее разочарование.

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

2. Apache2 + mod_php53 без оптимизатора apc

Cамый типичный для хостингов вариант. 90% популярных хостинг-провайдеров используют этот вариант. Хоть php53 давно не поддерживается разработчиками, но в интернете очень много сайтов, до сих пор работающих на этой версии.

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

3. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php56 без оптимизатора opcache

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

К сожалению, далеко не все сайты могут работать полноценно c этой версией. Почти каждая новая версия PHP перестает поддерживать некоторые устаревшие и «небезопасные» функции, нарушая работу «старого» кода.
Сам по себе php56 без оптимизатора довольно медленный, а mod_php склонен падать и занимать всю память на сервере под нагрузкой.

4. Nginx + php-fpm53 без оптимизатора apc

Достаточно передовая конфигурация, для тех кто не желает иметь проблемы из-за ошибок с оптимизатором кода. При этом используется «совместимая» версия интерпретатора PHP, а также из связки убирается ресурсоемкий Apache2.

5. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php53 + apc

Еще одна распространенная вариация. Очень многие хостинги применяют именно её, при этом либо используют по умолчанию, либо дают возможность включать оптимизатор в своих панелях управления.
Обычно Apache2 оставляют для работы.htaccess-правил, таких как преобразование ссылок и ЧПУ.

Получаем прирост скорости в 3,5 раза, по сравнению с вариантом без использования оптимизатора.
Сам по себе Apache (при использовании его собственного модуля mod_php) расходует для свой работы гораздо больше ресурсов, чем вариант с php-fpm. Apache2 склонен падать, если в одном из его модулей случается сбой или заполнять собой всю оперативную память сервера.

6. Nginx + php-fpm53 + apc

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

Именно такой вариант я использую, когда необходимо поднять устаревший сайт, добиться от него удовлетворительной скорости и надежной работы при высоких нагрузках.

7. Балансировка и статика через Nginx, динамическая часть Apache2 + php-fpm53 + apc

Вариант для устаревших сайтов со сложными.htaccess. Например - старые инсталляции Bitrix.

Это идеальный вариант для устаревших сайтов. Данная конфигурация устойчива к высоким нагрузкам, совместима и достаточно производительна.
Отлично подходит, когда нужны правила.htaccess и дополнительные модули Apache2.
Из недостатков - устаревшая и не обновляемая версия php, но если нет выбора - это самый лучший вариант. Отлично подходит для старой версий Bitrix, Joomla и других распространенных CMS не самых свежих версий.

8. Балансировка и статика через Nginx, динамическая часть Apache2 + mod_php56 + opcache

Достаточно производительная, но ресурсоёмкая конфигурация со всеми недостатками mod_php.

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

9. Nginx + php-fpm56 + opcache

Самый производительный вариант.

Это самый лучший вариант для всех современных сайтов. Хорошо держит нагрузку, показывает самый лучший результат с точки зрения производительности. Именно такой вариант я использую, когда стоит задача оптимизировать производительность сайта и увеличить скорость его работы.
Единственный недостаток - это то, что мы не сможем использовать.htaccess и все правила mod_rewrite нужно переписать на синтаксис Nginx.
Также не будут работать модули Apache2. Если таковые используются, то этот вариант не подойдёт.

10. Балансировка и статика через Nginx, динамическая часть Apache2 + php-fpm56+ opcache

Самый лучший вариант для сайтов, где нужен.htaccess. Идеально подходит для свежих версий Bitrix.

Хорошо держит нагрузку за счет php-fpm. Активно использую этот вариант для большинства сайтов.

Главная страница тестового сайта
Номер конфигурации Архитектура Средний отклик мс.
1 77,04 103,6
2 78,79 103,98
3 78,85 102,38
4 81,55 97,88
5 Apache2 + mod_php53 + apc 303,37 29,36
6. Nginx + php-fpm53 + apc 312,33 24,73
7. Apache2 + php-fpm53 + apc 339,63 23,32
8. 484,96 16,91
9. Nginx + php-fpm56 + opcache 546,34 14,08
10. Apache2 + php-fpm56+ opcache 571,14 13,78
Авторизация в админке тестового сайта
Номер конфигурации Архитектура Средняя скорость загрузки кб. Средний отклик мс.
1 Nginx + php-fpm56 без оптимизатора opcache 67,51 239,01
2 Apache2 + mod_php53 без оптимизатора apc 64,61 257,51
3 Apache2 + mod_php56 без оптимизатора opcache 66,75 242,42
4 Nginx + php-fpm53 без оптимизатора apc 68.79 233.15
5 Apache2 + mod_php53 + apc 173,81 94,26
6. Nginx + php-fpm53 + apc 173,3 91,3
7. Apache2 + php-fpm53 + apc 182,1 90,5
8. Apache2 + mod_php56 + opcache 218,35 77,55
9. Nginx + php-fpm56 + opcache 252,83 62,25
10. Apache2 + php-fpm56+ opcache 262,8 60,85
Выход из админки тестового сайта
Номер конфигурации Архитектура Средняя скорость загрузки кб. Средний отклик мс.
1 Nginx + php-fpm56 без оптимизатора opcache 41,01 184,49
2 Apache2 + mod_php53 без оптимизатора apc 42,42 188,97
3 Apache2 + mod_php56 без оптимизатора opcache 42,06 188,37
4 Nginx + php-fpm53 без оптимизатора apc 45,48 169,15
5 Apache2 + mod_php53 + apc 190,1 41,87
6. Nginx + php-fpm53 + apc 185,92 41,24
7. Apache2 + php-fpm53 + apc 202,78 39,21
8. Apache2 + mod_php56 + opcache 315,56 26,23
9. Nginx + php-fpm56 + opcache 373,19 20,43
10. Apache2 + php-fpm56+ opcache 381,21 20,57

В качестве итогов:

  • В реальной жизни, все варианты с Apache2 могут быть медленней, так как в своих тестах я умышленно передал отдачу статики Nginx. Это сделано, чтобы исключить влияние скорости отдачи статики на результаты замера скорости работы интерпретатора PHP. Одной из наиболее слабой стороной Apache2 и при этом сильной Nginx - является скорость отдачи статики. Особенно, это заметно на высоких нагрузках. Кроме того, Nginx менее подвержен атаке «медленных соединений»
  • mod_php очень быстро занимает всю доступную память сервера и теряет производительность на нагрузках
  • php-fpm расходует память значительно эффективнее, безопаснее и гибче в настройках. В ряде случаев он быстрее и без высоких нагрузок.
  • Тест имеет узкую специфику, тут мы увидели особенности работы движка Drupal, другие могут вести себя иначе, но общая тенденция будет такой же.

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

Если у вас возникнут вопросы, трудности или потребуется совет:
Мои контакты в

Производительность решений на PHP — частая тема различных споров и дискуссий. Мы не будем сейчас участвовать в них. Ведь как бы там ни было, все всегда зависит от конкретной задачи. К примеру, мне известен достоверный случай, когда некий программный код в течение полутора года переписывали на Ассемблере. Изначально он был написан на Си. Когда работы завершились, позади остались сотни рабочих дней большой группы разработчиков, а на руках — версия ПО, полностью написанная на Ассемблере. Какое же было удивление команды, когда в итоге их творение на Ассемблере заработало гораздо медленней их же, более раннего творения на Си!

Оптимизация программного кода — задача многогранная. Следует учитывать множество факторов. Следует понимать, что в ряде случаев ею вообще можно пренебречь: в конце концов, часто проще докупить высокопроизводительного «железа», чем оплачивать дополнительную работу команды высококлассных разработчиков. Автоматизация, индустриализация, други мои! Роботы заменяют людей. А ведь когда-то были такие профессии, как, например, профессия фонарщика или лифтера, нет, не того, который сейчас чинит и обслуживает лифты. Того, который раньше был штурманом лифта и возил пассажиров куда они просили. Сейчас это уже кажется смешным. А лет через энное количество смех будут вызывать пилоты самолетов. Те будут летать на полностью автоматизированных системах управления И т.д.

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

Рассмотрим на примере PHP. На самом деле, что бы там не говорили о нем, PHP ничуть не хуже Perl или ASP.NET, я бы сказал даже наоборот — у PHP значительно больше преимуществ. Почему же ему чаще всех достается? Очень просто — потому, что он самый популярный! Ведь и Windows ругают все, под нее больше всего вирусов, в ней больше всего найденных «дыр». Но стоит на ее популярность… Хм более 98% пользователей работают именно под ОС Windows. На все остальные вместе взятые операционные системы приходится не более 2% пользователей. Не удивительно, что к Windows такое внимание. Я уверен, что если любая другая ОС была бы настолько же популярна (и настолько же сложна, функциональна и доступна), в ней было бы найдено не меньше дыр. Ну да ладно, это разговор для отдельной темы.

Возвращаясь к PHP, кроме всего прочего, это, пожалуй, наиболее простой язык программирования, широко применяемый для веба. Его простота и доступность обусловливают возникшую армию новичков, которые хоть что-то в нем пытаются делать. Их некомпетентность часто становится причиной негативных дискуссий о PHP. Тот же ASP.NET не столь доступен. Как следствие — основные его «носители» — достаточно грамотные люди. Со всеми вытекающими последствиями. Но ведь доступность PHP никоим образом не нивелирует его достоинств в руках профессионалов.

В конце концов, на чем написана самая популярная социальная сеть, и второй по посещаемости веб-ресурс в мире, facebook? А его аналог vkontakte? Конечно же, на PHP!

Следует понимать область применения. Если вам нужно проводить серьезные вычисления, особенно связанные с мультимедиа, с большими данными и высокими нагрузками, например, обработкой видео онлайн, конечно же, лучше написать соответствующий код на том же Си и уже использовать его под PHP как откомпилированный модуль. PHP — это скорее некий универсальный шаблонизатор, чем язык программирования, каким мы его понимаем. У PHP задачи совсем иные.

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

7 принципов, или 7 позиций оптимизации кода PHP.

1) Любовь к готовым библиотекам.

Различные готовые библиотеки — вещи, безусловно, полезные и удобные. Но следует не забывать, что бесплатный сыр бывает только в мышеловке. За все, так или иначе, а платить приходится.

Разработка программного обеспечения для реализации задумки некоего сайта всегда (при условии соотносимых уровней исполнителей, конечно же) в плане производительности будет значительно более выгодна, чем применение готовой, универсальной CMS (Content Management System — система управления содержимым, «движок» сайта). Низкая производительность — расплата за универсальность CMS. Это то — же самое, что ездить на базар на личном автобусе, или даже, на самолете, но не на своем легковом автомобиле. То же самое и с готовыми библиотеками.

Но почему я поставил библиотеки на первое место? Потому, что если они применяются, то сразу съедают львиную долю производительности. Смотрите сами: подключение одних только Smarty и DbSimple сразу же «съедает» порядка 0.025 сек. времени и почти 3/4 Мб ОЗУ. И это на неплохом сервере при низкой общей нагрузке. Добавить сюда еще какой-нибудь phpMailer , и мы имеем 0.03 сек. затраченного времени и 1 Мб сожранной памяти попросту на пустом месте. Мы еще ничего не делали, лишь подключили модули, это еще даже без их инициализации! У меня есть один самописный проект, наподобие социальной сети, так в нем на полное создание странички в среднем уходит ощутимо меньше ресурсов. Другой пример — движок новостного сайта, который я разрабатывал: публикации, комментарии и т.д. По большому счету, ничего сверхсложного, но и скорость достойная — в среднем меньше 0.001 сек. на генерацию странички и до 0.15 Мб памяти. Проекты построены на связке PHP + MySQL. Кстати, таким образом, второй из них, спокойно держит более 400тыс. хитов в сутки, со всплесками до 1600 хитов за минуту в пиках и почти 500 хостами онлайн. На VPS за $30/мес. А подключи к нему те три библиотеки, тогда уже не обойтись без выделенного сервера, и не самой слабой конфигурации. А ведь дело нередко доходит до применения с десятка готовых библиотек.

С другой стороны, безусловно, если вы разрабатываете небольшой сайт — для фирмы, или личную страничку, заботиться об оптимизации, и, таким образом, отказываться от применения готовых библиотек тут смысла нет. Время дороже. Если посещаемость вашего сайта не более 1000 посетителей в сутки, не стоит тратить время на идеальный и быстрый код. Пользуйтесь готовыми библиотеками. Вам хватит ресурсов любого хорошего виртуального хостинга. Если у вас посещаемость достигает 2-3 тыс. посетителей в сутки, уже есть смысл задуматься об оптимизации кода. Но все же следует хорошо подумать над тем, стоит ли вам на данном этапе отказываться от готовых библиотек и убивать время на переработку кода (либо же время и деньги на программиста, который это сделает). Зачастую проще просто купить дополнительных ресурсов, или перейти на VPS, оплачивая по $10-50 в месяц.

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

Подводя итоги, еще раз подчеркну — вы можете спокойно применять библиотеки, наращивая мощность серверов, но не следует забывать, что это первая причина медленной работы ваших скриптов, и кроме высокой нагрузки на «железо», они являются причиной многих задержек загрузки страничек сайта.

2) Игнорирование Zend Optimizer, eAccelerator

Эти замечательные модули главным образом занимаются оптимизацией и динамическим кэшированием откомпилированного PHP кода (байт — кода ). Часто позволяют поднять производительность чуть ли не в десятки раз. Их применение имеет смысл в первую очередь на достаточно больших и высокопосещаемых проектах, хоть вы можете оптимизировать и любые другие сайты на PHP — это не потребует от вас по сути никаких дополнительных манипуляций. О применении данных модулей мы еще поговорим, в следующий раз, это достаточно объемная тема. Пока что вам достаточно запомнить этот пункт.

3) «Кривое» применение баз данных

По сути это отдельная тема. Вам следует помнить, что каждое подключение к БД, каждый запрос, каждая лишняя таблица в запросе и т.д. — все это создает ощутимую нагрузку. Но все же, логика самой БД, а не интерфейса работы с ней, несет наибольшую нагрузку. Мне недавно приходилось оптимизировать один очень популярный модуль для одного из самых популярных «движков» форума. Как мне сразу удалось выяснить — тот самый модуль и был главной причиной существенных тормозов. Добавив одну небольшую таблицу и два новых SQL запроса в PHP код, производительность форума была повышена на 60-80% (в зависимости от странички), потребление памяти снизилось на 5-7%! И это все практически на ровном месте. Как видите — это тот случай, когда добавление «лишней» таблицы и «лишних» запросов существенно увеличивает производительность. Я пошел не экстенсивным, а интенсивным путем, улучшив логику. И получив поистине замечательный результат.

На тему оптимизации БД мы поговорим в ближайшем будущем. Сейчас затрону лишь аспект, связанный с интерфейсом работы, как на PHP, так, впрочем, и на любом другом языке программирования.

Итак, прежде всего, всегда используйте файлы вместо БД, если в этом есть смысл. Когда в этом есть смыл? Предположим, вы пишите движок сайта новостей. Новость добавляется туда раз и навсегда. Она не подвержена последующим изменениям, она большая и цельная. Намного проще и эффективней поместить ее в отдельный файл, а не в БД. А вот рецензию к новости — уже лучше в БД. Ведь на определенных страничках вам явно придется выводить список последних рецензий по теме, или список случайных рецензий. Если писать каждую рецензию в отдельный файл — то при выводе, скажем, 50 рецензий на страничке, нам придется подключать к работе столько же соответствующих файлов рецензий. Писать все рецензии в один и тот же файл тоже не очень хорошо: при их большом количестве файл будет очень большим, и только разрастаться со временем, производительность же, соответственно — снижаться. Да и это попросту может быть достаточно неудобным и небезопасным делом — работа с такими файлами. Другое дело «закидать» наши небольшие рецензии в БД и «выдернуть» нужные одним несложным запросом. То же самое относится к любым часто редактируемым данным. Например, писать счетчик просмотров новостей на файлах — большая глупость. Только БД.

Что касается соединения с БД, его стоит закрывать как только в нем отпадает потребность. Однако, не стоит этого делать, если в работе данного скрипта оно еще пригодится.

Следите за содержимым переменных, которым присваиваются результаты выполнения запросов. Есть смысл использовать unset в ситуациях, когда серьезные объемы данных более не нужны.

4) Отсутствие кэширования

В целом ряде случаев кэширование просто незаменимо. Рассмотрим простой пример. Чуть выше, когда речь шла о БД, я приводил пример со списком рецензий. Предположим, мы заходим на некую страничку, где отображается список из 50 рецензий к последним новостям. Как правило, всех их можно выбрать из БД одним несложным запросом. Но с другой стороны, мы можем заранее создать некий файл, который будет содержать все эти 50 рецензий в готовом виде. Нам не нужно будет выбирать их из БД, форматировать согласно нашему шаблону и вставлять в нужное место в страничке. Мы просто сразу подключаем все это из заранее сформированного файла.

Суть кэширования сводится к созданию кэша из наиболее часто используемых и наиболее редко изменяемых данных. К примеру, как часто вам придется обновлять кэш ваших 50 рецензий? Ясно, что каждый раз, когда будут добавляться новые новости — чтоб наш кэш отображал актуальную информацию. А как часто будут добавляться новые новости? Предположим, примерно каждые 15 минут, т.е. до 100 раз за сутки. А какая посещаемость у этого сайта, как часто просматривают эти рецензии? На проекте, «движок» которого я разрабатывал, порядка 70 тыс. раз за сутки. Таким образом, вместо того, чтобы выполнять выборку из базы, форматирование и вставку этих рецензий по 70 тыс. раз на сутки, она выполняется обычно не более 100 раз, остальное — лишь простые инклуды полностью готовых данных.

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

Не забывайте о том, что кэш не обязательно хранить только в файлах и в нем не обязательно можно хранить только части нашей будущей HTML — странички. А особенно если он подвержен частым, систематическим обновлениям. Например, список данных о пользователях, находящихся онлайн, гораздо разумней держать в БД, в таблице типа Memory.

5) Буфер, сжатие, фронтенд http-сервер

Все очень просто. В процессе выполнения все данные, которые выводятся пользователю, тут же ему и отправляются. Грубо говоря, пока данные не будут забраны, продолжение выполнения кода не выполняется. Так что если в процессе работы ваш скрипт отправляет готовый HTML — код через функцию echo, например, или любым другим методом, то крипт передает данные «по кусочкам», каждый раз «подвисая». Намного грамотней выводить данные в буфер, примерно так:

php//инициализируем буферизацию
ob_start (); //выполнение кода скрипта
//... //завершаем буферизацию, извлекаем данные
$html = ob_get_contents ();
ob_end_clean ();
exit ( $html ); ?>

Включение динамического сжатия готовых HTML — страниц (

ob_start(`ob_gzhandler`);

) может сжать их в среднем на 20-60%, увеличивая скорость загрузки и снижая количество «висящих» процессов. У вас ограничение по трафику на хостинге? Тогда динамическое сжатие страниц принесет двойную выгоду.

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

В завершение, фронтенд http-сервер может вывести производительность ваших PHP скриптов на новый уровень. Дело в том, что даже с кэшированием, процессы, связанные с запросом пользователя, будут «висеть» до того, пока пользователь не примет все данные (либо пока не выйдет лимит отведенного на это времени). Суть фронтенд сервера в том, чтобы сразу же принимать данные, позволяя сразу выгружать отработавшие процессы. Он является неким связующим звеном между пользователем и достаточно «тяжелым» бэкенд сервером — где выполняются ваши PHP скрипты. Но благодаря своей «легкости», фронтенд сервер существенно снижает потребляемые ресурсы. Опять-таки, это очень обширная тема и мы будем рассматривать ее более детально, в ближайшем будущем.

6) Тотальный инклуд

Предположим, вы создали свой «движок» на PHP, соблюдали все предыдущие советы. В нем практически неизбежно будет множество различный инклудов: файлов конфигурации, функций, языков и т.д. Суть сводится к тому, что даже обычный инклуд того же файла с функциями будет требовать немало времени и памяти, даже если кроме функций в инклуде нет никакого исполняемого кода, и не одна из функций не вызывается.

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

Не пренебрегайте оптимизацией инклудов. Выносите то, что применяется не повсеместно в отдельные, специализированные инклуды. Еще один пример для закрепления. Мой любимый движок новостного сайта. Функции добавления новостей, комментариев, их контроля и пре-парсинга занимает около 1/3 кода общего количества функций. Но как часто они необходимы? В 1 из 100 запросах? Или в 1 из 200? Или еще реже? Так зачем же их каждый раз грузить? Это действительно может существенно снизить производительность ваших решений.

7) Лишняя функциолизация и ООП-тимизм

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

часто используемых в пределах одного цикла работы программы

частей кода в отдельную, общую часть. В принципе, выносить код в «отдельную часть» имеет смысл и тогда, когда он выполняется по некому, относительно маловероятному событию. К примеру, прикрепление фото к посту на форуме. Вынос обработчика загрузки и обработки картинки в «отдельную часть» позитивно отразится на производительности, даже если он заключен в условие (факт загрузки картинки). При этом, если данная «отдельная часть» нам понадобится лишь один раз, лучше выполнить ее просто как код (инклуд), а не как функцию. Функции всегда требуют некоторых дополнительных ресурсов. То же самое касается и ООП-программирования в PHP. ООП-код потребляет несколько больше ресурсов, поэтому если вам не принципиально ООП-форматирование кода, лучше отказаться от него. Я говорю именно о ООП-форматировании, поскольку ООП-подход в PHP имеет мало общего с самим понятием ООП-программирования. Как и PHP с классическим пониманием языков программирования и их задач — о чем я писал в начале.

Вот вы и ознакомились с 7 основными принципами производительного кода на PHP. Это только — только самое начало. Впереди у нас еще много интересного, более конкретного материала по данной теме.

Существует ряд правил, которые стоит соблюдать, чтобы увеличить скорость работы приложений на PHP. Правила простые и не потребуют значительных изменений в существующих приложениях.

Fastcgi

FastCGI — это один из вариантов подключения PHP к Web серверу. Лучше всего использовать в связке с Nginx. PHP-fpm (Fastcgi контейнер для PHP) и Nginx по умолчанию поддерживают совместную работу и очень легко настраиваются .

OpCache


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

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

В версии PHP5.5+ этот модуль поставляется в стандартной сборке. В предыдущих версиях модуль нужно устанавливать самостоятельно. Проверить наличие можно так: php -i | grep opcache

# Пустой вывод будет означать, что модуля нет

Если версия слишком ранняя, лучше использовать APC: apt-cache search php-apc

# Это альтернатива opCache, но делает то же самое

Кэширование

Часто код просто медленный. Например:

  • обращения к внешним API
  • тяжелые выборки из баз данных
  • обработка больших файлов
session.save_handler = memcache session.save_path = "tcp://localhost:11211 "

# localhost:11211 это стандартный хост и порт Memcache

Кроме этого, такая схема хранения позволит масштабироваться на несколько серверов.

Оптимизация кода

ООП

Помните! ООП — это всегда медленно. Объекты нужно создавать, где-то хранить и уничтожать. Не используйте объекты, если они не нужны. Например, тут:

set_title($_GET["title"]); $post->set_description($_GET["description"]); $post->save();

# $posts = список объектов Post, полученных каким-то образом foreach ($posts as $post) { echo $post->title . "
"; }

# Используем список объектов только для того, чтобы вывести свойство

В этих примерах использование ООП не имеет особого смысла. Зато расходует ресурсы. Старайтесь использовать массивы, когда объекты не нужны:

$_GET["title"], "description" => $_GET["description"]]);

# Избежали создания объекта, функция просто сохраняет данные из массива в базу

"; }

# Намного лучше — сделать простую выборку и вывести нужные данные из массива

Мелочи

При работе с файлами используйте абсолютные пути. Тогда не будут происходить лишние операции поиска файла:

include "/var/www/file.php"; file_get_contents("/var/www/dir/data.txt");

Константы классов работают эффективнее, чем define:

class posts { const PER_PAGE = 10; ... }

Не используйте функции в условии for, т.к. они будут повторяться на каждой итерации цикла:

$max = mysql::get_col("SELECT count(*) FROM posts"); for ($i = 0; $i < $max; $i++) { ... }

В качестве ключей массивов всегда указывайте строки с кавычками :

$post["title"] = "Первый пост";

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

strpos($post["title"], "хорошо");

Используйте строки с одинарными кавычками:

$post["title"] = "В этом случае нет дополнительной обработки переменных"

PHP cron-скрипты

Когда PHP используется для разработки скрипта, который будет выполняться по крону, следует избегать использования глобальных переменных. Например:

(.+?)<\/title/", $rss, $matches ); }

(.+?)<\/title/", $rss); if ($has_something) $updates = time(); $rss = file_get_contents("http://othersource.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); }

Теперь переменная $updates будет расти до максимального предела. Когда будет достигнут лимит по памяти, скрипт будет остановлен. Уследить за всеми переменными довольно тяжело, поэтому лучше использовать функции. Все переменные, созданные внутри функции будут удаляться после ее завершения:

process(); function process() { $rss = file_get_contents("http://somesite.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); $rss = file_get_contents("http://othersource.com/rss"); $has_something = preg_match("/title>(.+?)<\/title/", $rss); if ($has_something) $updates = time(); }

Самое важное

  • Обязательно используйте opCache для PHP. Это бесплатно экономит ресурсы.
  • Используйте FastCGI (лучше всего Nginx + PHP-fpm).
  • Функции в крон задачах помогут избежать утечек памяти.
  • Кэширование медленных участков кода часто самое простое решение для ускорения работы.
  • Помните о

От автора: каждый уважающий себя разработчик переживает за «судьбу» своего кода. Старается сделать приложение как можно удобнее, быстрее и повысить его отказоустойчивость. Но не всегда оптимизация PHP позволит вам достичь этих высот.

Не лечи руку, если хромой на ногу!

Пардон за народный ирландский афоризм! Но он в самое «яблочко» отражает всю суть проблемы. Чаще всего оптимизация кода не позволит вам повысить быстродействие созданного скрипта или ресурса. А в случае с все крайне усложняется из-за большого количества факторов, повлиять на которые вы (как разработчик) просто не в силах.

Что касается неподвластных явлений, то я имею в виду скорость интернет-соединения, загруженность сервера, настройки ОС на клиентской машине, мощность железа ПК пользователя. На все эти составляющие вы не сможете повлиять. И в итоге получается, что проведенная оптимизация PHP кода не даст полноценного результата.

Что остается под властью веб-разработчика:

Настройки сервера – ограниченно. Настройка параметров через файл конфигурации Apache httpd.conf позволяет задать количество дочерних процессов, таймаут соединения через сокет, объем буфера для вывода при соединении TCP/IP, время простоя и другие.

Настройки ядра языка – через параметры, прописанные в файле php.ini. Позволяет задать значения буферизации, изменить максимальное время выполнения скриптов, обработку ошибок, управление логами и другие настройки.

С помощью PHP оптимизации изображений – об этом позже. Оптимизация программного кода – позволяет «сэкономить» ресурсы и повысить быстродействие.

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

Работа с изображениями

Я не сторонник обработки изображений на стороне сервера. Это также ведет к трате драгоценных ресурсов, которых на хостинге всегда мало. Получается, что экономя на одном, мы понапрасну расходуем другие «запасы».

Более оптимальным является вариант загрузки изображений на сторонний сервис, откуда они уже в оптимизированном виде подгружаются в браузер пользователя по заданному адресу. В Сети таких сервисов множество. Хочу назвать только несколько из них: kraken.io, TinyPNG

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

Кроме этого обладает собственным встроенным инструментарием для «облегчения» изображений. Например, функция imagecopyresampled (). Она уменьшает вес контента за счет ресамплинга и изменения размеров рисунка. Пример использования:

header ("Content-Type: image/jpeg" ) ;

$file = "sample.jpg" ;

$img_obrabot = imagecreatetruecolor (200 , 100 ) ;

$img_orig = imagecreatefromjpeg ($file ) ;

imagecopyresampled ($img_obrabot , $img_orig , 0 , 0 , 0 , 0 , 200 , 100 , 541 , 286 ) ;

imagejpeg ($img_obrabot ) ;

Что можно еще

Также не забывайте о применении оптимизации клиентской стороны с помощью PHP. В какой-то мере сервер может влиять на клиентский браузер через Cache-Control, а также атрибуты этого заголовка: post-check, max-age и другие.

Кроме этого управлять состоянием кэша на клиентской машине позволяют заголовки Last-Modified и ETag. Для изменения каждого файла они устанавливают уникальный идентификатор. Благодаря чему сервер не пересылает ресурсы заново, а лишь ответы 304 статусом.

В статье мы не поднимали вопроса оптимизации с помощью PHP FPM. Но для его рассмотрения потребуется отдельная статья. А на сегодня все. До следующей встречи!


Как без особых усилий заставить PHP -код работать на порядок быстрее ? Перед тем как задаваться вопросами кеширования и масштабирования стоит попробовать оптимизировать код. Есть ряд несложных правил:

Еще про оптимизацию....

При вставке кусков PHP-кода в HTML страницы всегда используйте полные открывающие и закрывающие скобки ! Это обезопасит Вас от вариаций настройки php.ini short_open_tag на разных серверах и возможно сэкономит много времени при переносе или загрузке проектов на разные сервера.

Старайтесь использовать функцию вывода echo вместо printf и sprintf там где возможно. Нет надобности использовать эти функции, так как они выполняются медленней потому, что созданы для интерпретации и вывода строки с ее обработкой, подстановкой значений, в отформатированном виде. О чем и говорит буква f в конце названия этих 2-х функций.

Sprintf("мама"); printf("папа");

Echo "мама"; echo "папа";

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

Лучший вариант(самый быстрый)

Echo "Вес равен: ".$weight;

Худший вариант(медленный):

Echo "Вес равен: $weight";

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

$i = 0; if ($i != 0) { //Не равно } else { //Равно }

$i = 0; if ($i > 0) { //Не равно } else { //Равно } Нужно также учитывать, что если строка принимает только пустое значения, либо пользовательские строковые данные, то вместо сравнения строки со строкой, для выявления ее пустоты, так же можно использовать сравнение с нулем, которые выполнится быстрее.

Для проверки строки на пустоту используйте функцию trim($str) ; Она не только проверит заполнена ли строка, но также обрежет несущественные символы - пробелы (табуляции, white-spaces) и вернет положительное значение, в случае если в строке ей действительно какие то значимые символы.

If ($str != "") { //обработка строки }

If (trim($str)) { //обработка строки }

Для получения данных из форм методом Get и Post лучше использовать следующий минимальный набор самописных функций:

GetParam ($array, $value, $default = "") { return (isset($array[$value])) ? $array[$value] : $default; } GetParamSafe ($array, $value, $default = "") { return (isset($array[$value])) ? addslashes($array[$value]) : $default; }

Функция GetParam($_POST, "myvar", "empty") к примеру коректно получит данные из $_POST["myvar"], и в случае если $_POST переменная не существует вернет значение по умолчанию, без всяких Waring и Notice. Фунция GetParamSafe($_POST, "myvar", "empty") делает ту же операцию, только возвращает экранированную переменную. Для защиты от SQL инъекций к примеру. А данная конструкция позволяет получить целочисленное число из $_POST.

Intval(GetParam($_POST, "myvar", "empty")):

В случае если в массиве $_POST лежало совсем не число функия вернет 0;

Для простого сравнения строк не используйте preg_match() или preg_match_all() . Используйте strstr() и strpos() .

При получении строк из базы данных (MySQL к примеру) старайтесь использовать функцию mysql_fetch_object . К примеру при изменении кода запроса с

$query = "SELECT field7, field3 FROM mytable WHERE id = 5" на $query = "SELECT * FROM mytable WHERE id = 5" код вывода строки полученной из этих запросов $row = mysql_fetch_array(mysql_query($query)); echo $row."-->".$row; //перестанет работать, в то время, как $row = mysql_fetch_object(mysql_query($query)); echo $row->field7."-->".$row->field3; // останется работоспособным.

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

При формировании больших запросов вставки данных в БД через insert все строчки старайтесь поместить в один-три insert"а. Выполнение каждой строчки отдельно не только загрузит сервер БД, но и задержит работу Вашего скрипта.

В случае если необходимо в разных местах (разных классах) одной системы использовать одни и те же сложно вычисляемые данные (например которые достаются из БД через запрос с последющей обработкой строк), старайтесь их вычислять единожды, хранить глобально для всей системы и передавать в класс(скрипт) один раз, непосредственно при создании класса (подключении скрипта)

При больших нагрузках на Web-сервер задумайтесь над использованием стандартных решений для включения кэша(кэш-технологии). Например бесплатный PHP класс JCache_Lite_Function.

При проектировании/разработке больших систем отдавайте предпочтение Объектно-Ориентированному программированию с использование шаблонов проектирования. Наиболее частые шаблоны: MVC, PageController, BodyHandler, Fabric...


Читать дальше: