Здравствуйте, опять появилось желание чего-то написать. На этот раз я решил сделать вольный перевод одной из частей книги: «Surviving The Deep End» - бесплатной книги для изучения Zend Framework на русский язык.
Наиболее интересным материалом из книги я посчитал часть Appendix B. Performance Optimisation For Zend Framework Applications — увеличение производительности Zend Framework приложений…
Вступление
Оптимизация производительности не заключается в замене двойных кавычек одинарными для того чтобы получить прирост производительности в несколько наносекунд. Скорее это спланированный процесс по оценке текущей эффективности приложения, выявления недостатков и узких мест, приобретение соответствующего оборудования для Вашего веб-сервера и возможно применение доселе неизвестных Вам тактик оптимизации. Иными словами, это очень весело!
В этой части, я раскрываю вопрос оптимизации с точки зрения различных тактик и подходов, используемых в реальном мире, — где мы действительно не беспокоимся о кавычках (они не дают ощутимого эффекта).
Раскрытие данной темы большая задача, это большая часть книги, но я надеюсь, что материал будет полезным.
Избежание преждевременной оптимизации
Прежде чем приступить к решению данного вопроса, Вы должны четко уяснить, что нельзя жертвовать всем ради преждевременной оптимизации приложения. Преждевременная оптимизация, по словам Тони Хора (Tony Hoare), корень всего зла. Давайте запомним это навсегда. Если приступить к оптимизации приложения слишком рано, то это может привести к ограничению программного дизайна приложения, что может вызвать намного больше проблем. Так что стоит подождать пока приложение будет готово к проведению оптимизации.
Оптимизация это игра по ликвидации измеримой неэффективности. Здесь ключевое слово «измеримой». Если Вы не знаете и не можете уверенно предсказать к чему приведет оптимизация, то заслуживает ли это Вашего внимания? Глупая замена двойных кавычек одинарными, которую может выполнить один разработчик за час своей работы, может привести к совершенно не заметному приросту производительности. Вы просто потратите один час работы впустую, не получив при этом ничего! Между тем есть медленные SQL запросы, которые иногда при нескольких минутах работы с использованием Zend_Cache, могут принести прирост производительности в целую секунду. Очевидно, что второй вариант является гораздо больше достойным Вашего внимания. Поэтому сфокусируйтесь на оптимизацию, обеспечивающую наибольшую выгоду.
Существует три подхода к оптимизации: слепое следование Вашим надеждам, следование опытной интуиции, применение программных средств для анализа оптимизационных возможностей. Третий вариант, является единственным действенным решением. При использовании первых двух вариантов Вы рискуете упустить из виду реальные возможности для оптимизации или тратить время на бессмысленные операции.
Эти слова не отменяют первые два варианта напрочь. Этим должен руководствоваться программист во время разработки, а не после уже свершившегося факта тратить много часов для этого.
Опытный программист редко создает безобразно неэффективное приложение, которое усеянное очевидными недостатками исходного кода. Некоторые элементы оптимизированной производительности уже будут присутствовать в приложении, поэтому останется лишь использовать необходимый, заранее заданный потенциал. Много оптимизационных приемов имеют здравый смысл, решений на выбор очень много, и описаны половиной блогов планеты.
Измерение производительности
Оптимизация работает только тогда, когда Вы можете создать значительные, ощутимые результаты. Когда Вы оптимизируете наиболее очевидные проблемы производительности, более мелкие проблемы начинают выходить на передний план до тех пор, пока Вы не достигнете состояния, когда оптимизация стоит больше чем ожидаемый результат или в качестве альтернативы бросаете больше на аппаратную составляющую. В любом случае, Вы должны иметь цели оптимизации, и для достижения этой цели необходимо измерить текущую производительность для установки базового уровня, и будущую производительность, чтобы сравнить Ваши достижения по сравнению с базовым уровнем.
Измерение производительности, как правило, описывается несколькими характеристиками. Память и использование ЦП самые очевидные из них, особенно на едином сервере, ресурсы которого ограничены. Даже в среде, где Вы можете масштабировать ваше аппаратное обеспечение горизонтально или вертикально, максимализм производительности поможет Вам уберечься от нужды покупки дорогих серверов для покрытия дыр не оптимального кода.
Другой общепринятой характеристикой для измерения производительности является количество запросов в секунду, измерения того, сколько запросов некая часть Вашего приложения в состоянии обслужить за секунду на конкретном аппаратном обеспечении.
Измерение памяти и использования ресурсов ЦП
Измерение используемой памяти может быть осуществлено как на уровне сервера так и на уровне PHP. Последний же, позволяет измерить память с помощью двух функций — memory_get_usage() и memory_get_peak_usage(). Данные функции помогают определить сколько байт памяти использовано в текущий момент, а также пиковое ее значение. Они обычно используются, чтобы приблизительно определить профиль потребления памяти приложением и выставить необходимые настройки интерпретатору.
Существуют различные тактики измерения уровня потребления памяти, среди которых самые распространенные ручное измерение и автоматическое. Ручное измерение заключается в получении данных для каждой страницы отдельно, которую Вы вызываете сами. Второй подход заключается в использовании ПО, которое сможет выполнить запросы ко всем Вашим страницам. Выбор тактики зависит исключительно от Вас.
Одним из возможных грубых решений есть написание небольшого плагина, который реализует Zend_Controller_Plugin_Abstract:: dispatchLoopShutdown() метод:
Зарегистрировать плагин Вы можете в бутстрап-файле:
Это довольно простой пример, но Вы можете запросто доработать этот код для получения более детальной информации о потреблении памяти на конкретных страницах, что поможет определить причины любых проблем с использованием памяти.
Вот пример данных записанных в лог-файл:
- 2009-01-09T15:41:46+00:00 INFO (6): 4102728 bytes /
- 2009-01-09T15:42:57+00:00 INFO (6): 4103608 bytes /index/comments
Если Вы предпочитаете смотреть и анализировать результаты «на лету», то можно использовать различные PHP stream Writer'ы, например, Firebug Writer для просмотра результатов в Firefox с FirePHP.
Еще один вариант исследования потребления ресурсов приложением — профилирование кода, что помогает определить причины и места в коде, где ресурсы используются не рационально.
Помимо вышеприведенных решений имеет смысл также использование серверных инструментов для измерения использования ресурсов приложением. Например, в Linux предлагается к использованию top, free, vmstat и ряд других программ. Мой любимый — Htop, в котором отображаются постоянно обновляемые данные о памяти, процессоре, с некоторыми интерактивными функциями.
Этот прием особенно полезен для настройки сервера под Ваше приложение, для достижения максимальной производительности. Также, очевидно, такие исследования помогут понять сколько Apache клиентов сможет работать одновременно и что иссякнет в первую очередь CPU или RAM?
Запросы в секунду
Нагрузочное тестирование еще один полезный инструмент измерения производительности. Для того чтобы получить сопоставимые данные Вы должны измерять производительность своего приложения, при этом не меняя аппаратную составляющую. Целью нагрузочного тестирования является получение информации о том, сколько запросов в секунду может обслужить конкретный URL (или набор URL).
Этот подход достаточно прост для имитации. Необходимо всего лишь создать ситуацию нескольких одновременно работающих пользователей, с запросами от них через заданные промежутки времени. Иногда, базовым элементом есть использование фиксированного количества запросов на определенный интервал времени. Тогда оценка производительности происходит делением количества обслуженных запросов на количество времени в секундах, за которое это было сделано. Это весьма эффективно для исследования изменения производительности системы в целом.
Для проведения подобных тестов чаще всего используют два инструмента ApacheBench (AB) и Siege.
AB обычно устанавливается на сервер вместе с HTTP сервером Apache. Если у Вас его нет, то Вы всегда можете его установить.
Вот команда для запуска AB: 10 000 запросов по 100 одновременно работающих (слэш в конце имеет значение):
AB -10000 -N с 100 http://www.survivethedeepend.com/
В результате вы получите следующий вывод:
Server Software: apache2
Server Hostname: www.survivethedeepend.com
Server Port: 80
Document Path: /
Document Length: 9929 bytes
Concurrency Level: 100
Time taken for tests: 341.355 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 101160000 bytes
HTML transferred: 99290000 bytes
Requests per second: 29.29 [#/sec] (mean)
Time per request: 3413.555 [ms] (mean)
Time per request: 34.136 [ms] (mean, across all concurrent requests)
Transfer rate: 289.40 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.7 0 52
Processing: 124 3409 831.1 3312 10745
Waiting: 120 3267 818.5 3168 10745
Total: 124 3409 831.1 3312 10745
Percentage of the requests served within a certain time (ms)
50% 3312
66% 3592
75% 3784
80% 3924
90% 4344
95% 4828
98% 5576
99% 6284
100% 10745 (longest request)
Вот аналогичный пример, только с Siege. Мы устанавливаем количество запросов и количество одновременных пользователей. Так 100 одновременных пользователей, повторив свой запрос 10 раз в общей сложности дает Вам 1000 запросов. Дополнительная опция дает возможность установить задержку между запросами, в данном случае это 1 секунда, которой вполне достаточно для проведения теста.
siege -c 100 -r 10 -d 1 http://www.survivethedeepend.com
Вот и сам вывод:
Transactions: 1000 hits
Availability: 100.00 %
Elapsed time: 43.77 secs
Data transferred: 3.06 MB
Response time: 3.20 secs
Transaction rate: 22.85 trans/sec
Throughput: 0.07 MB/sec
Concurrency: 73.08
Successful transactions: 1000
Failed transactions: 0
Longest transaction: 8.78
Shortest transaction: 0.05
Оба примера исследования с помощью нагрузочного тестирования достойны внимания, для изучения других их возможностей и проведения более разнообразных тестов. Комбинирование различных тестов, с контролем потребления ресурсов может быть очень полезным при настройке Apache.
И да, производительность этой книги на веб-сайте была просто ужасной! Если бы я включил кэширование страниц, то показатели производительности были бы существенно выше!
Следует отметить, что нагрузочное тестирование можно проводить не только для оптимизации серверного ПО, а также и для оптимизации самого приложения.
Продолжение следует...
Предыдущие части:
- Первая часть
- Вторая часть
- Третья часть
- Четвертая часть
- Пятая часть