Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Подходы к оптимизации (веб-)приложений

Anna | 31.05.2014 | нет комментариев

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

Когда следует оптимизировать?

Самый 1-й вопрос, тот, что необходимо себе задавать перед тем, как заняться оптимизацией чего-либо — устраивает ли вас нынешняя продуктивность? Скажем, если вы разрабатываете игру, каков наименьший FPS на «среднем» железе и «средних» настройках? Если он опускается ниже, скажем, 30, то игроки это подметят. Даже если средняя частота кадров составляет 60 FPS, именно минимальное значение FPS определяет ощущения от игры — «тормозит» либо «работает плавно». Если это веб-сайт, сколько времени открываются страницы для пользователей? Если это время составляет доли секунды, пользователи будут больше энергичны и будут получать удовлетворение от работы с вашим сайтом.

Возможен, вы осознали, что вас (либо ваше руководство, хехехе) не устраивает нынешняя эффективность приложения. Что делать?

1. Измеряйте

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

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

По этим (и, допустимо, некоторым иным) причинам в качестве замены отдельной утилите для профилирования при веб-разработке встраивают так называемые «дебаг-панели» в development-версии сайта (пример), в которых приводится сводка (с вероятностью посмотреть детали) разных метрик, которые встроены прямо в код. Традиционно это число и время исполнения SQL-запросов, реже встречается числа и времена исполнения запросов к иным сервисам (скажем, к memcache). Примерно неизменно измеряется также всеобщее время исполнения, размер результата с сервера, число потребляемой памяти.

В большинстве игр дозволено включить «отладочную консоль», в которой, как правило, дозволено видеть число FPS, число объектов на сцене и т.д. До касательно недавнего времени в minecraft содержалась диаграмма с разделением времени для всякого кадра: одним цветом рисовалось время, затраченное на «физику», иным — рендеринг.

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

<?php
function sql_query($query) {
$start = microtime(true);
$result = mysql_query($query);
$GLOBALS['SQL_TIME']  = microtime(true) - $start;
return $result;
}

2. Я сказал, измеряйте!

Вы молодец, всё обвесили таймерами, в development-окружении всё Удивительно, но на production всё по-иному? Значит, вы измеряете ненормально либо, что больше возможно, не всё… Как насчёт того, Дабы измерять эффективность на production? Если вы пишете, к примеру, на PHP, существует восхитительный инструмент для измерения продуктивности в production-окружении, работающий по протоколу UDP, под наименованием Pinba. На основании этого инструмента дозволено оставить debug-панель при разработке и в дополнение получить realtime-статистику по вашим таймерам в «боевом» окружении. Если вы никогда не измеряли продуктивность таким методом, вы скорее каждого узнаете дюже много увлекательного о том, как на самом деле работает ваш сайт.

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

3. Будьте ленивы

Зачастую дозволено найти, что в коде на всякий чих происходит инициализация чего-нибудь большого и непотребного на этой странице. Скажем, какой-нибудь огромный init-способ, тот, что на всякий веб-запрос лезет за прогнозом погоды на иной сайт либо выполняется «git pull origin master» в корне плана, как средство механического деплоя. В процессе обзора продуктивности вы непременно натолкнетесь на много пророческой, которые дозволено легко выбросить из кода, либо «завернуть в if», и включать необходимый кусок только тогда, когда он подлинно требуется.

Дюже Зачастую встречается, что большые фрагменты страницы остаются фактически непоколебимыми (скажем, «шапка» и «подвал» страницы). Если это так, то явственным решением является либо предварительно сгенерировать содержимое, либо разместить его в кеш и не рисовать его всякий раз по новой.

Будьте ленивы в своем коде и в реальной жизни. Не делайте одну и ту же (никому не необходимую) работу непрерывно, делайте только то, что подлинно необходимо для результата на запрос пользователя, а остальное либо не делайте, либо делегируйте кому-нибудь (скажем, дозволено «тяжелые», но не дюже Эмоциональные к задержкам, вещи возложить cron’у взамен того, Дабы исполнять это в вебе).

4. Используйте (асинхронную) пакетную обработку

