Одной из тем докладов была производительность. И судя по тому, что на второй день конференции не раз возвращались к этому вопросу в кулуарах, понятно, что тема интересная и животрепещущая
Хочу теперь зафиксировать квинтэссенцию доклада и этих обсуждений.
Обновление от 16.09.09: улучшил скрипт по совету из комментариев.
[spoiler]
Итак, разберёмся в терминологии. Под производительностью веб сервера понимается число отдаваемых страниц в единицу времени. Когда мы говорим о производительности конкретного сайта, это сводится ко времени открытия страницы (строго говоря, зависимость не линейная т.к. сервер обрабатывает параллельно несколько запросов, но именно время открытия страницы поддаётся оптимизации).
Из чего складывается это время:
Два этапа,
первый: загрузка html кода страницы.
Здесь есть три процесса, которые следует рассматривать независимо: работа базы данных (время исполнения запросов), работа php кода и загрузка данных по сети.
При анализе производительности процесс загрузки надо сразу исключить, канал должен быть нормальным. Скажем, неразумно тестировать сайт через GPRS.
Затем работу базы и php рассматривать отдельно.
Для этого в продукте есть замечательный инструмент отладки, который поможет детально разобрать работу каждой страницы.
Авторизуемся под администратором, включаем:
Теперь под каждым компонентом и внизу страницы видим результаты:
(Если сделать логаут - будем видеть данные отладки для неавторизованного пользователя, они могут быть другими).
Этой информации достаточно чтобы начинать работать.
В моём примере время открытия страницы ~ 2,1 сек, время исполнения запросов ~ 0,1 сек (данные сформированы на стороне сервера, поэтому время загрузки здесь не учитывается). Т.е. на работу php скриптов уходит 2 секунды. Оптимизация базы не даст эффекта более 5%!
Первое, на что надо обратить внимание, это наличие
В моём прошлом примере акселератор был отключён, затем я включил его (использовал
Общее время создания страницы сократилось с 2 до 0,6 сек. Поэтому рекомендация такая: на своём сервере или VPS надо обязательно ставить акселератор, при
Для своего сервера рекомендую обратить внимание на бесплатную сборку Apache и php: Zend Server CE, о которой
Часто бывает наоборот: выполняется много тяжёлых и избыточных запросов, работа базы составляет основное время, жмём "Статистика SQL запросов" и видим какой запрос тормозит страницу и откуда он вызван.
При включении суммарной статистики отображается статистика включаемых областей, сразу видно, какой компонент работает продолжительное время.
Все SQL запросы, которые не требуется выполнять на каждый хит, необходимо
(Более 50 запросов на стандартной странице это много, более 100 - очень много).
Все стандартные компоненты имеют встроенное кеширование, необходимо его включать. При написании своих компонентов всегда думайте, что стоит за АПИ! Не указывайте сортировку, группировку если в этом нет необходимости, выбирайте только те данные, которые нужны для отображения. Используйте ограничение выборки. (Подробности:
Для наиболее сложных запросов рекомендуется создавать дополнительные индексы в базе данных.
Пример работы компонента с выключенным кешированием:
Теперь включаем кеширование:
Запросов к базе данных нет и общее время работы компонента сократилось более чем вдвое.
Таким образом можно всегда проанализировать и улучшить работу любой страницы.
Вторым этапом загрузки страницы является статика
Браузер запрашивает стили CSS, скрипты JS, картинки и т.д. (таких запросов может быть сотни). Кроме визуального восприятия скорости загрузки статики влияет на работу сервера. Apache загружает ненужные в этом случае модули php, mod_rewrite и др., использует большое число дочерних процессов и в целом потребляет много оперативной памяти.
Самое важное, что мы не можем ограничить это число и практически не контролируем расход памяти.
На посещаемом сайте обязательно следует применять
Это позволяет жёстко зафиксировать число процессов Apache и стабилизировать расход памяти через параметр MaxClients. Например, при среднем расходе памяти 50Мб можно установить
MaxClients = 5 |
50 x 5 = 250Мб |
И простейшего сервера с ОП 512 Мб может вполне хватить для обработки порядка 100 000 хитов в сутки на среднем сайте (стандарт, малый бизнес).
Как найти узкое место
Обновление от 21.06.2010:
Может возникать ситуация когда известно, что сайт создаёт нагрузку на сервер (например, приходит уведомление от хостера о превышении нагрузки на виртуальном хостинге), но не известно, какая конкретно страница.
Будем сохранять время открытия страниц в текстовый файл, затем анализировать результат. Делается просто:
1. В файле bitrix/php_interface/dbconn.php определим константу:
define('PAGE_START_TIME',microtime(1)); |
2. Добавим обработчик, который будет писать страницу и время в текстовый файл timelog.txt, для этого вставляем код в bitrix/php_interface/init.php:
AddEventHandler('main','OnAfterEpilog','WriteTime'); function WriteTime() { $file = $_SERVER['DOCUMENT_ROOT'].'bitrix/php_interface/timelog.txt'; if (filesize($file)>1024*1024) // Очистка если больше 1Мб fclose(fopen($file,'w')); file_put_contents($file, (microtime(1) - PAGE_START_TIME)."\t".$_SERVER['REQUEST_URI']."\n", FILE_APPEND | LOCK_EX); } |
3. Анализируем результат. Для этого написал небольшой скрипт:
<? error_reporting(E_ALL &~E_NOTICE); header("Content-type:text/html; charset=windows-1251"); $file = $_SERVER['DOCUMENT_ROOT'].'/bitrix/php_interface/timelog.txt'; if ($_REQUEST['clear']) fclose(fopen($file,'w')); file_exists($file) || die("Файл не найден: ".$file); $arFile = file($file); $arResult = array(); $arSort = array(); $sort = $_REQUEST['sort'] ? $_REQUEST['sort'] : 'avg'; foreach($arFile as $line) { list($time,$uri) = explode("\t",$line); list($page,$params) = explode("?",$uri); $page = trim($page); $arResult[$page]['cnt']++; $arResult[$page]['min'] = floatval($arResult[$page]['min']) == 0 || $time < $arResult[$page]['min'] ? $time : floatval($arResult[$page]['min']); $arResult[$page]['avg'] = (floatval($arResult[$page]['avg']) * ($arResult[$page]['cnt']-1) + $time) / $arResult[$page]['cnt']; $arResult[$page]['max'] = $time > $arResult[$page]['max'] ? $time : floatval($arResult[$page]['max']); $arResult[$page]['sum'] = $arResult[$page]['avg'] * $arResult[$page]['cnt']; $arSort[$page] = $arResult[$page][$sort]; } arsort($arSort); $arHeaders = array( 'min'=>'min', 'avg'=>'среднее', 'max'=>'max', 'cnt'=>'хиты', 'sum'=>'сумма', ); ?><html><body> <h2>Время открытия страниц</h2> <p>Общее число хитов: <?=count($arFile)?><br> <a href="javascript:if(confirm('Очистить файл \'<?=$file?>\'?'))document.location='?clear=Y'">Очистить статистику</a></p> <table border=1 cellspacing=0 cellpadding=4> <tr align=center> <td><b>Страница</b></td> <? foreach($arHeaders as $key=>$val) echo "<td><b><a href='?sort=".$key."'>".$val."</a></b></td>\n"; ?> </tr> <? foreach($arSort as $page=>$time) { $arTime = $arResult[$page]; echo '<tr><td>'.htmlspecialchars($page).'</td>'; foreach($arHeaders as $key=>$val) echo '<td>'.round($arTime[$key],3).'</td>'; echo '</tr>'; } ?> </table> |
Запускаем, получаем табличку вида:
Показывает для каждой страницы минимальное, максимальное и среднее время открытия, число хитов и суммарное время всех хитов. По каждому можно отсортировать.
На рисунке показана сортировка по среднему значению времени, получилось у меня на тестовом сайте самые "тяжёлые" разделы это каталог и социальная сеть:
/e-store/xml_catalog/ /club/index.php |
Также важный показатель - сортировка по суммарному времени. Например, бывает на сайте указана неправильная ссылка на картинку, в результате большое число хитов идёт на 404ю страницу, что создаёт существенную нагрузку, при том, что сама страница 404 может открываться быстро.
Таким образом, вы имеете инструменты для комплексного анализа производительности сайта.
P. S. Есть
Фото:
Данные генерации главной страницы:
Т.е. запросы исполняются моментально, а время работы скриптов значительное.
Что можно предпринять в этом случае? Или это особенности Zend-Accelerator-а?
EAccelerator тоже имеет свои настройки, которые сделаны не случайно.
Надо обязательно установить:
Важный параметр
Посмотрите, работает ли вообще акселератор: в папке, указанной в
В phpinfo должно меняться значение cached scripts.
Не приходилось с ним работать, но, очевидно, принципы будут те же.
Имхо, можно сократить вызов 3 функций на php
до 1 вызова стандартной функции -
Механизм очень удобный, сам им пользуюсь и вполне доволен. Для диагностирования причин ошибок очень удобно.
В применении к задачам профилировки -
Теперь могу начальству говорить, что не у меня (админа) руки кривые, а у наших программистов.
Спасибо, сделал.
а в демоверсии стоит фильтр
Как правильно?
В файле:
0.7867579460144 /contacts/
0.93328905105591 /contacts/
1.0784859657288 /contacts/
0.78065609931946 /contacts/
0.83487796783447 /contacts/
0.8450620174408 /contacts/
а результат:
Страница min среднее max хиты сумма
/contacts/ 0.845 0.877 1.078 6 5.259
я предлагаю строку
$arResult[$page]['min'] = intval($arResult[$page]['min']) == 0 || $time < $arResult[$page]['min'] ? $time : floatval($arResult[$page]['min']);
$arResult[$page]['min'] = floatval($arResult[$page]['min']) == 0 || $time < $arResult[$page]['min'] ? $time : floatval($arResult[$page]['min']);
при большом количестве файлов в директории сессии, сайт начинает тупить.
У себя я их обнаружил в количестве более миллиона.
Оказывается, программеры выставили время хранения сессии - 4 года.
Что я сделал:
1) Урезал время хранения сессий до 10 дней (увы, необходимость).
Результат: файлов создается не более 100 000.
Но 100 000 - это тоже много.
2) Вынес директорию хранения сессий в RAM-диск.
Рассматривать все выдающиеся варианты конфигурации не представляется возможным
все умирает.. битрикс не грузиться вообще.. в чём может быть дело?
настройки такие:
zend_extension="/usr/local/lib/php/20060613/eaccelerator.so"
extension="eaccelerator.so"
eaccelerator.shm_size="16"
eaccelerator.cache_dir="/tmp/eaccelerator"
eaccelerator.enable="0"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
;eaccelerator.filter="!*/help/* !*/admin/* !*/bitrix/*cache/* */bitrix/* */.*.php"
eaccelerator.filter="!*/help/* !*/admin/* !*/bitrix/cache/* */bitrix/* */.*.php"
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="0"
eaccelerator.shm_prune_period="0"
eaccelerator.shm_only="0"
eaccelerator.compress="0"
eaccelerator.compress_level="9"
и включите акселератор заменив строку
eaccelerator.enable="0" на
eaccelerator.enable="1"
советую
eaccelerator.compress_level="9" замените на
eaccelerator.compress_level="3"
Освободите ресурсы процессора, так как сжатие на 9 не имеет смысла.
Вполне достаточно "3"-"4".
eaccelerator.shm_size="16" поменяйте на
eaccelerator.shm_size="128" хотя-бы.
Проставьте время жизни
eaccelerator.shm_ttl="3600"
Если памяти много, то попробуйте не писать на диск а писать в память. Поправьте фильтрацию на директории, которые не стоит кешировать и тратить на них время.
Включите дебаг и проверьте что все работает павильно и работает с тем, чем нужно.
eaccelerator.filter="!*/help/* !*/admin/* !*/bitrix/cache/* */bitrix/* */.*.php"
load average увеличилось в среднем до 2 (двухядерный проц).
Вернул обратно
eaccelerator.filter=""
Загрузка вернулась к 0,1...0,2.
Насчет скорости открытия страниц: всё плохо, странички открывались по несколько секунд против полсекунды без включенного фильтра. Я думаю, там и мерять нечего, всё и так было видно.
С фильтром минут через 10 после рестарта httpd
Как вариант еще можно проверить