«1. Введение
В этом руководстве мы поймем, как выполнять распределенное тестирование производительности с помощью Gatling. В процессе мы создадим простое приложение для тестирования с помощью Gatling, поймем обоснование использования распределенного тестирования производительности и, наконец, поймем, какая поддержка доступна в Gatling для достижения этой цели.
2. Тестирование производительности с помощью Gatling
Тестирование производительности — это практика тестирования, которая оценивает скорость отклика и стабильность системы при определенной рабочей нагрузке. Существует несколько типов тестов, которые обычно относятся к тестированию производительности. К ним относятся нагрузочное тестирование, стресс-тестирование, тестирование выдержки, пиковое тестирование и некоторые другие. Все они имеют свои конкретные цели для достижения.
Однако одним из общих аспектов любого тестирования производительности является моделирование рабочих нагрузок, и такие инструменты, как Gatling, JMeter и K6, помогают нам в этом. Но, прежде чем мы продолжим, нам нужно приложение, которое мы можем протестировать на производительность.
Затем мы разработаем простую модель рабочей нагрузки для тестирования производительности этого приложения.
2.1. Создание приложения
В этом руководстве мы создадим простое веб-приложение Spring Boot с использованием Spring CLI:
spring init --dependencies=web my-application
Затем мы создадим простой REST API, который предоставляет случайное число по запросу: ~~ ~
@RestController
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping("/api/random")
public Integer getRandom() {
Random random = new Random();
return random.nextInt(1000);
}
}
В этом API нет ничего особенного — он просто возвращает случайное целое число в диапазоне от 0 до 999 при каждом вызове.
Запустить это приложение достаточно просто с помощью команды Maven:
mvnw spring-boot:run
2.2. Создание модели рабочей нагрузки
Если нам нужно развернуть этот простой API в рабочей среде, мы должны убедиться, что он может справиться с ожидаемой нагрузкой и по-прежнему обеспечивать желаемое качество обслуживания. Здесь нам нужно выполнить различные тесты производительности. Модель рабочей нагрузки обычно определяет один или несколько профилей рабочей нагрузки для имитации реального использования.
Для веб-приложения с пользовательским интерфейсом определение подходящей модели рабочей нагрузки может быть довольно сложной задачей. Но для нашего простого API мы можем сделать предположения о распределении нагрузки для нагрузочного тестирования.
Gatling предоставляет Scala DSL для создания сценариев для тестирования в моделировании. Давайте начнем с создания базового сценария для API, который мы создали ранее:
package randomapi
import io.gatling.core.Predef._
import io.gatling.core.structure.ScenarioBuilder
import io.gatling.http.Predef._
import io.gatling.http.protocol.HttpProtocolBuilder
class RandomAPILoadTest extends Simulation {
val protocol: HttpProtocolBuilder = http.baseUrl("http://localhost:8080/")
val scn: ScenarioBuilder = scenario("Load testing of Random Number API")
.exec(
http("Get Random Number")
.get("api/random")
.check(status.is(200))
)
val duringSeconds: Integer = Integer.getInteger("duringSeconds", 10)
val constantUsers: Integer = Integer.getInteger("constantUsers", 10)
setUp(scn.inject(constantConcurrentUsers(constantUsers) during (duringSeconds))
.protocols(protocol))
.maxDuration(1800)
.assertions(global.responseTime.max.lt(20000), global.successfulRequests.percent.gt(95))
}
Давайте обсудим основные моменты этой базовой симуляции:
-
Мы начнем с добавления некоторых необходимых импортов Gatling DSL Затем мы определим протокол HTTP. конфигурация Затем мы определяем сценарий с помощью одного запроса к нашему API Наконец, мы создаем определение моделирования для нагрузки, которую мы хотим внедрить; здесь мы вводим нагрузку, используя 10 одновременных пользователей в течение 10 секунд
Создать такой сценарий для более сложных приложений с пользовательским интерфейсом может быть довольно сложно. К счастью, Gatling поставляется с еще одной утилитой, называемой рекордером. Используя этот рекордер, мы можем создавать сценарии, позволяя ему прокси-взаимодействия между браузером и сервером. Он также может использовать файл HAR (HTTP-архив) для создания сценариев.
2.3. Выполнение моделирования
Теперь мы готовы выполнить наш нагрузочный тест. Для этого мы можем поместить наш файл моделирования «RandomAPILoadTest.scala» в каталог «%GATLING_HOME%/user-file/randomapi/». Обратите внимание, что это не единственный способ выполнить симуляцию, но, безусловно, один из самых простых.
Мы можем запустить Gatling, выполнив команду:
$GATLING_HOME/bin/gatling.sh
Это предложит нам выбрать симуляцию для запуска:
Choose a simulation number:
[0] randomapi.RandomAPILoadTest
При выборе симуляции она запустит симуляцию и сгенерирует вывод с сводка:
Далее генерируется отчет в формате HTML в каталоге «%GATLING_HOME%/results»:
Это только одна часть сгенерированного отчета, но мы можем ясно видеть сводку результата. Это довольно подробно и легко следовать.
3. Распределенное тестирование производительности
«Все идет нормально. Но, если вспомнить, целью тестирования производительности является имитация реальных рабочих нагрузок. Это может быть значительно выше для популярных приложений, чем нагрузка, которую мы видели в нашем тривиальном случае. Если мы заметим в сводке тестов, нам удалось достичь пропускной способности примерно 500 запросов в секунду. Для реального приложения, обрабатывающего реальные рабочие нагрузки, это может быть во много раз больше!
Как смоделировать такую рабочую нагрузку с помощью любого инструмента для повышения производительности? Реально ли достичь этих цифр, вводя нагрузку только с одной машины? Возможно нет. Даже если инструмент внедрения нагрузки может обрабатывать гораздо более высокие нагрузки, базовая операционная система и сеть имеют свои собственные ограничения.
Здесь мы должны распределить нашу инъекцию нагрузки по нескольким машинам. Конечно, как и любая другая модель распределенных вычислений, у этой есть свои проблемы:
-
Как мы распределяем рабочую нагрузку между участвующими машинами? Кто координирует их завершение и устранение возможных ошибок? Как мы собираем и обобщаем результаты для консолидированной отчетности?
Типичная архитектура распределенного тестирования производительности использует главные и подчиненные узлы для решения некоторых из этих проблем:
Но, опять же, что произойдет, если главный узел выйдет из строя? В задачи этого руководства не входит рассмотрение всех проблем, связанных с распределенными вычислениями, но мы, безусловно, должны подчеркнуть их последствия при выборе распределенной модели для тестирования производительности.
4. Распределенное тестирование производительности с помощью Gatling
Теперь, когда мы поняли необходимость распределенного тестирования производительности, мы посмотрим, как мы можем добиться этого с помощью Gatling. Режим кластеризации — это встроенная функция Gatling Frontline. Однако Frontline является корпоративной версией Gatling и недоступна с открытым исходным кодом. Frontline поддерживает развертывание инжекторов локально или у любого из популярных поставщиков облачных услуг.
Тем не менее, с открытым исходным кодом Gatling этого все же можно добиться. Но большую часть тяжелой работы нам придется делать самим. В этом разделе мы рассмотрим основные шаги для его достижения. Здесь мы будем использовать ту же симуляцию, которую мы определили ранее, для создания нагрузки с несколькими машинами.
4.1. Настройка
Мы начнем с создания компьютера-контроллера и нескольких удаленных рабочих компьютеров либо локально, либо в любом из облачных сервисов. Есть определенные предпосылки, которые мы должны выполнить на всех этих машинах. К ним относятся установка Gatling с открытым исходным кодом на всех рабочих машинах и настройка некоторых переменных среды контроллера.
Для достижения стабильного результата мы должны установить одну и ту же версию Gatling на всех рабочих машинах с одинаковой конфигурацией на каждой из них. Это включает в себя каталог, в который мы устанавливаем Gatling, и пользователя, которого мы создаем для его установки.
Давайте посмотрим, какие важные переменные среды нам нужно установить на машине контроллера:
HOSTS=( 192.168.x.x 192.168.x.x 192.168.x.x)
И давайте также определим список удаленных рабочих машин, с которых мы будем вводить нагрузку:
GATLING_HOME=/gatling/gatling-charts-highcharts-1.5.6
GATLING_SIMULATIONS_DIR=$GATLING_HOME/user-files/simulations
SIMULATION_NAME='randomapi.RandomAPILoadTest'
GATLING_RUNNER=$GATLING_HOME/bin/gatling.sh
GATLING_REPORT_DIR=$GATLING_HOME/results/
GATHER_REPORTS_DIR=/gatling/reports/
~ ~~ Некоторые переменные указывают на каталог установки Gatling и другие скрипты, которые нам нужны для запуска симуляции. В нем также упоминается каталог, в котором мы хотим создавать отчеты. Позже мы увидим, где их использовать.
Важно отметить, что мы предполагаем, что машины имеют Linux-подобную среду. Но мы можем легко адаптировать процедуру для других платформ, таких как Windows.
4.2. Распределение нагрузки
Здесь мы скопируем тот же сценарий на несколько рабочих машин, которые мы создали ранее. Может быть несколько способов скопировать симуляцию на удаленный хост. Самый простой способ — использовать scp для поддерживаемых хостов. Мы также можем автоматизировать это с помощью сценария оболочки:
for HOST in "${HOSTS[@]}"
do
scp -r $GATLING_SIMULATIONS_DIR/* [email protected]$HOST:$GATLING_SIMULATIONS_DIR
done
«
«Приведенная выше команда копирует содержимое каталога на локальном хосте в каталог на удаленном хосте. Для пользователей Windows PuTTY — лучший вариант, который также поставляется с PSCP (протокол защищенного копирования PuTTY). Мы можем использовать PSCP для передачи файлов между клиентами Windows и серверами Windows или Unix.
4.3. Выполнение симуляции
После того, как мы скопировали симуляции на рабочие машины, мы готовы их запустить. Ключом к достижению совокупного числа одновременных пользователей является выполнение имитации на всех хостах почти одновременно.
for HOST in "${HOSTS[@]}"
do
ssh -n -f [email protected]$HOST \
"sh -c 'nohup $GATLING_RUNNER -nr -s $SIMULATION_NAME \
> /gatling/run.log 2>&1 &'"
done
Мы снова можем автоматизировать этот шаг с помощью сценария оболочки:
Мы используем ssh для запуска моделирования на удаленных рабочих машинах. Здесь важно отметить, что мы используем опцию «без отчетов» (-nr). Это связано с тем, что на данном этапе нас интересует только сбор журналов, а позже мы создадим отчет, объединив журналы со всех рабочих машин.
4.4. Сбор результатов
for HOST in "${HOSTS[@]}"
do
ssh -n -f [email protected]$HOST \
"sh -c 'ls -t $GATLING_REPORT_DIR | head -n 1 | xargs -I {} \
mv ${GATLING_REPORT_DIR}{} ${GATLING_REPORT_DIR}report'"
scp [email protected]$HOST:${GATLING_REPORT_DIR}report/simulation.log \
${GATHER_REPORTS_DIR}simulation-$HOST.log
done
Теперь нам нужно собрать файлы журналов, сгенерированные симуляциями на всех рабочих машинах. Это, опять же, то, что мы можем автоматизировать с помощью сценария оболочки и выполнить с машины контроллера:
Команды могут показаться сложными для тех из нас, кто не очень хорошо разбирается в сценариях оболочки. Но это не так сложно, когда мы разбиваем их на части. Сначала мы подключаемся по ssh к удаленному хосту, перечисляем все файлы в каталоге отчетов Gatling в обратном хронологическом порядке и берем первый файл.
Затем мы копируем выбранный файл журнала с удаленного хоста на компьютер с контроллером и переименовываем его, добавляя имя хоста. Это важно, так как у нас будет несколько лог-файлов с одинаковыми именами с разных хостов.
4.5. Генерация отчета
mv $GATHER_REPORTS_DIR $GATLING_REPORT_DIR
$GATLING_RUNNER -ro reports
Наконец, мы должны сгенерировать отчет из всех файлов журналов, собранных в результате симуляций, выполненных на разных рабочих машинах. К счастью, всю тяжелую работу здесь делает Gatling:
Мы копируем все файлы журналов в стандартный каталог отчетов Gatling и выполняем команду Gating для создания отчета. Это предполагает, что у нас также установлен Gatling на компьютере с контроллером. Окончательный отчет похож на то, что мы видели ранее:
Здесь мы даже не осознаем, что на самом деле нагрузка была введена с нескольких машин! Мы можем ясно видеть, что количество запросов увеличилось почти втрое, когда мы использовали три рабочих машины. Однако в реальных сценариях масштабирование не будет таким идеально линейным!
5. Рекомендации по масштабированию тестирования производительности
Мы видели, что распределенное тестирование производительности — это способ масштабирования тестирования производительности для имитации реальных рабочих нагрузок. Теперь, хотя распределенное тестирование производительности полезно, у него есть свои нюансы. Следовательно, мы определенно должны попытаться максимально масштабировать возможности ввода нагрузки по вертикали. Только когда мы достигнем вертикального предела на одной машине, мы должны рассмотреть возможность использования распределенного тестирования.
Как правило, ограничивающими факторами для масштабирования внедрения нагрузки на машину являются базовая операционная система или сеть. Есть определенные вещи, которые мы можем оптимизировать, чтобы сделать это лучше. В Linux-подобных средах количество одновременных пользователей, которых может создать инжектор загрузки, обычно ограничено пределом открытых файлов. Мы можем увеличить его с помощью команды ulimit.
Еще один важный фактор касается ресурсов, доступных на машине. Например, инъекция нагрузки обычно потребляет много пропускной способности сети. Если пропускная способность сети машины является ограничивающим фактором, мы можем рассмотреть возможность ее модернизации. Точно так же процессор или память, доступные на машине, могут быть другими ограничивающими факторами. В облачных средах довольно легко переключиться на более мощную машину.
«Наконец, сценарии, которые мы включаем в нашу симуляцию, должны быть устойчивыми, поскольку мы не должны всегда предполагать положительный отклик под нагрузкой. Следовательно, мы должны быть осторожны и защищаться, записывая наши утверждения по ответу. Кроме того, мы должны свести количество утверждений к минимуму, чтобы сохранить наши усилия по увеличению пропускной способности.
6. Заключение
В этом руководстве мы рассмотрели основы выполнения распределенного теста производительности с помощью Gatling. Мы создали простое приложение для тестирования, разработали простую симуляцию в Gatling, а затем поняли, как мы можем выполнить это на нескольких машинах.