Всем привет! Меня зовут Андрей Попов, я Middle QA Engineer Auto-test в Утконос Онлайн. В этой статье хочу поделиться, почему мы выбрали Apache JMeter для нагрузочного тестирования, как выглядит этот инструмент, для чего он был нам нужен, и как мы используем его для нестандартных задач. Поехали.
Почему Apache JMeter
Что из себя представляет
Для чего нам понадобился Jmeter
Процесс настройки Jmeter для нагрузочного тестирования
Нестандартные задачи, которые мы решаем с помощью Jmeter
API тесты
С какой проблемой мы столкнулись, и возможные пути ее решения
Почему Apache JMeter
Для себя мы увидели шесть плюсов в этом инструменте, поэтому остановили выбор на нем.
Кроссплатформенность. Jmeter может быть запущен на любой ОС с установленной Java.
GUI — в JMeter графический интерфейс и, как следствие, низкий порог вхождения.
Описать простые сценарии может любой тестировщик, даже без знания языков. Кроме того, в JMeter гибкая настройка сценариев. Для нас это круто, поскольку мы строим достаточно сложные сценарии, берем значения из ответов, обрабатываем всевозможными способами и пробрасываем в следующие запросы, попутно прикручивая дополнительную логику.
Есть много плагинов, как официальных, так и кастомных. Для расширения функционала не нужно прибегать к написанию своих скриптов — вероятнее всего до вас их кто-то уже сделал.
Инструмент долгое время на рынке, поэтому по нему есть большое количество документации, поддержка сообщества, примеры практического использования — Ютуб, гайды как для опытных пользователей, так и для новичков. Легко изучить и начать работу.
Бесплатный — очень приятный пункт.
Что из себя представляет
В левой части интерфейса Jmeter располагается тест-план со всеми его элементами. Сценарии создаются добавлением этих элементов. Во второй части просто конфигурируют наши элементы. Интерфейс на первый взгляд староват, зато интуитивно понятный — это позволяет начать пользоваться им достаточно быстро.
Для чего нам понадобился Jmeter
Первая задача, которая перед нами стояла — определить, какой клиентский поток выдержит наш продукт — при каком количестве запросов в секунду наши сервера смогут оставаться стабильными. Еще хотелось постоянно наблюдать за производительностью системы и держать при себе ответ на вопрос: «Выдержим ли мы следующую Черную пятницу или Новый год?»
Что сделали первым делом:
Когда мы начали работать с Jmeter, провели нагрузочное тестирование. Поняли, что близки к пику производительности, и высокий сезон, скорее всего, не выдержим. Начали выявлять узкие места, создали задачи на оптимизацию и приступили к работе.
Оптимизировали эти узкие места, исправили основные проблемы. Нагрузка значительно упала, сервер стал дышать легче — мы увидели, что движемся в правильном направлении и продолжили работу.
В результате получили то, что ожидали: количество пользователей увеличилось в два раза, при этом сервера работали в нормальном режиме и даже был запас мощности.
В настоящий момент мы используем Jmeter с теми же целями — идентифицируем проблемы, создаем задачи на оптимизацию, а также в альтернативных целях, про которые я расскажу чуть позже в этой статье.
Процесс настройки Jmeter для нагрузочного тестирования
Чтобы построить правильный сценарий для нагрузки, мы обратились к системам сбора и аналитики данных — ELK и AppDynamics и построили профиль, максимально приближенный к реальному. Считывалась частота каждого запроса относительно друг друга.
Слева на изображении — методы: первый называется «500 раз в минуту», второй — «100 раз в минуту». Соответственно, в сценарий мы добавляем пять запросов к первому методу и один запрос ко второму. Точно также поступим с третьим методом и запустим все это в несколько потоков. Слева на графике видим, что соотношение частоты вызова данных методов сохраняется. Таким образом мы достаточно точно имитируем пользовательскую нагрузку.
Если у вас нет возможности мониторить какие-то пользовательские запросы, можно прибегнуть к расширению для браузера Blazemeter. Мы тоже использовали его одно время. Мы обратились к аналитике клиентского пути, выяснили пользовательское поведение на сайте и воспроизвели его вручную. Здесь тоже все достаточно просто и удобно: нужно установить расширение для браузера, нажать кнопку «запись», выполнить необходимое действие на своем сайте, остановить запись и сохранить в JMX формате — он подходит для Jmeter.
Запись сценария занимает минимум времени, а на выходе получаем готовый файл для нагрузки. Сам Jmeter умеет записывать такие сценарии, но мы использовали Blazemeter, так как это оказалось быстрее и проще.
По результатам теста Jmeter формирует дашборд в виде HTML:
Здесь показан график времени ответа, на котором можно увидеть, что один из API методов выбивается из общей массы и отвечает дольше остальных. Мы исследуем, почему такие проблемы возникают, и создаем задачи, чтобы их исправить.
Для удобства мы подняли Apache сервер для доступа к этому отчету из корпоративной сети. Таким образом заинтересованные пользователи могут без проблем заходить и получать какую-то информацию о результатах нагрузки: доступны всевозможные сводные таблицы по всем запросам, графики по времени, пропускной способности, задержки, количество запросов — и все это в разном представлении.
Помимо общих данных, которые мы получаем по результатам нагрузки, обращаем внимание на каждый метод: прикручиваем всевозможные ассерты, смотрим на время ответа, ошибки, и на основании этого делаем выводы о работе конкретных API методов.
Сравнивая результаты от релиза к релизу, можно сделать вывод о том, какие методы мы действительно улучшили, какие стали медленнее и требуют доработки. При обнаружении проблем они анализируются, и выпускаются фиксы. Это можно было бы сделать с помощью систем мониторинга, но далеко не все проблемы всплывают при стандартной нагрузке, а мы стараемся выявить проблемы еще до того, как они появились в боевой среде.
Все, что я перечислил выше — это стандартное использование JMeter. В какой-то момент мы поняли, что он может нам помочь с решением рутинных задач, для которых изначально не предназначен.
Нестандартные задачи, которые мы решаем с помощью Jmeter
Сразу начнем с примера из реальной жизни. Задача — нужно зарегистрировать 1000 пользователей, но не просто добавить какие-то данные в базу данных, а пройти весь путь регистрации через API.
Путем несложных манипуляций получаем сценарий, который читает из личного документа связку имени, почты, пароля и телефона и имитирует регистрацию наших пользователей. Можно было бы сделать это на любом языке, но с помощью нашего инструмента это все делается, допустим, в 100 потоков, что значительно ускоряет процесс.
Еще один пример — подобным образом мы начали тестировать создание заказов.
Мы брали тестовых пользователей из первой таблицы, логинились и проверяли, есть ли у них в профиле адрес. Если не было, то добавляли из второй таблицы, из третьей добавляли всевозможные товары, и точно также делали это в несколько потоков. Таким образом, мы создавали заказы. Плюс записывали номера заказов в отдельную таблицу для дальнейшего анализа.
Все то же самое можно было бы сделать без всевозможных таблиц, просто добавив все данные в тест-план Jmeter — это всего лишь 1 файл, который мы можем передавать другому тестировщику — он запустит тесты у себя и точно также будет смотреть на результаты и редактировать.
API тесты
Jmeter имеет достаточно гибкую настройку ассертов, переменные, регулярные выражения, парсинг JSON-ов и т.д.. Вы можете полноценно писать в нем API тесты. Пример простого API теста:
Мы выводим переменную для удобства в корень тест-плана, меняя ее значение, и можем прогонять наш тест на тестовом контуре или на проде. Создаем GET запрос по пути /posts и подставляем переменную SRV_NAME, которую объявили ранее.
К этому же запросу прикручиваем JSon Extractor, используя JSon Path получаем User ID и создаем переменную с соответствующим именем.
Используем нашу новую переменную в следующем запросе, поставив ее в Path.
Ко второму запросу мы тоже добавим ассерт, в котором укажем путь, используя JSon Path, expression и ожидаемое значение.
Получаем результат проверки. Jmeter показал нам не только завалившийся ассерт, но и дал информацию о том, что ожидалось, а что пришло на самом деле.
Так мы достаточно быстро написали простой API тест. Причем не нужно прикручивать никакие репортеры, так как Jmeter умеет строить дашборд, о котором мы уже говорили выше. И никаких языков программирования знать не нужно.
Это то, как мы используем Jmeter в работе.
С какой проблемой мы столкнулись, и возможные пути ее решения
Применять нагрузочные тесты после каждого релиза — это здорово, но у нас функциональность системы зависит от многих факторов — внешних и внутренних, изменений конфигурации, обновлений, незначительных правок в микросервисах, с которыми общается наше приложение — все они могут повлиять на работу продукта в целом. Чтобы идентифицировать проблемы как можно раньше, нужно прогонять тесты как можно чаще. В связи с этим мы решили запускать нагрузочные тесты в GitLab CI.
Вся CI инфраструктура у нас поддерживается DevOps инженерами, от нас нужны были только docker-образ, Java, Jmeter и тест-план. Настроили запуск по расписанию и публикации отчета — и готово.
Для тех, кто использует Jenkins, есть перфоманс-плагин, который позволяет также легко настроить Jenkins на работу с Jmeter. Настраивать публикацию и отчеты в Jenkins не нужно, он сам умеет строить графики и сравнивать результаты предыдущего прогона с текущим. Также есть сводная таблица, в которой отображены все прогоны всех билдов в вашем текущем проекте:
Здесь мы столкнулись с первой достаточно распространенной проблемой Jmeter — это ошибка в Out Of Memory, нехваткой памяти. Для использования сложных сценариев, ассертов он потребляет достаточно много памяти, и здесь мы нашли ряд решений, которые предлагает официальная документация.
Первым делом запускаем Jmeter с параметрами для увеличения размера кучи.
В большинстве случаев мы также знаем данные, на которые будем смотреть, поэтому сразу можно отключить ненужное.
Есть много способов передавать значения внутри теста — нужно попробовать разные и выбрать для себя менее требовательные, оптимальные.
Добавлять ассерты только там, где это необходимо — чем их меньше, тем проще будет Jmeter.
Можно запускать JVM в режиме сервера с аргументом server — это переключает JVM в серверный режим с оптимизацией параметров времени выполнения. Сам Jmeter будет стартовать немного медленнее, но общая производительность будет выше.
Отдельная тема со своими нюансами и бесконечными обсуждениями — это сборщик мусора: можно поэкспериментировать с его настройками.
Следуя этим рекомендациям, мы добились стабильной работы сценариев без ошибок. Если ничего не помогает, и мы все равно упираемся в мощности железа, то Jmeter может нам предложить распределенный запуск. Можно запускать сценарии с одной машины, а он подключит остальные, что позволяет нам использовать ресурсы удаленных машин для достаточно сложных и тяжелых сценариев.
На сегодняшний день нам хватает возможностей и производительности Jmeter. Единственную ошибку, с которой мы столкнулись, я описал выше. Также инструмент подойдет для тестирования надежности и стресс-тестов. Огромным плюсом был быстрый переход на JMeter благодаря большому количеству документации в свободном доступе — нам нужно было начать тестировать быстро и обучить этому инструменту большое количество тестировщиков — все прошло достаточно гладко и просто.
Если у вас есть вопросы по использованию JMeter — задавайте в комментариях.
Комментарии (6)
mSnus
17.03.2022 02:05Спасибо! А как вы собирали метрики, каким-то отдельным инструментом?
Somalil Автор
17.03.2022 09:59+1При запуске в режиме с графическим интерфейсом метрики собираются путем добавление в тест план слушателей (Listeners). Для того, чтобы получить HTML отчет, я запускаю Jmeter в NonGUI режиме(не забудьте выключить всех слушателей в тест плане) и пасую флаг ”-e” для генерации отчета. Вот пример команды, которую необходимо выполнить в командной строке(не забудьте перейти в директорию bin, где хранится ваш jmeter):
sh jmeter -n -t /Путь/до/тест/плана/в/формате.jmx -l /Путь/куда/jmeter/положит/результирующий/файл.csv -e -o /Путь/куда/jmeter/положит/HTMLreport
-n: non GUI mode (запуск Jmeter без графической оболочки)
-t: location of jmeter script(путь, по которому лежит ваш тест план в формате jmx)
-l: location of the result file(путь, куда jmeter положит файл с результатми теста, название файла придумываете сами)
-e: generate HTML report(говорим джиметру сформировать HTML репорт из файла с результатами теста, джиметр сам знает где он лежит)
-o: output folder(произвольный путь, куда джиметр положит HTML отчет)
Taumer
17.03.2022 10:37+2Также во время прогона сценария jmeter умеет складывать метрики, например, в InfluxDB, откуда потом можно смотреть на красивые графики в Grafana
https://jmeter.apache.org/usermanual/realtime-results.html
iridiumhawk
Спасибо за статью! Случайно на нее сегодня наткнулся и оказалось это именно то, что мне нужно для автоматического нагрузочного тестирования страниц с большим объемом SQL-запросов.
Уже поиспользовал JMeter и возникло пару вопросов:
1. Параметр Rump-up period (Thread Group) - за что отвечает? Какой-то разогрев? Как это работает и какое значение оптимально использовать по вашему опыту?
2. Сколько Threads можно запустить одновременно в дефолтной настройке (без тюнинга)? По опыту на какие ограничения стоит рассчитывать?
Taumer
Я не автор, но тоже имею немного опыта в нагрузочном тестировании с jmeter.
1) Rump-up period - время в секундах, за которое jmeter должен стартовать потоки этого Thread Group.
Сам по себе Thread Group не очень гибкий инструмент, лучше притащить что-нибудь такое: https://jmeter-plugins.org/wiki/UltimateThreadGroup/
2) Зависит от сценария. В моем случае jmeter загибался при ~1300 тредах. Решилось добавлением памяти (параметры Xmx и Xms)
Somalil Автор
@Taumer Уже ответил на вопрос, спасибо! Немного подробностей для понимания:
1) Если вы устанавливаете количество пользователей (Threads) = 100, а Rump-up period = 20, то это будет значить, что jmeter запустит 100 потоков в течении 20 секунд, т.е. будет добавлять по 5 потоков в секунду (100/20=5).
2) Зависит от кол-ва слушателей, семплеров, и остальных элементов тест плана. При ошибках OutOfMemory добавьте ему выделяемой памяти и запускайте тест в режиме без GUI.