Статьи

Тестирование производительности веб-приложений с помощью Siege: планирование, тестирование, обучение

Эта статья была рецензирована Иваном Эндерлином и Верном Анчетой . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

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

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

Если рассматривать веб-приложение как черный ящик, все довольно просто: приложение ожидает запрос, обрабатывает его и возвращает ответное представление ресурса (HTML, JSON, XML и т. Д.). Кто-то может подумать: «Да, это просто, мы должны иметь возможность легко масштабировать наше приложение». К сожалению, мир веб-разработки — это не только солнце и радуга, и вы столкнетесь с множеством проблем с производительностью, пока ваш трафик растет! Вы узнаете и улучшите свои навыки и приложение с течением времени. В этой статье, предназначенной для ускорения этого процесса, я расскажу об основных принципах тестирования приложения (регрессионное, нагрузочное и стресс-тестирование) с помощью Siege, а также о некоторых советах и ​​приемах, которые мне нравятся при тестировании собственного веб-сайта. Программы.

Векторное изображение катапульты

Типы тестирования

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

Кроме того, знаете ли вы о том, как внесенные вами изменения кода могут повлиять на производительность? Одно простое обновление может значительно снизить или повысить производительность веб-приложения с высоким трафиком, и вы даже не узнаете, что произошло и почему, пока шторм не закончится. Чтобы убедиться, что приложение выполняет то же самое до и после изменения, мы проводим регрессионное тестирование.

Другим важным стимулом для регрессионного тестирования является изменение инфраструктуры: по любой причине вам может потребоваться перейти от поставщика A к поставщику B (или перейти с Apache на nginx). Вы знаете, что ваше приложение обычно обрабатывает N запросов в минуту (в среднем) и каков его обычный трафик (быстрый взгляд на аналитику сделает эту работу). Вы ожидаете, что ваше приложение будет вести себя так же (или лучше) после развертывания сервера провайдера B. Вы уверены, хотя? Ты бы рискнул? У вас уже есть все необходимые данные, не угадайте! Проверьте вашу новую настройку перед развертыванием и спите лучше!

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

Шаги для успешного тестирования

  • Строить планы

    Подумайте о том, что вы хотите проверить. и что вы ожидаете. Сколько трафика, по каким URL, с какой полезной нагрузкой? Определите параметры заранее, а не просто случайно попали в ваше приложение.

  • Подготовить

    Убедитесь, что ваши среды настолько изолированы, насколько это возможно: используйте одну и ту же среду для тестирования при каждом запуске теста. Хорошее руководство о том, как этого добиться, можно найти в этой книге о настройке сред PHP .

  • Анализировать и учиться

    Изучите что-нибудь из чисел и принимайте обоснованные решения. Результаты всегда должны оцениваться в их контексте: не спешите с выводами; проверь все хотя бы дважды.

Начало работы с осадой

Siege — отличный инструмент для тестирования и тестирования веб-приложений. Он имитирует одновременных пользователей, запрашивающих ресурсы по заданному URL-адресу (или нескольким URL-адресам), и позволяет пользователю тщательно настраивать параметры тестирования. Запустите siege --help мы рассмотрим некоторые из них подробно ниже.

Подготовка тестового приложения

С помощью Siege вы можете протестировать стабильность, производительность и улучшения приложения между изменениями кода (или инфраструктуры). Вы также можете использовать его, чтобы убедиться, что ваш веб-сайт WordPress может справиться с пиком, который вы ожидаете после публикации вирусной фотографии кошки, или для настройки и оценки преимуществ системы кэширования HTTP, такой как Varnish .

Для тестов в этой статье я буду использовать слегка измененное демонстрационное приложение Symfony, развернутое на одном узле Digital Ocean во Франкфурте, а SIEGE 4.0.2 — на втором узле Digital Ocean в Нью-Йорке.

Как я уже говорил ранее, крайне важно, чтобы приложение и тестовый сервер были изолированы, когда это возможно. Если вы запускаете какой-либо из них на локальном компьютере, вы не можете гарантировать ту же среду, потому что запущены другие процессы (почтовый клиент, инструменты обмена сообщениями, демоны), которые могут повлиять на производительность; даже с такими высококачественными виртуальными машинами, как Homestead Improved , доступность ресурсов не гарантируется на 100% (хотя эти изолированные виртуальные машины являются допустимым вариантом, если вы не хотите тратить деньги на этапе нагрузочного тестирования своего приложения).

Демо-приложение Symfony довольно простое и быстрое, когда используется из коробки. В реальной жизни мы имеем дело со сложными и медленными приложениями, поэтому я решил добавить два модуля на боковую панель одной страницы поста: последние посты (10 последних постов) и популярные посты (10 постов с наибольшим количеством комментариев). Сделав это, я добавил сложности в приложение, которое теперь запрашивает БД как минимум три раза. Идея состоит в том, чтобы получить как можно более реальную ситуацию. База данных заполнена 62 230 фиктивными статьями и ~ 1445 505 комментариями.

Изучение Основ

Запуск команды siege SOME-URL После первоначального сообщения …

 ** Preparing 25 concurrent users for battle.
The server is now under siege…

… Экран начнет заполняться информацией об отправленных запросах. Ваш немедленный рефлекс, вероятно, будет состоять в том, чтобы остановить выполнение, нажав CTRL + C

Прежде чем мы продолжим, следует помнить одну вещь при тестировании / тестировании веб-приложения. Подумайте о жизненном цикле одного HTTP-запроса, отправляемого на страницу блога демонстрационного приложения Symfony — /en/blog/ Сервер сгенерирует ответ HTTP со статусом 200 (ОК) и HTML в теле с содержимым и ссылками на изображения и другие ресурсы (таблицы стилей, файлы JavaScript,…). Веб-браузер обрабатывает эти ссылки и запрашивает все ресурсы, необходимые для отображения веб-страницы в фоновом режиме. Сколько всего HTTP-запросов нам нужно?

Чтобы получить ответ, попросим Siege выполнить один тест и проанализировать результат. У меня открыт журнал доступа моего приложения ( tail -f var/logs/access.logsiege -c=1 --reps=1 http://sfdemo.loc/en/blog/ По сути, я говорю Siege: «Запустите тестирование один раз (–reps = 1) с одним пользователем (-c = 1) для URL http: //sfdemo.loc/en/blog/». Я вижу запросы как в журнале, так и в выводе Siege.

  siege -c=1 --reps=1 http://sfdemo.loc/en/blog/

** Preparing 1 concurrent users for battle.
The server is now under siege...
HTTP/1.1 200     1.85 secs:   22367 bytes ==> GET  /en/blog/
HTTP/1.1 200     0.17 secs:    2317 bytes ==> GET  /js/main.js
HTTP/1.1 200     0.34 secs:   49248 bytes ==> GET  /js/bootstrap-tagsinput.min.js
HTTP/1.1 200     0.25 secs:   37955 bytes ==> GET  /js/bootstrap-datetimepicker.min.js
HTTP/1.1 200     0.26 secs:   21546 bytes ==> GET  /js/highlight.pack.js
HTTP/1.1 200     0.26 secs:   37045 bytes ==> GET  /js/bootstrap-3.3.7.min.js
HTTP/1.1 200     0.44 secs:  170649 bytes ==> GET  /js/moment.min.js
HTTP/1.1 200     0.36 secs:   85577 bytes ==> GET  /js/jquery-2.2.4.min.js
HTTP/1.1 200     0.16 secs:    6160 bytes ==> GET  /css/main.css
HTTP/1.1 200     0.18 secs:    4583 bytes ==> GET  /css/bootstrap-tagsinput.css
HTTP/1.1 200     0.17 secs:    1616 bytes ==> GET  /css/highlight-solarized-light.css
HTTP/1.1 200     0.17 secs:    7771 bytes ==> GET  /css/bootstrap-datetimepicker.min.css
HTTP/1.1 200     0.18 secs:     750 bytes ==> GET  /css/font-lato.css
HTTP/1.1 200     0.26 secs:   29142 bytes ==> GET  /css/font-awesome-4.6.3.min.css
HTTP/1.1 200     0.44 secs:  127246 bytes ==> GET  /css/bootstrap-flatly-3.3.7.min.css

Transactions:                  15 hits
Availability:              100.00 %
Elapsed time:                5.83 secs
Data transferred:            0.58 MB
Response time:                0.37 secs
Transaction rate:            2.57 trans/sec
Throughput:                0.10 MB/sec
Concurrency:                0.94
Successful transactions:          15
Failed transactions:               0
Longest transaction:            1.85
Shortest transaction:            0.16

Журнал доступа выглядит так:

 107.170.85.171 - - [04/May/2017:05:35:15 +0000] "GET /en/blog/ HTTP/1.1" 200 22701 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/main.js HTTP/1.1" 200 2602 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/bootstrap-tagsinput.min.js HTTP/1.1" 200 49535 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/bootstrap-datetimepicker.min.js HTTP/1.1" 200 38242 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/highlight.pack.js HTTP/1.1" 200 21833 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/bootstrap-3.3.7.min.js HTTP/1.1" 200 37332 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/moment.min.js HTTP/1.1" 200 170938 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /js/jquery-2.2.4.min.js HTTP/1.1" 200 85865 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/main.css HTTP/1.1" 200 6432 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/bootstrap-tagsinput.css HTTP/1.1" 200 4855 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/highlight-solarized-light.css HTTP/1.1" 200 1887 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/bootstrap-datetimepicker.min.css HTTP/1.1" 200 8043 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/font-lato.css HTTP/1.1" 200 1020 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/font-awesome-4.6.3.min.css HTTP/1.1" 200 29415 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/bootstrap-flatly-3.3.7.min.css HTTP/1.1" 200 127521 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"

Мы видим, что, хотя мы и сказали Siege протестировать URL-адрес один раз, было выполнено 15 транзакций (запросов). Если вам интересно, что такое транзакция, вы должны проверить страницу GitHub :

Транзакция характеризуется тем, что сервер открывает сокет для клиента, обрабатывает запрос, передает данные по проводам и закрывает сокет по завершении.

Таким образом, Siege не только отправит один HTTP-запрос GET для предоставленного URL-адреса, но и сгенерирует HTTP-запросы GET для всех связанных ресурсов, на которые ссылается ресурс по указанному URL-адресу. Мы все еще должны знать, что Siege не оценивает JavaScript, поэтому запросы AJAX здесь не включены. Также следует помнить, что браузеры могут кэшировать статические файлы (изображения, шрифты, файлы JS).

Это поведение можно изменить начиная с версии 4.0 , обновив файл конфигурации Siege, расположенный в ~/.siege/siege.confparser = false

Примечание. Поведение по умолчанию может отличаться в зависимости от используемой версии Seige или даже от инструмента. Если вы используете что-то отличное от Siege, проверьте, что именно он считает единым тестом (это один запрос для данного URL или запрос для данного URL и дополнительные запросы для всех его ресурсов?), Прежде чем перейти к выводы.

Из результатов теста, приведенного выше, мы видим, что Siege сгенерировал 15 запросов (транзакций) за ~ 6 секунд, что привело к 0,58 МБ переданных данных со 100% доступностью или 15/15 успешных транзакций — « Успешных транзакций — это количество раз, сервер вернул код менее 400. Соответственно, перенаправления считаются успешными транзакциями ».

Время ответа — это среднее время, необходимое для выполнения всех запросов и получения ответов. Скорость транзакций и пропускная способность говорят нам, какова емкость нашего приложения (какой объем трафика может обрабатывать наше приложение в данный момент времени).

Давайте повторим тест с 15 пользователями:

 siege --concurrent=15 --reps=1 sfdemo.loc/en/blog/

Transactions:                 225 hits
Availability:              100.00 %
Elapsed time:                6.16 secs
Data transferred:            8.64 MB
Response time:                0.37 secs
Transaction rate:           36.53 trans/sec
Throughput:                1.40 MB/sec
Concurrency:               13.41
Successful transactions:         225
Failed transactions:               0
Longest transaction:            1.74
Shortest transaction:            0.16

Увеличивая тестовую нагрузку, мы позволяем нашему приложению показать свою полную мощность. Мы видим, что наше приложение может очень хорошо обрабатывать один запрос от 15 пользователей на странице блога, со средним временем ответа 0,37 секунды. Осада по умолчанию задерживает запросы случайным образом в интервале от 1 до 3 секунд. Установив параметр --delay=N

совпадение

Параллельность, вероятно, является наиболее запутанным атрибутом результата, поэтому давайте объясним это. Документация гласит:

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

Из раздела FAQ мы можем увидеть, как рассчитывается параллелизм:

Параллельность — это общее количество транзакций, деленное на общее время, прошедшее с начала Таким образом, если мы завершили 100 транзакций за 10 секунд, наш параллелизм составил 10,00.

Еще одно отличное объяснение параллелизма доступно на официальном сайте :

Мы можем проиллюстрировать это на очевидном примере. Я запустил Siege против кластерного сайта с двумя узлами. Мой параллелизм был 6,97 . Затем я убрал узел и запустил тот же прогон на той же странице. Мой параллелизм вырос до 18,33 . В то же время мое время было продлено на 65% .

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

Тестирование производительности с Siege

Чтобы получить реальный обзор производительности нашего приложения, я буду запускать Siege в течение 5 минут с другим числом одновременно работающих пользователей и сравнивать результаты. Поскольку домашняя страница блога является простой конечной точкой с одним запросом к базе данных, в следующих тестах я буду тестировать отдельные страницы сообщений, поскольку они медленнее и сложнее.

 siege --concurrent=5 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.`

Пока запущены тесты, я могу взглянуть top MySQL усердно работает:

 %CPU %MEM     TIME+ COMMAND
96.3 53.2   1:23.80 mysqld

Это ожидалось, поскольку каждый раз, когда приложение отображает одну страницу публикации, оно выполняет несколько нетривиальных запросов к БД:

  1. Получить статью с соответствующими комментариями.
  2. Получить 10 лучших сообщений отсортировано по убыванию по времени публикации.
  3. Запрос SELECTCOUNT

Первый тест с пятью одновременными пользователями выполнен, и цифры не настолько впечатляющие:

 siege --concurrent=5 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.

Transactions:                1350 hits
Availability:              100.00 %
Elapsed time:              299.54 secs
Data transferred:           51.92 MB
Response time:                1.09 secs
Transaction rate:            4.51 trans/sec
Throughput:                0.17 MB/sec
Concurrency:                4.91
Successful transactions:        1350
Failed transactions:               0
Longest transaction:           15.55
Shortest transaction:            0.16

Siege удалось выполнить 1350 транзакций за 5 минут. Поскольку у нас 15 транзакций / загрузка страницы, мы можем легко рассчитать, что наше приложение могло обрабатывать 90 страниц в течение 5 минут или 18 загрузок страницы / 1 минуту или 0,3 загрузки страницы / секунду . Мы рассчитываем то же самое путем деления скорости транзакций на количество транзакций на странице 4,51 / 15 = 0,3.

Ну … это не такая большая пропускная способность, но, по крайней мере, теперь мы знаем, где находятся узкие места (запросы к БД), и у нас есть ссылка для сравнения после оптимизации нашего приложения.

Давайте запустим еще несколько тестов, чтобы увидеть, как наше приложение работает под большим давлением. На этот раз для одновременных пользователей установлено значение 10, и в течение первых нескольких минут тестирования мы видим множество ошибок HTTP 500: приложение начало разваливаться при немного большем трафике. Давайте теперь сравним, как приложение работает в осаде с 5, 10 и 15 одновременными пользователями.

 siege --concurrent=10 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.

Lifting the server siege…
Transactions:                 450 hits
Availability:               73.89 %
Elapsed time:              299.01 secs
Data transferred:           18.23 MB
Response time:                6.17 secs
Transaction rate:            1.50 trans/sec
Throughput:                0.06 MB/sec
Concurrency:                9.29
Successful transactions:         450
Failed transactions:             159
Longest transaction:           32.68
Shortest transaction:            0.16
 siege --concurrent=10 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.

Transactions:                   0 hits
Availability:                0.00 %
Elapsed time:              299.36 secs
Data transferred:            2.98 MB
Response time:                0.00 secs
Transaction rate:            0.00 trans/sec
Throughput:                0.01 MB/sec
Concurrency:               14.41
Successful transactions:           0
Failed transactions:             388
Longest transaction:           56.85
Shortest transaction:            0.00

не осадное сравнение-нет-кэш

Сравнение результатов осады с параллелизмом, установленным на 5, 10 и 15

Обратите внимание, как растет параллелизм при снижении производительности нашего приложения. Приложение было полностью мертво в осаде с 15 одновременными пользователями — то есть 15 диких пользователей — все, что нужно, чтобы разрушить вашу крепость! Мы инженеры, и мы не собираемся оплакивать проблемы, мы собираемся их решать!

Помните, что эти тесты автоматизированы, и мы подвергаем наше приложение давлению. В действительности, пользователи не просто нажимают кнопку обновления, как маньяки, они обрабатывают (то есть читают) содержимое, которое вы представляете, и поэтому существует некоторая задержка между запросами.

Кеш на помощь

Теперь мы знаем о некоторых проблемах с нашим приложением — мы слишком часто запрашиваем базу данных. Нужно ли нам получать список популярных и последних статей из базы данных по каждому запросу? Вероятно, нет, поэтому мы можем добавить слой кэша на уровне приложения (например, Redis) и кэшировать список популярных и последних статей. Эта статья не о кэшировании (для этого, посмотрите эту ), поэтому мы собираемся добавить полный кеш ответов для отдельной страницы поста.

Демонстрационное приложение уже поставляется с включенным Symfony HTTP Cache , нам просто нужно установить заголовок TTL для ответа HTTP, который мы возвращаем.

 $response->setTtl(60);

Давайте повторим тесты с 5, 10 и 15 одновременными пользователями и посмотрим, как добавление кэша влияет на производительность. Очевидно, мы ожидаем, что производительность приложения увеличится после того, как кеш нагреется. Мы также ждем как минимум 1 минуту, чтобы срок действия кэша истек между тестами.

Примечание: будьте осторожны с кэшированием, особенно с IRT-защищенными областями веб-приложения ( пример упс ), и всегда помните, что это одна из двух сложных вещей в информатике .

Результаты: добавление 60-х кеша значительно улучшило стабильность и производительность приложения. Посмотрите на результаты в таблице и диаграммах ниже.

С = 5 С = 10 С = 15
операции 4566 просмотров 8323 просмотров 12064 хитов
Доступность 100,00% 100,00% 100,00%
Пройденное время 299,86 с 299,06 с 299,35 с
Данные переданы 175,62 МБ 320,42 МБ 463,78 МБ
Время отклика 0,31 с 0,34 с 0,35 с
Коэффициент транзакций 15,23 транс / сек 27,83 транс / сек 40.30 транс / сек
пропускная способность 0,59 МБ / с 1,07 МБ / с 1,55 МБ / с
совпадение 4,74 9,51 14,31
Успешные транзакции 4566 8323 12064
Неудачные транзакции 0 0 0
Самая длинная транзакция 4,32 5,73 4,93

Осада одного сообщения URL с HTTP кешем ttl, установленным на 60 секунд

Транзакции до и после добавления кеша

Приложение могло обрабатывать больше транзакций с кешем

Время ответа до и после добавления кеша

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

Настоящее чувство

Если вы хотите по-настоящему ощутить использование своего приложения, когда оно находится под давлением, вы можете запустить Siege и использовать свое приложение в браузере. Siege окажет давление на приложение, и вы сможете ощутить реальный пользовательский опыт. Несмотря на то, что это субъективный метод, я думаю, что это является открытием для большинства разработчиков. Попытайся.

Альтернативные инструменты

Siege — не единственный инструмент для нагрузочного тестирования и тестирования веб-приложений. Давайте быстро протестируем приложение с помощью ab.

Ab

ab или Apache HTTP-сервер сравнительного анализа является еще одним отличным инструментом. Он хорошо документирован и имеет много опций, хотя он не поддерживает использование файлов URL, синтаксический анализ и запрос ссылочных ресурсов, а также случайные задержки, как это делает Siege.

Если я запускаю ab на одной странице поста (без кеша), результат:

 ab -c 5 -t 300 http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking sfdemo.loc (be patient)
Finished 132 requests


Server Software:        Apache/2.4.18
Server Hostname:        sfdemo.loc
Server Port:            80

Document Path:          /en/blog/posts/vero-iusto-fugit-sed-totam.
Document Length:        23291 bytes

Concurrency Level:      5
Time taken for tests:   300.553 seconds
Complete requests:      132
Failed requests:        0
Total transferred:      3156000 bytes
HTML transferred:       3116985 bytes
Requests per second:    0.44 [#/sec] (mean)
Time per request:       11384.602 [ms] (mean)
Time per request:       2276.920 [ms] (mean, across all concurrent requests)
Transfer rate:          10.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       81   85   2.0     85      91
Processing:  9376 11038 1085.1  10627   13217
Waiting:     9290 10953 1084.7  10542   13132
Total:       9463 11123 1085.7  10712   13305

Percentage of the requests served within a certain time (ms)
  50%  10712
  66%  11465
  75%  12150
  80%  12203
  90%  12791
  95%  13166
  98%  13302
  99%  13303
 100%  13305 (longest request)

И после того, как мы включим кеш, результат будет:

 ab -c 5 -t 300 http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking sfdemo.loc (be patient)
Completed 5000 requests
Finished 5373 requests


Server Software:        Apache/2.4.18
Server Hostname:        sfdemo.loc
Server Port:            80

Document Path:          /en/blog/posts/vero-iusto-fugit-sed-totam.
Document Length:        23351 bytes

Concurrency Level:      5
Time taken for tests:   300.024 seconds
Complete requests:      5373
Failed requests:        0
Total transferred:      127278409 bytes
HTML transferred:       125479068 bytes
Requests per second:    17.91 [#/sec] (mean)
Time per request:       279.196 [ms] (mean)
Time per request:       55.839 [ms] (mean, across all concurrent requests)
Transfer rate:          414.28 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       81   85   2.1     85     106
Processing:   164  194 434.8    174   13716
Waiting:       83  109 434.8     89   13632
Total:        245  279 434.8    259   13803

Percentage of the requests served within a certain time (ms)
  50%    259
  66%    262
  75%    263
  80%    265
  90%    268
  95%    269
  98%    272
  99%    278
 100%  13803 (longest request)

Мне нравится, как ab показывает разбивку по времени и статистику в отчете! Я сразу вижу, что 50% наших запросов были обработаны в течение 259 мс (против 10,712 мс без кеша), и 99% из них были менее 278 мс (против 13,305 мс без кеша), что является приемлемым. Опять же, результаты теста оцениваются в их контексте и относительно предыдущего состояния.

Расширенное нагрузочное тестирование с осадой

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

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

Шаг 1: спланируйте тест

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

Я бы создал файл URL на основе данных из моего аналитического инструмента или файла журнала доступа к серверу. Можно использовать инструменты анализа журналов доступа, такие как доступ к веб-серверу Log Parser, для анализа журналов доступа Apache и создания списка URL-адресов, отсортированных по популярности. Я бы взял верхние N (20, 50, 100…) URL-адресов и поместил их в файл. Если некоторые URL-адреса (например, целевая страница или вирусная статья) посещаются чаще, чем другие, мы должны отрегулировать вероятности так, чтобы осада запрашивала эти URL-адреса чаще.

Допустим, у нас есть следующие URL с таким количеством посещений за последние N дней:

  • Целевая страница / Домашняя страница — 30.000
  • Статья А — 10.000
  • Статья B — 2.000
  • Статья С — 50 000
  • О нас — 3.000

Мы можем нормализовать количество посещений и получить такой список:

  • Целевая страница / Домашняя страница — 32% (30.000 / 95.000)
  • Статья А — 11% (10.000 / 95.000)
  • Статья B — 2% (2.000 / 95.000)
  • Статья С — 52% (50 000/95 000)
  • О нас — 3% (3.000 / 95.000)

Теперь мы можем создать файл URL с 100 URL-адресами (строками) с 32 x URL-адресами домашней страницы, 52 x URL-адресами Article C и т. Д. Вы можете перетасовать конечный файл, чтобы получить больше случайности, и сохранить его.

Возьмите среднее время сеанса и количество страниц за сеанс из своего аналитического инструмента, чтобы вычислить среднюю задержку между двумя запросами. Если средняя продолжительность сеанса составляет 2 минуты, а пользователи посещают в среднем по 8 страниц за сеанс, простая математика дает нам среднюю задержку в 15 секунд (120 секунд / 8 страниц = 15 секунд / страница).

Наконец, мы отключаем синтаксический анализ и запрос ресурсов, так как я кеширую статические файлы в рабочей среде и обслуживаю их с другого сервера. Как упоминалось выше, анализатор отключается установкой parser = false~/.siege/siege.conf

Шаг 2. Подготовка и запуск тестов

Поскольку сейчас мы имеем дело со случайностью, было бы неплохо увеличить продолжительность теста, чтобы получить более релевантные результаты. Я буду использовать Siege в течение 20 минут с максимальной задержкой, равной 15 секундам и 50 одновременным пользователям. Я протестирую домашнюю страницу блога и 10 статей с разными вероятностями.

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

 siege -b --file=urls.txt -t 30S -c 1

Теперь мы готовы подвергнуть наше приложение серьезному давлению. Если мы используем ключ --internet Без переключателя Siege выбирает URL-адреса последовательно. Давайте начнем:

 siege --file=urls.txt --internet --delay=15 -c 50 -t 30M

Lifting the server siege...
Transactions:               10931 hits
Availability:               98.63 %
Elapsed time:             1799.88 secs
Data transferred:          351.76 MB
Response time:                0.67 secs
Transaction rate:            6.07 trans/sec
Throughput:                0.20 MB/sec
Concurrency:                4.08
Successful transactions:       10931
Failed transactions:             152
Longest transaction:           17.71
Shortest transaction:            0.24

Или с 60 одновременными пользователями во время осады:

 siege --file=urls.txt --delay=15 -c 60 -t 30M
Transactions:               12949 hits
Availability:               98.10 %
Elapsed time:             1799.20 secs
Data transferred:          418.04 MB
Response time:                0.69 secs
Transaction rate:            7.20 trans/sec
Throughput:                0.23 MB/sec
Concurrency:                4.99
Successful transactions:       12949
Failed transactions:             251
Longest transaction:           15.75
Shortest transaction:            0.21

Мы видим, что модифицированное демо-приложение Symfony (с включенным кешем) хорошо справляется с тестами. В среднем он мог обслуживать 7,2 запроса в секунду в течение 0,7 секунды (обратите внимание, что мы используем одноядерный дроплет Digital Ocean с только 512 МБ ОЗУ). Доступность составила 98,10% из-за сбоя 251 из 13.200 запросов (соединение с БД несколько раз не удавалось).

Отправка данных с помощью Siege

До сих пор мы отправляли только HTTP-запросы GET, которых обычно достаточно, чтобы получить представление о производительности приложения. Часто имеет смысл отправлять данные во время нагрузочных тестов (например, тестирование конечных точек API). С Siege вы можете легко отправлять данные на конечную точку:

 siege --reps=1 -c 1 'http://sfdemo.loc POST foo=bar&baz=bash'

Вы также можете отправить данные в формате JSON. Используя параметр --content-type

 siege --reps=1 -c 1 --content-type="application/json" 'http://sfdemo.loc POST {"foo":"bar","baz":"bash"}'

Мы также можем изменить пользовательский агент по умолчанию с помощью --user-agent="MY USER AGENT"--header="MY HEADER VALUE"

Siege также может читать данные полезной нагрузки из файла:

 cat payload.json
{
  "foo":"bar",
  "baz":"bash"
}

siege --reps=1 -c 1 --content-type="application/json" 'http://sfdemo.loc POST < payload.json'

Вы также можете отправлять куки в тестах, используя опцию --header

 siege --reps=1 -c 1 --content-type="application/json" --header="Cookie: my_cookie=abc123" 'http://sfdemo.loc POST < payload.json'

Вывод

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

Это всегда хорошая идея, чтобы автоматизировать процесс тестирования (простой скрипт bash сделает работу) и визуализировать результаты. Я обычно запускаю несколько процессов Siege в параллельном тестировании конечных точек только для чтения (т. Е. Отправляю только запросы GET) с высокой скоростью и отправляю данные (т. Е. Публикую комментарии, аннулирую кэш и т. Д.) С более низкой скоростью, в соответствии с реальными коэффициентами жизни , Поскольку вы не можете указать динамические полезные нагрузки в одном тесте Siege, вы можете установить большую задержку между двумя запросами и запустить больше команд Siege с различными параметрами.

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