«1. Введение

Выбор правильного инструмента для работы может быть сложной задачей. В этом руководстве мы упростим это, сравнив три инструмента нагрузочного тестирования веб-приложений — Apache JMeter, Gatling и The Grinder — с простым REST API.

2. Инструменты нагрузочного тестирования

Во-первых, давайте быстро пробежимся по каждому из них.

2.1. Gatling

Gatling — это инструмент для нагрузочного тестирования, который создает тестовые сценарии в Scala. Рекордер Gatling генерирует тестовые сценарии Scala, что является ключевой функцией Gatling. Ознакомьтесь с нашим руководством «Введение в Gatling» для получения дополнительной информации.

2.2. JMeter

JMeter — это инструмент нагрузочного тестирования от Apache. Он предоставляет приятный графический интерфейс, который мы можем использовать для настройки. Уникальная функция, называемая логическими контроллерами, обеспечивает большую гибкость при настройке тестов в графическом интерфейсе.

Посетите наш учебник «Введение в JMeter», чтобы увидеть снимки экрана и дополнительные пояснения.

2.3. The Grinder

И наш последний инструмент, 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. Наш план тестирования

Далее нам нужны тестовые сценарии.

Чтобы получить справедливое сравнение, мы выполним одни и те же шаги автоматизации для каждого инструмента:

  1. Generate random customer account ids
  2. Post a transaction
  3. Parse the response for the random customer id and transaction id
  4. Query for a customer rewards account id with the customer id
  5. Parse the response for the rewards account id
  6. If no rewards account id exists then add one with a post
  7. Post the same initial transaction with updated rewards id using the transaction id
  8. Query for all transactions by rewards account id

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

3.3. Gatling

Для Gatling знакомство со Scala является преимуществом для разработчиков, поскольку Gatling API надежен и содержит множество функций.

Gatling 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 гибкость, которую обеспечивают сценарии. Кроме того, мы даже устанавливаем область действия для наших переменных!

<stringProp name="ThreadGroup.num_threads">100</stringProp>

Наша конфигурация для прогонов и пользователей в JMeter использует ThreadGroups:

«

«Просмотрите весь файл jmx в качестве ссылки. Хотя это и возможно, написание тестов в формате XML в виде файлов .jmx не имеет смысла с полнофункциональным графическим интерфейсом.

customerId = str(random.nextInt());
result = request1.POST("http://localhost:8080/transactions/add",
  "{"'"customerRewardsId"'":null,"'"customerId"'":"+ customerId + ","'"transactionDate"'":null}")
txnId = parseJsonString(result.getText(), "id")

3.5. The Grinder

Без функционального программирования Scala и графического интерфейса наш Jython-скрипт для The Grinder выглядит довольно просто. Добавьте несколько системных классов Java, и у нас будет намного меньше строк кода.

grinder.threads = 100
grinder.processes = 1
grinder.runs = 1000

Однако меньшее количество строк кода настройки теста уравновешивается потребностью в большем количестве кода обслуживания строк, такого как синтаксический анализ строк JSON. Кроме того, API HTTPRequest ограничен по функциональности.

В The Grinder мы определяем значения потоков, процессов и запусков во внешнем файле свойств:

Наш полный Jython-скрипт для The Grinder будет выглядеть следующим образом.

4. Тестовые запуски

4.1. Выполнение теста

Все три инструмента рекомендуют использовать командную строку для тестов с большой нагрузкой.

./gatling.sh

Для запуска тестов мы будем использовать Gatling версии 3.4.0 с открытым исходным кодом в качестве отдельного инструмента, JMeter 5.3 и The Grinder версии 3.

Gatling требует только наличия JAVA_HOME и GATLING_HOME. Для запуска Gatling мы используем:

./jmeter.sh -n -t TestPlan.jmx -l log.jtl

в каталоге GATLING_HOME/bin.

export CLASSPATH=/home/lore/Documents/grinder-3/lib/grinder.jar:$CLASSPATH
export GRINDERPROPERTIES=/home/lore/Documents/grinder-3/examples/grinder.properties

JMeter нужен параметр, чтобы отключить графический интерфейс для теста, как было предложено при запуске графического интерфейса для настройки:

Как и Gatling, Grinder требует, чтобы мы установили JAVA_HOME и GRINDERPATH. Однако ему также нужны еще несколько свойств:

java -classpath $CLASSPATH net.grinder.Console
java -classpath $CLASSPATH net.grinder.Grinder $GRINDERPROPERTIES

Как упоминалось выше, мы предоставляем файлgrinder.properties для дополнительной настройки, такой как потоки, запуски, процессы и хосты консоли.

Наконец, мы загружаем консоль и агентов с помощью:

Successful Requests Errors Total Test Time (s) Average Response Time (ms)  Mean Throughput
Gatling 500000 Requests 0 218s 42 2283 req/s
JMeter 499997 Requests 0 237s 46 2101 req/s
The Grinder 499997 Requests 0 221s 43 2280 req/s

4.2. Результаты тестов

В каждом тесте было выполнено 1000 прогонов со 100 пользователями/потоками. Давайте раскроем некоторые основные моменты:

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

Каждый инструмент также предоставляет дополнительную информацию в более удобном пользовательском интерфейсе.

Gatling сгенерирует отчет в формате HTML в конце выполнения, который содержит несколько графиков и статистических данных как для всего выполнения, так и для каждого запроса. Вот фрагмент отчета о результатах теста:

При использовании JMeter мы можем открыть графический интерфейс после запуска теста и создать отчет HTML на основе файла журнала, в котором мы сохранили результаты:

Отчет JMeter HTML также содержит разбивка статистики по запросу.

Наконец, консоль Grinder записывает статистику для каждого агента и запуска:

Gatling JMeter The Grinder
Project and Community 9 9 6
Performance 9 8 9
Scriptability/API 7 9 8
UI 9 8 6
Reports 9 7 6
Integration 7 9 7
Summary 8.3 8.3 7

Несмотря на то, что Grinder является высокоскоростным, это достигается за счет дополнительного времени разработки и меньшего разнообразия выходных данных.

    5. Резюме

Теперь пришло время бросить общий взгляд на каждый из инструментов нагрузочного тестирования.

    Gatling:

Надежный, отполированный инструмент для нагрузочного тестирования, который выводит красивые отчеты со сценариями Scala. Уровни поддержки Open Source и Enterprise для продукта

    JMeter:

Надежный API (через графический интерфейс) для разработки тестовых сценариев без требуется кодирование. Поддержка Apache Foundation и отличная интеграция с Maven.

The Grinder:

Инструмент быстрого нагрузочного тестирования для разработчиков, использующих Jython. необходимость, затем используйте The Grinder.

Если великолепно выглядящие интерактивные графики помогают показать прирост производительности в пользу изменений, используйте Gatling.

JMeter — это инструмент для сложной бизнес-логики или уровня интеграции со многими типами сообщений. Являясь частью Apache Software Foundation, JMeter предоставляет зрелый продукт и большое сообщество.

6. Заключение