Ускорение PHP-программ
Как без особых усилий заставить PHP-код работать на порядок быстрее ? Перед тем как задаваться вопросами кеширования и масштабирования стоит попробовать оптимизировать код. Есть ряд несложных правил:
-
Выносите функции и вычисления из циклов. Такое:
$ar=array(1,2,2,3,4,4); for($i=0;$i
Замените на
$ar=array(1,2,2,3,4,4); $e=12342+sqrt($b)/12123; $c=count($ar); for($i=0;$i
Альтернативный вариант:
for($i=count($ar)-1;$i>=0;$i--)
Прочитать про всё это подробнее, посмотреть графики скорости и загрузить все примеры можно вот тут: «Оптимизация программ на 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 = »)
Функция 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
$query = "SELECT * FROM mytable WHERE >код вывода строки полученной из этих запросов
$row = mysql_fetch_array(mysql_query($query)); echo $row[0].'-->'.$row[1]; //перестанет работать, в то время, как
$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.
Как ускорить приложение за счёт PHP-FPM (няшим FPM conf)
Сегодня хочу поговорить о том, как ускорить приложение через конфигурирование PHP-FPM.
Сейчас самый популярный (из тех с которыми я сталкивался) стек на котором поднимается PHP приложение это веб сервер nginx и процесс-менеджер php-fpm.
Я хочу поднять простое приложение с Laravel проектом, которое устанавливается со всеми параметрами по умолчанию. Попробуем это приложение нагрузить пользователями с помощью простого Javascript скрипта и посмотрим как ему удастся справиться с нагрузкой и как мы можем повысить обрабатываемую нагрузку только конфигурированием php-fpm. В конце статьи можно будет найти ссылку на GitHub и попробовать своими руками.
Для начала посмотрим на стандартную конфигурацию php-fpm и попытаемся понять где могут быть проблемы в производительности с коробки.
Итак, у меня есть простое приложение на PHP с NGINX и PHP-FPM предустановленными в стандартных конфигурациях и маршрут Laravel.
Маршрут симулирует нагрузку через команду засыпания на одну секунду и возвращает простой json ответ.
Так же у меня есть Javascript файл который производит запрос на наш роут. Запускать его мы будем с помощью нагрузочной утилиты k6.
Для того чтобы провести нагрузочное тестирование давайте запустим утилиту k6 с пятью VU (virtual users)
k6 run —vus 5 —duration 30s script.js
Как видим в строке http_req_duration avg (среднее по всем показателям значение) равно 1.77 сек. Это сама нагрузка 1 секунда + время прохода запроса по сети и работа фреймворка.
Давайте проведём еще один такой же тест но на 10и пользователях
k6 run —vus 10 —duration 30s script.js
Как видим время возросло почти в два раза.
Давайте проведём еще один тест и будем разбираться в чём же дело.
На этот раз попробуем нагрузить сразу 50ью пользователями наше приложение.
k6 run —vus 50 —duration 30s script.js
Как видим результат стал совсем грустным. В среднем клиенту приходится ждать ответа от сервера 15.48 секунд. Давайте разбираться в чём дело.
Для начала давайте узнаем какая сейчас конфигурация php-fpm. Сделать это можно с помощью команды php-fpm -tt
Эта команда выведет все параметры php-fpm, самые важные параметры я обвел рамкой.
Самый важный параметр — это pm.max_children он равен сейчас 5. Этот параметр сообщает нашему php-fpm сколько он может максимально запустить дочерних процессов (обработчиков) запросов. Иными словами сколько параллельно процессов будет обрабатывать входящую нагрузку.
Для лучшей наглядности я нарисовал небольшую схему.
Когда в наше приложение одномоментно приходит 50 клиентов они сначала обращаются в наш NGINX, он является просто прокси сервером и пробрасывает запросы сквозь себя на PHP-FPM (за исключением запросов за статическими ресурсами/файлами) и дальше PHP-FPM пытается обработать все запросы с помощью своих процессов (воркеров). Если же ситуация как у нас, когда PHP-FPM располагает только пятью воркерами, то первые 5 клиентов обрабатываются, а остальные 45 становятся в очередь и ждут, когда первые 5 обработаются. Как только первые 5 отработали, следующие 5 зашли на их место и оставшиеся 40 ждут в очереди.
На этом этапе появляется две проблемы. Первая — мы заставляем таким образом ждать клиентов ответа, вторая — если время ожидания будет выше стандартного для NGINX в параметре fastcgi_read_timeout (стандартное 30 секунд) то мы можем получить 504 ошибку от NGINX. Вторую проблему мы можем исправить увеличив время ожидания, но это не спасет нас от первой проблемы.
Логичное решение проблемы — просто добавить воркеров для PHP-FPM и это вполне адекватная мысль, но стоит позаботиться о том, чтобы добавить достаточно воркеров и не добавить лишних воркеров, которые займут всю операционную память.
Давайте вернёмся к нашим конфигурационным параметрам и постараемся сделать правильную настройку.
Итак, нас интересуют следующие параметры:
pm = dynamic — php-fpm сам контролирует количество запущенных воркеров, при указанном параметре dynamic php-fpm будет в зависимости от нагрузки добавлять или удалять воркеры. Так же в этом параметре может быть значение static в таком случае количество воркеров будет статическим.
pm.max_children — максимальное количество процессов единовременно работающих. Часто это значение ставится в количестве 4 * на количество CPU. Для того чтобы узнать количество CPU можно воспользоваться командой lscpu.
Более правильно будет еще проверить количество свободной памяти, можно сделать это командой free -hl
Обязательно нужно понимать сколько памяти занимает один воркер.
Это можно сделать с помощью команды htop и посмотреть среднее количество памяти которое занимают воркеры php-fpm
pm.min_spare_servers — минимальное количество процессов в состоянии ожидания. Это количество нужно как резервное в случае внезапного появления нового количества клиентов. Чтобы клиенты не ждали пока новые процессы создадутся резервные процессы подхватят внезапную нагрузку. Значение обычно ставится в 2 * на количество CPU.
pm.max_spare_servers — максимальное количество процессов в состоянии ожидания. В случае если нет нагрузки на приложение php-fpm удалит лишние процессы с целью сохранить оперативную память.
Хорошо, давайте сконфигурируем наш PHP-FPM.
Для начала найдем где находится файл конфигурации с помощью команды
Ставим start_server в 24.
min_spare_servers в 12.
max_spare_servers в 24.
И повторим нагрузочное тестирование с 50ью пользователями.
Как видите результат нагрузки средний 1.6 секунд. Примерно как и был в первом тесте, с пятью пользователями.
Так же еще можно посмотреть как отрабатывает php-fpm при установке pm стратегии в dynamic. Если вы запустите htop, то увидите стартовое количество воркеров
и если запустите тест, то постепенно количество воркеров сначала увеличится до максимально доступного
и после окончания теста снизится до начального.
Ускорение и оптимизация PHP-сайта. Какие технологии стоит выбирать при настройке сервера под PHP
Типичная проблема:
В какой-то момент сайт начинает открываться и работать слишком медленно. Бывает, что хостинговая компания блокирует сайт за превышение нагрузки или перерасход ресурсов. Что же делать в такой ситуации?
Может быть, сайт стал пользоваться слишком высокой посещаемостью или был установлен какой-то ресурсоёмкий модуль, совершается атака или сайт заражен вирусом. Так или иначе, но у всех этих случаев есть кое-что общее и это проблема всех сайтов на всех хостингах.
И если говорить о серверах для PHP, то такой проблемой является способ исполнения php кода, ровно как и другие значимые настройки окружения на сервере.
Не зависимо от того, есть ли проблема в вашем коде или её нет, высокая у вас посещаемость или нет, от настроек сервера зависит очень многое. Что бы все сказанное не звучало пустыми словами и была написана эта статья.
В этом обзоре я протестирую только что установленный сайт на одном из самых распространённых движков управления контентом Drupal 7.33.
Для теста выбрана лишь одна составляющая php-хостинга. Мы будем тестировать web-серверы Nginx и Apache2, модули mod_php и php-fpm, версии php php53 и php56, посмотрим, как влияют оптимизаторы apc и opcache на скорость работы сайта.
Конечно, эти параметры лишь часть настроек от которых зависит скорость сайта. Но мы умышлено
ограничиваемся этим, что бы не делать обзор бесконечным.
Так же вы можете прочитать другие мои публикации на тему «Идеального» кластера
- «Идеальный» кластер. Часть 3.1 Внедрение MySQL Multi-Master кластера
- «Идеальный» кластер. Часть 2.2: Высокодоступный и масштабируемый web-сервер, лучшие технологии на страже вашего бизнеса
- О виртуальном кластере на hetzner
- Frontend: NGINX + Keepalived (vrrp) на CentOS
- HAPRoxy для Percona или Galera на CentOS. Его настройка и мониторинг в Zabbix
- Zabbix 2.2 верхом на nginx + php-fpm и mariadb
Дано:
- Операционная система 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 | Nginx + php-fpm56 без оптимизатора opcache | 77,04 | 103,6 |
2 | Apache2 + mod_php53 без оптимизатора apc | 78,79 | 103,98 |
3 | Apache2 + mod_php56 без оптимизатора opcache | 78,85 | 102,38 |
4 | Nginx + php-fpm53 без оптимизатора apc | 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. | Apache2 + mod_php56 + opcache | 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, другие могут вести себя иначе, но общая тенденция будет такой же.
И главное — от конфигурации вашего сервера или хостинга, зависит скорость вашего сайта. Подобрав верную архитектуру, вы можете получить пятикратное увеличение скорости работы сайта.
Если у вас возникнут вопросы, трудности или потребуется совет:
Мои контакты в профиле
Как ускорить сайт в 4 раза, просто перенастроив сервер
Если вы работаете с сайтом, который постепенно растет, — увеличивается количество товаров, трафик с рекламы — то рано или поздно придется перейти в режим работы highload, высоких нагрузок на сервер. Но что делать, если ваш сайт не растет, а сервер все чаще не выдерживает, и происходит блокировка данных? Именно с этой проблемой мы столкнулись, дорабатывая сайт для интернет-магазина светового оборудования с ассортиментом более чем 100 000 товаров.
6.7K открытий
Исходная ситуация
Проект располагался на сервере, у которого было достаточно ресурсов, чтобы обеспечить быструю и бесперебойную работу сайта даже при очень высоких нагрузках. Однако сервер не отвечал на действия пользователей или отвечал очень медленно как только посещаемость сайта хотя бы немного возрастала.
Поиск проблемы
Мы провели аудит настроек сервера и сайта, разделив работы на два этапа: анализ back-end и front-end, и обнаружили низкую скорость загрузки страниц на back-end’e — порядка 80 секунд на самых посещаемых страницах, что в итоге приводило к существенному снижению конверсии.
Мы выяснили, что основная проблема заключалась в неправильно настроенном кэше и настройке базы данных.
В итоге был составлен план действий из четырех шагов, который помог нам добиться неплохих результатов. Что мы сделали?
Шаг 1. Настройка баз данных
На первом этапе мы настроили базу данных MySQL без изменения систем хранения, исходя из доступных ресурсов и нагрузки проекта. Эти действия, в первую очередь, были направлены на оптимизацию потребления ресурсов оперативной памяти, что позволило избежать ухода сервера в SWAP, когда, исчерпав ресурсы оперативной памяти, сервер начинал работать из файла подкачки и замедлял работу сайта.
Шаг 2. Смена типа хранения на InnoDB
Почему мы выбрали InnoDB?
В InnoDB данные хранятся в больших совместно используемых файлах, в отличие от используемого прежде MyISAM, где для каждой конкретной таблицы создается отдельный файл данных. InnoDB обеспечивает надежность хранения данных за счет блокировки данных на уровне строки и транзакционности.
Главное преимущество InnoDB заключается в скорости работы – при выполнении запроса к базе InnoDB происходит блокировка только строки, при выполнении же запроса к базе MyISAM блокируется вся таблица. Дело в том, что пока запрос не будет выполнен, никакие другие обращения к таблице/строке будут невозможны. А поскольку строки значительно меньше целых таблиц, InnoDB обрабатывает запросы быстрее.
Также была произведена оптимизация работы самой базы данных InnoDB. Например, были оптимизированы параметры:
Промежуточные результаты
После выполнения шагов 1 и 2 количество одновременных соединений с веб-сервером уменьшилось, так как запросы к базе данных и подключение к ней стали обрабатываться быстрее.
Это в свою очередь привело к уменьшению потребляемой оперативной памяти.
Шаг 3. Перенастройка Nginx и установка модулей кэширования brotli, pagespeed, proxy_buffering
Nginx позиционируется как простой, быстрый и надежный сервер, неперегруженный функциями. Уже длительное время Nginx обслуживает серверы многих высоконагруженных российских сайтов, например, Яндекс, Mail.Ru, ВКонтакте и Рамблер. Для улучшения производительности при использовании дополнительных серверов, Nginx поддерживает буферизацию (proxy_buffering) и кеширование (proxy_cache), чем мы и воспользовались.
Не обошлось и без курьезов настроек Nginx. У клиента был обычный интернет-магазин с товарами, тогда как настройки буферизации, которые мы обнаружили во время аудита, позволяли ему быть чуть ли ни стриминговым сервисом. Мы существенно уменьшили значения в параметре client_max_body_size, что в совокупности с перенастройкой Nginx еще больше снизило потребление памяти.
Шаг 4. Оптимизация настроек PHP-FPM и Memcache и отключение Apache
PHP-FPM нередко используется в паре с веб-сервером Nginx. Последний обрабатывает статические данные, а обработку скриптов отдает PHP-FPM. Такая реализация работает быстрее, чем распространенная модель Nginx + Apache.
Скорость обработки запросов Apache ниже. Например, Apache приходится каждый раз считывать несколько конфигурационных файлов на сервере, затрачивая системные ресурсы и время. В итоге мы решили просто отключить Apache, который ничего не обслуживал, а только потреблял ресурсы.
Необходимым шагом стал перевод работы PHP-FPM на unix socket. Зачем это понадобилось? Nginx сам по себе довольно быстрый веб-сервер, однако самостоятельно он не может обрабатывать скрипты. Для этого необходим бэкенд в виде PHP-FPM. Чтобы вся эта связка работала без потери скорости, мы использовали unix socket – способ подключения к PHP-FPM, позволяющий избегать сетевые запросы и дающий значительный прирост в скорости работы сайта.
Результаты работ
1. Время отклика главной страницы уменьшилось с 24 секунд до чуть более 3 секунд, внутренних до 5-8 сек.
2. Уменьшилось потребление серверных ресурсов.
3. Стабилизировалось поведение сервера — он перестал зависать.
4. Глубина просмотров увеличилась на 30%, и как следствие, это дало улучшение в SЕО, а также последующих продаж: растут поведенческие показатели => растут позиции сайта в выдаче => растет трафик => растут продажи.
5. Клиенту были даны рекомендации по оптимизации front-end части сайта для ускорения работы сайта. Например:
- оптимизировать графики и настройку выдачи изображений в формате webp;
- настроить lazyload-загрузки данных;
- вынести все некритические для отображения страницы скрипты в конец страницы.
Мы ускорили сайт и устранили проблемы с его загрузкой без изменения кода. Скорость работы сайта влияет на многие показатели: начиная с удобства для пользователя и заканчивая ранжированием сайта в поисковой выдаче, что в конечно итоге сказывается на конверсии.
7 комментариев
Написать комментарий.
Про innodb написана немного хрень, этот тип таблиц даст прирост скорости вывода данных, по сравнению с myisam, в том случае, если данные часто меняются. Myisam блокирует всю таблицу во время изменения строк, но не во время вывода. В интернет магазине навряд ли часто изменяются данные в тех таблицах, откуда они наиболее часто выводятся. Правда и недостатков у перехода на innodb не много, только увеличение занимаемого места на диске в два раза.
Время отклика страницы это именно время генерации php (в данном случае) кода, а затем еще идет загрузка всех ресурсов и отрисовка фронтенда. В наше время обычно время отклика сайта должно быть 0,1 секунды и меньше. Кое-как может жить сайт с временем отклика до секунды. Если на подопытном сайте время отклика было 24 секунды. то просмотров там могло быть от силы десятки в день. Никто сейчас не сидит по 30 секунд перед белым полотном в ожидании хоть какой-то реакции сайта. Поэтому скорее всего вы говорите о времени полной загрузки страницы, но тогда перечисленные работы не могли дать такой эффект без других оптимизаций, как раз перечисленных в списке про фронтэнд.
Пожалуйста, подключайте к написанию технических статей — технических специалистов. Зачастую одно слово, которое обозначает «вроде бы то же самое», на самом деле меняет весь смысл статьи или ее части, превращая его в бессмыслицу.
Развернуть ветку
MyISAM уже давно deprecated, на текущий момент нет ни одной причины для использования этого движка. Даже на самом MySQL отказались от использования этого движка для системных таблиц, он медленный и ненадежный. То что MyIsam быстрее innodb давно миф. При правильной настройке InnoDb будет давать прирост производительности не только за счет вставок, но и за счет более оптимальных сортировок, и прочей кучи оптимизаций которые продолжают добавлять в innodb/extradb. MyISAM имеет тенденцию крэшится без возможности восстановления при средней нагрузке и количестве данных от миллиона строк.
Innodb обеспечивает ACID, более качественную и производительную структуру хранения индексов в tablespace, оптимальную работу с индексами на уровне оптимизатора запросов. Кластеризованные индексы, которые значительно ускоряют работу по primary key. Автоматическое восстановление после crash. И много других преимуществ.
То что ребята написали про тюнинг изоляции транзакций очень странно, очевидно их нет в проекте и все идет автокоммитом.