Основная проблема в том, что выполнить оценку производительности сервера нужно быстро, без использования специальных (читай, сложных) инструментов и, разумеется, до релиза. Мы должны уметь снять с сервера некие метрики и, умножив их на известные показатели приложения, получить оценку производительности приложения на этом сервере.
В жизни выполнить эту задачу может далеко не каждый разработчик, а из оставшихся далеко не каждый хочет её выполнять.
В этой статье я хочу рассказать о тех приёмах и инструментах, которые мы используем для оценки производительности сервера.
Типичные ситуации
№1
Команда разработчиков выходит на релиз и скоро готовится выпустить первую версию продукта. Следующий шаг — развернуть приложение на боевом сервере, который по условиям проекта нужно купить и настроить. На общем митинге руководитель проекта предлагает найти ответственного для решения этого «простого» вопросы: «Так, кто подберет хостинг и сервер? Я заложу необходимую сумму в бюджет следующей итерации». Как правило, желающих на эту задачу нет :). Более того, прямое делегирование — «Вася, займись этой задачей!» — тоже не работает: Вася мгновенно находит и перечисляет не менее десятка срочных/важных задач, которые вот прямо сейчас на нем висят и сдать их нужно вчера («и вообще, мы — не админы»). Повинуясь общему чувству самосохранения, команда слаженно подсказывает Руководителю Проекта, где именно нужно поискать такого специалиста (не ближе, чем в соседнем подразделении), и уж вот Он точно подберёт идеальную конфигурацию сервера.
№2
По условиям проекта сервер предоставляет заказчик. Это выглядит как отличное условие на старте проекта, но оно не является таковым, когда мы подходим к релизу. На вопрос клиенту «А сервер-то мощный?» следует неизменный ответ: «А то!». После деплоя Руководитель Проекта грустными глазами смотрит на тайминги откликов веб-приложения. Появляются неприятные мысли «Кто виноват?» и «Что делать?». Приходит понимание того, что конфигурацию сервера нужно было подбирать самим, но, с другой стороны, специалист из соседнего подразделения так и не нашелся. По факту выходит, что этот мощный сервер — дешёвая VPS’ка, параметры которой выглядят хорошо, но она делит ресурсы хоста с армией своих собратьев-соседей. Клиент оплатил сервер на пять лет вперед :) и менять что-либо не собирается (раньше нужно было говорить).
№3
Адвансед-уровень — у клиента есть сервер и админ. Параметры сервера не вызывают нареканий, но после деплоя приложения мы видим страшные тормоза, лаги, задержки. Наш девелоперский сервер по параметрам в три раза слабее, но приложение работает в восемь раз быстрее. Ни одно из наших предложений о замене сервера или покупке нового не принимается, так как у админа свое мнение — тормозит «ваше» приложение. Клиент не знает, кому верить; идея, влекущая новые расходы, ему тоже не нравится, поэтому аргумент админа засчитывается. Руководитель Проекта требует от команды четкого объяснения «почему приложение тормозит» и доказательств с цифрами «вины» сервера. У команды, как всегда, полно свободного времени, поэтому все с удовольствием берутся за решение задачи и ставят пиво специалисту из соседнего отдела за подсказку «куда копать».
Резюмируем, с какими ситуациями мы сталкиваемся и какие задачи нужно уметь решать:
— Подбор сервера под приложение и нагрузку
— Оценка возможностей имеющегося сервера
— Уметь ответить на вопрос «Почему так медленно?»
Требования к инструментам измерения
Наиболее точный способ измерения производительности сервера является одновременно и самым очевидным: нужно установить приложение на сервер и активировать реальную нагрузку. Такой способ хоть и даёт точный результат, но является бесполезным :) по ряду причин:
- Мы хотим знать оценку сервера заранее, до запуска в продакшн.
- Метод измерения должен быть быстрым и дешёвым.
- Инструмент измерения должен быть простым в использовании и установке на сервер.
- Результат измерения должен быть легко интерпретируемым и сравниваемым.
Объект измерения
Сервер куплен, операционная система установлена, sshd запущен. Открываем консоль и входим на сервер. Черная консоль, зеленые буквы и мигающий курс немо вопрошают тебя: «Что дальше?». Самое время задуматься, что будем измерять и из чего складывается производительность.
До этого момента вопрос казался простым: «запущу какой-нибудь бенчмарк и всё будет ясно». Сейчас, при виде мигающего курсора консоли, мысль замерла и никак не может выдать необходимую команду.
От чего в большей степени зависит производительность веб-приложения:
- Скорость работы связки CPU + RAM
- Скорость дисковой подсистемы
- Производительность среды исполнения языка (в нашем случае это PHP)
- Настройка базы данных (у нас это MySQL или PostgreSQL)
- И, конечно, от самого приложения (от того, какие ресурсы оно использует)
Нам нужно иметь четыре инструмента, которые бы могли замерить скорость работы по отдельности:
- для компонентов сервера: CPU+RAM и Дисковая подсистема
- для программных компонентов: MySQL и PHP
Имея на руках результаты замеров, мы можем комплексно говорить о производительности сервера в целом, а также можем прогнозировать работу веб-приложения.
Инструменты измерений
sysbench
github.com/akopytov/sysbench
Описать инструмент лучше, чем это сделал автор, нельзя, поэтому цитирую:
SysBench is a modular, cross-platform and multi-threaded benchmark tool for evaluating OS parameters that are important for a system running a database under intensive load.
The idea of this benchmark suite is to quickly get an impression about system performance without setting up complex database benchmarks or even without installing a database at all.
Это то, что нужно! Sysbnech позволяет быстро получить представление о производительности системы без установки сложных бенчмарков и специальных инструментов.
Установить sysbench просто:
apt-get install sysbench
Можно скомпилировать:
$ ./autogen.sh
$ ./configure
$ make
Проверяем производительность CPU
Для этого запускаем вычисление двадцати тысяч простых чисел.
$ sysbench --test=cpu --cpu-max-prime=20000 run
По умолчанию вычисление будет выполняться в одном потоке. Используем ключ --num-threads=N, если хотим производить параллельные вычисления.
Результат работы теста:
Тест CPU:
Test execution summary:
total time: 17.3915s
total number of events: 10000
total time taken by event execution: 17.3875
per-request statistics:
min: 1.66ms
avg: 1.74ms
max: 4.00ms
approx. 95 percentile: 2.03ms
Самое интересное в этом тесте — это значение total time. Запуская данный тест на нескольких серверах, мы можем сравнивать показания.
Приведу пример запуска этого теста на тех серверах, которые были у меня под рукой в момент подготовки статьи.
Заметки:
- G2 примерно в три раза быстрее, чем A3
- Простая VPS’ка на регру за 250 руб/мес сравнима с G2 :)
- Виртуалка на базе Xeon X3440 отработала так же, как и NUC i5
- Удивляет одинаковость результатов на четырех серверах
- Возможно, вычисление простых чисел происходит на одних и тех же блоках CPU, которые не отражают общей производительности процессора
Тестируем дисковую подсистему
Проверка дисковой подсистемы выполняется в три шага:
- Подготовить (сгенерировать) набор тестовых файлов
- Выполнить тестирование, снять показатели
- Убрать за собой мусор
Подготовка тестовых файлов:
$ sysbench --test=fileio --file-total-size=70G prepare
Команда создаст набор файлов общим размером на 70 гигабайт. Размер должен заметно превосходить объем оперативной памяти, чтобы на результат тестирования не влиял кэш операционной системы.
Выполнение теста:
$ sysbench --test=fileio --file-total-size=70G --file-test-mode=rndrw --init-rng=on --max-time=300 --max-requests=0 run
Будет произведен тест в режиме случайного чтения (rndw) в течение 300 секунд, после чего будут показаны итоги. Опять таки, по умолчанию тестирование будет выполняться в одном потоке (Number of threads: 1).
Очистка временных файлов:
$ sysbench --test=fileio cleanup
Пример результат выполнения теста:
Тест FileIO:
Operations performed: 249517 Read, 166344 Write, 532224 Other = 948085
Read 3.8073Gb Written 2.5382Gb Total transferred 6.3455Gb (21.659Mb/sec)
1386.18 Requests/sec executed
Test execution summary:
total time: 300.0045s
total number of events: 415861
total time taken by event execution: 178.9646
per-request statistics:
min: 0.00ms
avg: 0.43ms
max: 205.67ms
approx. 95 percentile: 0.16ms
Threads fairness:
events (avg/stddev): 415861.0000/0.00
execution time (avg/stddev): 178.9646/0.00
В качестве меры производительности дисковой подсистемы можно использовать значение средней скорости передачи данных (в данном примере это 21.659Mb/sec).
Посмотрим, что показал этот тест на моих серверах:
Заметки:
- Бросаются в глаза подозрительно низкие значения скорости на всех испытанных серверах
- На NUC i5 установлен ssd диск, сколько бы раз я не запускал тест, значение скорости передачи данных всегда было в интервале от 1.5 до 2 Mb/sec
- На моем рабочем MacBook Pro 2015 с ssd значение скорости в этом тесте равно 140Mb/sec 8-)
Тест MySQL OLTP
Тест проверяет скорость выполнения транзакций MySQL сервера, причем каждая транзакция состоит как из запросов на чтение, так и на запись.
Очень удобно изменять параметры сервера в my.cnf, перезапускать его и прогонять серию тестов, — сразу видно, как меняется производительность.
Подготовка к тестированию:
$ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test --mysql-user=root --mysql-password=pass prepare
Запуск теста:
$ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test --mysql-user=root --mysql-password=pass --max-time=60 --oltp-read-only=off --max-requests=0 --num-threads=8 run
Параметр --oltp-read-only можно установить в значение on, тогда будут выполняться только запросы на чтение, что позволит оценить скорость работы СУБД в режиме, например, slave-базы.
Результат выполнения теста:
OLTP test statistics:
queries performed:
read: 564158
write: 0
other: 80594
total: 644752
transactions: 40297 (671.57 per sec.)
deadlocks: 0 (0.00 per sec.)
read/write requests: 564158 (9402.01 per sec.)
other operations: 80594 (1343.14 per sec.)
Test execution summary:
total time: 60.0040s
total number of events: 40297
total time taken by event execution: 479.8413
per-request statistics:
min: 1.14ms
avg: 11.91ms
max: 70.93ms
approx. 95 percentile: 15.54ms
Самый интересный параметр в отчете — это количество транзакций в секунду (transactions per sec).
Как этот тест показал себя на серверах:
Заметки:
- На всех серверах конфигурация MySQL была одинаковая
- Удивляет отсутствие существенных различий между серверами A3 и G2
- NUC i5 сравним с G2
Как измерить производительность PostgreSQL?
К сожалению, инструмент sysbench не имеет встроенных средств для тестирования PostgreSQL. Но это нам совершенно не мешает, так как можно использовать утилиту pgbench.
Дополнительная информация:
www.postgresql.org/docs/devel/static/pgbench.html
Дефолтный сценарий тестирования производительности многократно выполняет следующую транзакцию:
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
Для создания тестовых данных выполняем команду:
$ pgbench -h localhost -U test_user -i -s 100 test
Выполняем тестирование:
$ pgbench -h localhost -U test_user -t 5000 -c 4 -j 4 test
Ключи команды означают, что 4 клиента будут выполнять 5000 транзакций в 4 потока. В итоге будет выполнено 20000 транзакций.
Результат:
starting vacuum...end.
transaction type: TPC-B (sort of)
scaling factor: 10
query mode: simple
number of clients: 4
number of threads: 4
number of transactions per client: 5000
number of transactions actually processed: 20000/20000
latency average: 0.000 ms
tps = 3350.950958 (including connections establishing)
tps = 3357.677756 (excluding connections establishing)
Самое главное здесь — это tps.
Сравнительных тестов на разных серверах, к сожалению, нет :)
А как же производительность PHP?
Вдоволь наигравшись с sysbench и намотав киловатты энергии на CPU многих серверов, мы научились быстро и весьма адекватно оценивать производительность случайно взятого сервера, что, в свою очередь, позволяет нам давать экспертный прогноз производительности web-приложения на этом сервере.
Однако возникают ситуации, когда sysbench показал хороший результат, а php-приложение на этом сервере демонстрирует совершенно посредственные показатели производительности.
Разумеется, на результат оказывают влияние такие параметры, как:
- Версия PHP
- Наличие акселератора
- Как и чем скомпилирован PHP
- Какие расширения активированы
Очень хотелось бы иметь инструмент, который бы легко устанавливался и после запуска выдавал понятную метрику производительности текущего PHP на сервере. Причем, хотелось, чтобы на этот инструмент не влияла производительность дисковой подсистемы (или сетевой) — измеряем только работу интерпретатора PHP на связке Процессор+Память.
Простое гугление/размышление привело к мысли, что:
- Существующего инструмента нет
- Нужно написать свой эталонный алгоритм (скрипт)
- В силу неизменности алгоритма получаемые результаты можно сравнивать
Что и было сделано: github.com/florinsky/af-php-bench
Скрипт собран в phar-архив, что заметно облегчает его скачивание и запуск на произвольном сервере.
Минимальная версия PHP для запуска — 5.4.
Для запуска:
$ wget https://github.com/florinsky/af-php-bench/raw/master/build/phpbm.phar
$ php phpbm.phar
Скрипт выполняет десять тестов, разделенных на три группы:
- Первая группа — это общие операции (циклы, rand, создание/удаление объектов)
- Вторая группа тестов проверяет строковые функции, implode/explode, вычисление хешей
- Третья — работа с массивами
- Все измерения выполняются в секундах
Отчет о выполнении теста:
[GENERAL]
1/10 Cycles (if, while, do) ...................... 6.72s
2/10 Generate Random Numbers ..................... 3.21s
3/10 Objects ..................................... 4.82s
Time: .. 14.76
[STRINGS]
4/10 Simple Strings Functions ................... 13.09s
5/10 Explode/Implode ............................ 15.90s
6/10 Long Strings ............................... 30.37s
7/10 String Hash ................................ 23.57s
Time: .. 82.93
[ARRAYS]
8/10 Fill arrays ................................ 22.32s
9/10 Array Sort (Integer Keys and Values) ....... 17.17s
10/10 Array Sort (String Keys and Values) ........ 14.29s
Time: .. 53.79
TOTAL TIME: . 151.47
Скрипт позволяет не только оценить общую производительность PHP на данном сервере (total time), но и увидеть, из чего она складывается. Неоднократно видел, что посредственный общий результат складывался только из-за одного теста: где-то это может быть медленная работа генератора случайных чисел, а где-то работа с длинными строками.
На странице результатов (https://github.com/florinsky/af-php-bench/blob/master/RESULTS.md) я записывал получаемые отчеты и группировал их в общую таблицу. Иногда результаты удивляют :)
Заключение
Я бы хотел добавить, что указанные выше инструменты позволяют оценить производительность сервера лишь прямо сейчас, в момент замера. Необходимо понимать, что на работу сервера могут оказывать влияние параллельно работающие процессы. И если замер показал вам хороший результат, это не значит, что он будет таким всегда.
Особенно остро эта проблема проявляется, если вы анализируете сервер клиента, который уже эксплуатируется «в полный рост». Вы не знаете, какие cron-задачи выполняются, какие процессы дремлют и ждут своего события, чтобы включить долгий gzip/tar, еще тут работает антивирус/спам-фильтр и десяток виртуалок, в которых происходит загадочное.
Для анализа поведения сервера во времени нам помогают atop и iostat. Копим статистику за несколько дней (или больше), после чего можно её просмотреть.
atop
Запись данных в файл:
$ atop -w /tmp/atop.raw 1 60
Прочитать запись:
atop -r /tmp/atop.raw
iostat
Замер загрузки CPU:
$ iostat -c 1
Вывод:
%user %nice %system %iowait %steal %idle
82.21 0.00 17.79 0.00 0.00 0.00
79.05 0.00 20.70 0.00 0.00 0.25
80.95 0.00 19.05 0.00 0.00 0.00
80.95 0.00 19.05 0.00 0.00 0.00
80.85 0.00 18.91 0.25 0.00 0.00
...
Замер загрузки дисковой подсистемы:
$ iostat -xd /dev/sda 1
Вывод:
rkB/s wkB/s await r_await w_await svctm %util
0.00 2060.00 4.05 0.00 4.05 3.98 95.60
0.00 2000.00 3.97 0.00 3.97 3.95 96.40
0.00 1976.00 3.92 0.00 3.92 3.92 95.60
0.00 2008.00 3.95 0.00 3.95 3.93 96.00
0.00 2008.00 3.92 0.00 3.92 3.92 96.80
0.00 2020.00 4.03 0.00 4.03 4.00 97.60
0.00 2016.00 3.97 0.00 3.97 3.97 97.20
...
И, разумеется, можно использовать Munin и ему подобные, чтобы собирать статистику с сервера в длинном хронологическом порядке.
Спасибо за внимание!
Комментарии (9)
Botkin
24.11.2015 11:24+1Всего этого можно было бы избежать, если бы разработчики не лезли в админские дела.
korvinriner
24.11.2015 12:22Суммарный вывод не увидел :( Фактически ставили четкую цель. По результатам замеров получили разрозненные (по агрегатам) результаты, как это поможет сделать выбор? В сухом итоге: Здесь А2 круче, Здесь А3 такой же, здесь VPS ничего… Наверное не хватает, что — то типа, но для нашего приложения важнее Проц и Память, поэтому Выбираем А2, но делаем себе отметку, что если будет провал там-то, то это нормально и надо искать другое решение… Возможно не понял посыл статьи.
SSul
24.11.2015 14:56Вероятно, вы правы, некого вывода в виде рецепта я не привел. Причем, когда статья задумывалась и формировалась, такая идея была.
Хотел показать некие практики наподобие «У вас есть сервис генерирующий thumbnail'ы (активное использование диска) — берите такой-то сервер. У вас строго вычислительный сервис — вам подойдет другой сервер».
Позже решил отказаться от такой идеи. Уж слишком однобокие получаются выводы. На практике такого и не встречал. Как правило, мы имеем дело с web-проектом, который активно нагружает все компоненты сервера, а значит все его компоненты должны быть быстрые. И приходим мы к выводу, что если нужен быстрый web-проект, то и сервер должен быть быстрый целиком, как бы банально это не звучало.
Поэтому в статье даётся перечень инструментов, которые позволяет измерить производительность отдельных компонентов сервера. Что делать с результатами — каждый решает сам.
korvinriner
24.11.2015 15:55Добрэ, как описание инструментов и способ применения — интересно и полезно.
Pilat
25.11.2015 00:05В принципе познавательно, но применимо ли на практике? Сколько можно вообще перетестировать серверов, выбирая нужный? Один, два, десять? Может быть, проще запускаться на первом попавшемся и по ходу дела определять чего не хватает? Вариантов то море, все не перепробуешь.
Pinkkoff
25.11.2015 16:58+1Ну не надо мерить так диски, ну что же это такое… То файлики копируют, то dd запускают.
Любой диск на обычном ПК будет значительно быстрее дискового массива с тысячью дисками за 2 млн $, если запускать на него 1 поток.
Никакое нормальное приложение никогда (надеюсь) не будет работать в таком однопоточном режиме с подобным профилем нагрузки. Сделайте один раз оценку, напишите профиль (а лучше несколько) на VDBench и используйте его для оценки производительности. Или найдите их в интернете.
Немного теории можно подчерпнуть в неплохой статье здесь
gydex
27.11.2015 10:18Методики интересные. Также бывает важно измерить время отклика сервера и пропускную способность канала. Причем результаты часто по закону подлости получаются из офиса заказчика гораздо хуже, чем с компьютеров разработчиков.
nikitasius
7z
fio