В самых различных планах дозволено встретить одну и ту же банальную ошибку проектирования: обработку десятков, сотен записей, по одной, взамен того, Дабы обрабатывать всё совместно, цельным запросом. Скажем, если на странице вам необходимо показать данные по 30 товарах, сделайте один запрос вида «SELECT … FROM table WHERE id IN(…)» взамен 30 запросов вида «SELECT … FROM table WHERE id = …». Для большинства баз данных разницы в скорости между одним запросом с итогом на 30 строк и одним (!) запросом с итогом на 1 строку не будет вообще. Как правило, необходимо вовсе малое число изменений в коде для того, Дабы добавить пакетную обработку, а вместо вы получите приход скорости в разы, изредка в сотни раз. Это касается не только SQL-запросов, но и всяких обращений к внешним либо внутренним сервисам. Обращение по сети куда-либо неизменно вносит значительную задержку в обработку запроса, следственно число запросов весьма желанно сокращать до минимума в условиях веба.

Ещё одна вероятность ускорить пакетную обработку — это асинхронность. Если ваш язык это разрешает и вы можете сгруппировать запросы к различным сервисам в один и исполнить их асинхронно, то вы тоже получите ощутимое уменьшение времени результата, причём чем огромнее сервисов, тем огромнее выигрыш. Это слабо применимо к MySQL, но отлично применимо при работе, скажем, с неторопливым Google Datastore API.

5. Упрощайте трудное, распутывайте запутанное

Приведу пример: у вас есть большущий SQL-запрос, тот, что что-то делает, и делает это (допустимо) верно, но ооочень медлительно, сканируя при этом миллионы строк. Дабы оптимизировать трудный SQL-запрос, для начала необходимо его упростить, выбросить оттуда всё лишнее, допустимо, целые таблицы либо вложенные выборки. Лишь позже того, как вы убрали всё лишнее, дозволено начать проводить осмысленную оптимизацию. В отвратном случае, вы можете потратить много времени впустую, оптимизируя фрагмент, тот, что никак не влияет на финальный итог. Зачастую, исключительно при работе с MySQL, в качестве удовлетворительного решения может быть разбиение запроса на несколько больше примитивных, всякий из которых работает гораздо стремительней начального.

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

6. «Дорогие» фичи

Абсолютно допустима обстановка, когда вы найдете, что есть фичи, которыми пользуется 0,1% пользователей, но которые при этом занимают половину времени результата на сервере. Если это так, то вы можете либо испробовать переосмыслить эту функциональность и предложить какое-то другое, больше «недорогое» решение вместо, либо сделать эту фичу опциональной и отключенной по умолчанию. Если пользователю она необходима, он её включит обратно.

7. Кеширование

Если вообще огромнее ничего не помогает, либо у вас есть данные, которые не меняются со временем, кешируйте их. Отчего я утверждаю, что стоит применять кеш только тогда, когда все другие опции израсходованы? Дело в том, что как только вы начинаете класть в кеш изменяемые данные, вы обязаны будете следить за актуальностью кеша, что является дюже трудной инженерной задачей.

Пример: вы кешируете отдельные записи в таблице table по первичному ключу id. Одна запись — один ключ в кеше вида «table_<id>». Представьте сейчас, что вам необходимо обновить несколько записей по определенному условию («update table where <condition>»). Как верно сбросить кеш в этом случае? Одно из примитивных, но дюже трудоёмких решений — это делать заблаговременную выборку по этому условию, сбрасывать все записи в кеше по id и потом делать update. А что, если между select, сбросом кеша и update «вклинится» иной запрос? Приблизительно вот так:

1-й запрос:
1. select id from table where <condition>
2. memcache delete ids6. update table set … where <condition>
2-й параллельный запрос:

3. memcache get «table_N» — пусто, кеш теснее сброшен
4. select … from table where id = N
5. memcache set «table_N» — устанавливаем ветхие данные в кеш

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

Безоговорочно, есть огромное число примеров, когда кеширование удачно используется для увеличения продуктивности, но, вновь же, позже рассмотрения всех остальных вероятностей. В операционных системах операции по работе с неторопливыми носителями кешируются (чтение легко кешируется, запись буферизуется, что изредка приводит к порче данных либо конструкции файловой системы). Это дает ощутимый взнос в скорость работы, но, если вы когда-нибудь сопоставляли user experience от работы с SSD и с жестким диском, вы никогда огромнее не захотите пользоваться последним, невзирая на кеширование :) . В процессорах применяется много ярусов кеша, от того что память разного объема отличается по скорости работы на порядки (сравните время доступа порядка 1 нс к регистровой памяти и 10 мс для жесткого диска — разница в 10 млн раз!), следственно существенное усложнение архитектуры всё равно оправдано (иллюстрация взята извикипедии).

Завершение

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

* Первая иллюстрация взята с этой страницы (по суждению гугла)

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB