1. Введение
Выбор правильного инструмента для работы может быть сложной задачей. В этом руководстве мы упростим это, сравнив три инструмента нагрузочного тестирования веб-приложений — Apache JMeter, Gatling и The Grinder — с простым REST API.
2. Инструменты нагрузочного тестирования
Во-первых, давайте быстро рассмотрим некоторые предыстории каждого из них.
2.1. Гатлинг
Gatling — это инструмент нагрузочного тестирования, который создает тестовые сценарии в Scala. Рекордер Gatling генерирует тестовые сценарии Scala, что является ключевой функцией Gatling. Ознакомьтесь с нашим руководством « Введение в Gatling » для получения дополнительной информации.
2.2. JMeter
JMeter — это инструмент нагрузочного тестирования от Apache. Он предоставляет приятный графический интерфейс, который мы можем использовать для настройки. Уникальная функция, называемая логическими контроллерами, обеспечивает большую гибкость при настройке тестов в графическом интерфейсе.
Посетите наш учебник « Введение в JMeter», чтобы получить скриншоты и дополнительные пояснения.
2.3. Измельчитель
И наш последний инструмент, The Grinder , предоставляет скриптовый движок, более основанный на программировании, чем два других, и использует Jython. Однако в The Grinder 3 есть функция записи сценариев.
Grinder также отличается от двух других инструментов тем, что позволяет использовать процессы консоли и агента. Эта функциональность позволяет процессу агента масштабировать нагрузочные тесты на нескольких серверах. Он специально рекламируется как инструмент нагрузочного тестирования, созданный для разработчиков, чтобы находить взаимоблокировки и замедления.
3. Настройка тестового примера
Далее, для нашего теста нам понадобится API. Наш функционал API включает в себя:
- добавить/обновить запись о наградах
- просмотреть одну/все записи о наградах
- связать транзакцию с записью вознаграждения клиента
- просмотр транзакций для записи вознаграждений клиентов
Наш сценарий:
В магазине проводится общенациональная распродажа с новыми и постоянными покупателями, которым нужны учетные записи для поощрения клиентов, чтобы сэкономить. API вознаграждений проверяет учетную запись вознаграждения клиента по идентификатору клиента .
Если учетная запись для вознаграждений не существует, добавьте ее, а затем свяжите с транзакцией.
После этого мы запрашиваем транзакции.
3.1. Наш REST API
Давайте кратко рассмотрим API, просмотрев некоторые заглушки методов:
@PostMapping(path="/rewards/add")
public @ResponseBody RewardsAccount addRewardsAcount(@RequestBody RewardsAccount body)
@GetMapping(path="/rewards/find/{customerId}")
public @ResponseBody Optional<RewardsAccount> findCustomer(@PathVariable Integer customerId)
@PostMapping(path="/transactions/add")
public @ResponseBody Transaction addTransaction(@RequestBody Transaction transaction)
@GetMapping(path="/transactions/findAll/{rewardId}")
public @ResponseBody Iterable<Transaction> findTransactions(@PathVariable Integer rewardId)
Обратите внимание на некоторые отношения, такие как запрос транзакций по идентификатору вознаграждения и получение учетной записи вознаграждения по идентификатору клиента .
Эти отношения вызывают некоторую логику и некоторый анализ ответов для создания нашего тестового сценария.
Тестируемое приложение также использует базу данных H2 в памяти для обеспечения устойчивости.
К счастью, все наши инструменты справляются с этим довольно хорошо, некоторые лучше, чем другие.
3.2. Наш план тестирования
Далее нам понадобятся тестовые скрипты.
Чтобы получить справедливое сравнение, мы выполним одинаковые шаги автоматизации для каждого инструмента:
- Создание случайных идентификаторов учетных записей клиентов
- Разместить транзакцию
- Проанализируйте ответ для случайного идентификатора клиента и идентификатора транзакции.
- Запрос идентификатора учетной записи вознаграждения клиента с идентификатором клиента
- Разобрать ответ для идентификатора учетной записи вознаграждения
- Если идентификатор учетной записи вознаграждения не существует, добавьте его с сообщением
- Опубликуйте ту же первоначальную транзакцию с обновленным идентификатором вознаграждения, используя идентификатор транзакции.
- Запрос всех транзакций по идентификатору учетной записи вознаграждения
Давайте подробнее рассмотрим шаг 4 для каждого инструмента. И обязательно ознакомьтесь с образцом для всех трех завершенных сценариев .
3.3. Гатлинг
Для Gatling знакомство со Scala является преимуществом для разработчиков, поскольку Gatling API надежен и содержит множество функций.
API Гатлинга использует подход DSL-строителя, как мы можем видеть на шаге 4:
.exec(http("get_reward")
.get("/rewards/find/${custId}")
.check(jsonPath("$.id").saveAs("rwdId")))
Особо следует отметить поддержку Gatling пути JSON, когда нам нужно прочитать и проверить ответ HTTP. Здесь мы возьмем идентификатор награды и сохраним его во внутреннем состоянии Гатлинга.
Кроме того, язык выражений Гатлинга упрощает динамические строки тела запроса:
.body(StringBody(
"""{
"customerRewardsId":"${rwdId}",
"customerId":"${custId}",
"transactionDate":"${txtDate}"
}""")).asJson)
Наконец, наша конфигурация для этого сравнения. 1000 прогонов задаются как повторение всего сценария, метод atOnceUsers
устанавливает потоки/пользователей:
val scn = scenario("RewardsScenario")
.repeat(1000) {
...
}
setUp(
scn.inject(atOnceUsers(100))
).protocols(httpProtocol)
Весь скрипт Scala доступен для просмотра в нашем репозитории Github.
3.4. JMeter
JMeter генерирует файл XML после настройки графического интерфейса. Файл содержит определенные объекты JMeter с заданными свойствами и их значениями, например:
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Add Transaction" enabled="true">
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Transaction Id Extractor" enabled="true">
Проверьте атрибуты testname
, они могут быть помечены, поскольку мы распознаем их в соответствии с логическими шагами, описанными выше. Возможность добавлять дочерние элементы, переменные и шаги зависимостей дает JMeter гибкость, которую обеспечивают сценарии. Кроме того, мы даже устанавливаем область действия для наших переменных!
Наша конфигурация для прогонов и пользователей в JMeter использует ThreadGroups
:
<stringProp name="ThreadGroup.num_threads">100</stringProp>
Просмотрите весь файл jmx
в качестве ссылки . Хотя это и возможно, написание тестов в формате XML в виде файлов .jmx
не имеет смысла с полнофункциональным графическим интерфейсом.
3.5. Измельчитель
Без функционального программирования Scala и графического интерфейса наш Jython-скрипт для The Grinder выглядит довольно просто. Добавьте несколько системных классов Java, и у нас будет намного меньше строк кода.
customerId = str(random.nextInt());
result = request1.POST("http://localhost:8080/transactions/add",
"{"'"customerRewardsId"'":null,"'"customerId"'":"+ customerId + ","'"transactionDate"'":null}")
txnId = parseJsonString(result.getText(), "id")
Однако меньшее количество строк кода настройки теста уравновешивается потребностью в большем количестве кода обслуживания строк, такого как анализ строк JSON. Кроме того, API HTTPRequest ограничен по функциональности.
С The Grinder мы определяем потоки, процессы и запускаем значения во внешнем файле свойств:
grinder.threads = 100
grinder.processes = 1
grinder.runs = 1000
Наш полный Jython-скрипт для The Grinder будет выглядеть так .
4. Тестовые прогоны
4.1. Выполнение теста
Все три инструмента рекомендуют использовать командную строку для тестов с большой нагрузкой.
Для запуска тестов мы будем использовать Gatling версии 3.4.0 с открытым исходным кодом в качестве отдельного инструмента, JMeter 5.3 и The Grinder версии 3 .
Gatling требует только, чтобы у нас были установлены JAVA_HOME
и GATLING_HOME
. Для выполнения Gatling используем:
./gatling.sh
в каталоге GATLING_HOME/bin.
JMeter нужен параметр, чтобы отключить графический интерфейс для теста, как было предложено при запуске графического интерфейса для настройки:
./jmeter.sh -n -t TestPlan.jmx -l log.jtl
Как и Gatling, Grinder требует, чтобы мы установили JAVA_HOME
и GRINDERPATH
. Однако ему нужны еще несколько свойств:
export CLASSPATH=/home/lore/Documents/grinder-3/lib/grinder.jar:$CLASSPATH
export GRINDERPROPERTIES=/home/lore/Documents/grinder-3/examples/grinder.properties
Как упоминалось выше, мы предоставляем файлgrinder.properties
для дополнительной настройки, такой как потоки, запуски, процессы и хосты консоли.
Наконец, мы загружаем консоль и агенты с помощью:
java -classpath $CLASSPATH net.grinder.Console
java -classpath $CLASSPATH net.grinder.Grinder $GRINDERPROPERTIES
4.2. Результаты теста
Каждый из тестов выполнял 1000 прогонов со 100 пользователями/потоками. Давайте раскроем некоторые из основных моментов:
| | **Успешные запросы** | **Ошибки** | **Общее время тестирования (с)** | **Среднее время отклика (мс)** | ** Средняя пропускная способность** |
| **Гатлинг** | 500000 запросов | 0 | 218с | 42 | 2283 запроса/с |
| **JMeter** | 499997 запросов | 0 | 237 с | 46 | 2101 запросов/с |
| **Измельчитель** | 499997 запросов | 0 | 221с | 43 | 2280 запросов/с |
Результаты показывают, что 3 инструмента имеют одинаковую скорость, при этом Гатлинг немного опережает другие 2, исходя из средней пропускной способности.
Каждый инструмент также предоставляет дополнительную информацию в более удобном пользовательском интерфейсе.
В конце выполнения Gatling сгенерирует отчет в формате HTML, который содержит несколько графиков и статистических данных как для всего выполнения, так и для каждого запроса. Вот фрагмент отчета о результатах теста:
При использовании JMeter мы можем открыть графический интерфейс после запуска теста и создать отчет в формате HTML на основе файла журнала, в котором мы сохранили результаты:
HTML-отчет JMeter также содержит разбивку статистики по запросам.
Наконец, консоль Grinder записывает статистику для каждого агента и запускает:
Хотя Grinder является высокоскоростным, он достигается за счет дополнительного времени разработки и меньшего разнообразия выходных данных.
5. Резюме
Теперь пришло время бросить общий взгляд на каждый из инструментов нагрузочного тестирования.
| | **Гатлинг** | **JMeter** | **Измельчитель** |
| Проект и сообщество | 9 | 9 | 6 |
| Производительность | 9 | 8 | 9 |
| Скриптовость/API | 7 | 9 | 8 |
| интерфейс | 9 | 8 | 6 |
| отчеты | 9 | 7 | 6 |
| Интеграция | 7 | 9 | 7 |
| **Резюме** | **8.3** | **8.3** | **7** |
Гатлинг:
- Надежный, отточенный инструмент для нагрузочного тестирования, который выводит красивые отчеты с помощью сценариев Scala.
- Уровни поддержки Open Source и Enterprise для продукта
JMeter:
- Надежный API (через графический интерфейс) для разработки тестовых сценариев без необходимости написания кода
- Поддержка Apache Foundation и отличная интеграция с Maven
Измельчитель:
- Инструмент быстрого нагрузочного тестирования для разработчиков, использующих Jython.
- Масштабируемость между серверами обеспечивает еще больший потенциал для крупных тестов.
Проще говоря, если вам нужны скорость и масштабируемость, используйте The Grinder.
Если великолепно выглядящие интерактивные графики помогают показать прирост производительности в пользу изменений, тогда используйте Gatling.
JMeter — это инструмент для сложной бизнес-логики или уровня интеграции со многими типами сообщений. Являясь частью Apache Software Foundation, JMeter предоставляет зрелый продукт и большое сообщество.
6. Заключение
В заключение мы видим, что инструменты имеют сопоставимые функциональные возможности в одних областях и превосходны в других. Правильный инструмент для правильной работы — это разговорная мудрость, которая работает в разработке программного обеспечения.
Наконец, API и скрипты можно найти на Github .