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

Основная проблема в том, что выполнить оценку производительности сервера нужно быстро, без использования специальных (читай, сложных) инструментов и, разумеется, до релиза. Мы должны уметь снять с сервера некие метрики и, умножив их на известные показатели приложения, получить оценку производительности приложения на этом сервере.

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

В этой статье я хочу рассказать о тех приёмах и инструментах, которые мы используем для оценки производительности сервера.

Типичные ситуации


№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).

Посмотрим, что показал этот тест на моих серверах:

image

Заметки:

  • Бросаются в глаза подозрительно низкие значения скорости на всех испытанных серверах
  • На 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)


  1. nikitasius
    24.11.2015 11:18
    +1

    7z
    fio


  1. Botkin
    24.11.2015 11:24
    +1

    Всего этого можно было бы избежать, если бы разработчики не лезли в админские дела.


  1. korvinriner
    24.11.2015 12:22

    Суммарный вывод не увидел :( Фактически ставили четкую цель. По результатам замеров получили разрозненные (по агрегатам) результаты, как это поможет сделать выбор? В сухом итоге: Здесь А2 круче, Здесь А3 такой же, здесь VPS ничего… Наверное не хватает, что — то типа, но для нашего приложения важнее Проц и Память, поэтому Выбираем А2, но делаем себе отметку, что если будет провал там-то, то это нормально и надо искать другое решение… Возможно не понял посыл статьи.


    1. SSul
      24.11.2015 14:56

      Вероятно, вы правы, некого вывода в виде рецепта я не привел. Причем, когда статья задумывалась и формировалась, такая идея была.

      Хотел показать некие практики наподобие «У вас есть сервис генерирующий thumbnail'ы (активное использование диска) — берите такой-то сервер. У вас строго вычислительный сервис — вам подойдет другой сервер».

      Позже решил отказаться от такой идеи. Уж слишком однобокие получаются выводы. На практике такого и не встречал. Как правило, мы имеем дело с web-проектом, который активно нагружает все компоненты сервера, а значит все его компоненты должны быть быстрые. И приходим мы к выводу, что если нужен быстрый web-проект, то и сервер должен быть быстрый целиком, как бы банально это не звучало.

      Поэтому в статье даётся перечень инструментов, которые позволяет измерить производительность отдельных компонентов сервера. Что делать с результатами — каждый решает сам.


  1. korvinriner
    24.11.2015 15:55

    Добрэ, как описание инструментов и способ применения — интересно и полезно.


  1. Pilat
    25.11.2015 00:05

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


  1. Pinkkoff
    25.11.2015 16:58
    +1

    Ну не надо мерить так диски, ну что же это такое… То файлики копируют, то dd запускают.
    Любой диск на обычном ПК будет значительно быстрее дискового массива с тысячью дисками за 2 млн $, если запускать на него 1 поток.
    Никакое нормальное приложение никогда (надеюсь) не будет работать в таком однопоточном режиме с подобным профилем нагрузки. Сделайте один раз оценку, напишите профиль (а лучше несколько) на VDBench и используйте его для оценки производительности. Или найдите их в интернете.
    Немного теории можно подчерпнуть в неплохой статье здесь


    1. SSul
      26.11.2015 08:20

      Спасибо! Вот это очень интересно!


  1. gydex
    27.11.2015 10:18

    Методики интересные. Также бывает важно измерить время отклика сервера и пропускную способность канала. Причем результаты часто по закону подлости получаются из офиса заказчика гораздо хуже, чем с компьютеров разработчиков.