Всем привет! Меня зовут Андрей Попов, я Middle QA Engineer Auto-test в Утконос Онлайн. В этой статье хочу поделиться, почему мы выбрали Apache JMeter для нагрузочного тестирования, как выглядит этот инструмент, для чего он был нам нужен, и как мы используем его для нестандартных задач. Поехали.

  • Почему Apache JMeter

  • Что из себя представляет

  • Для чего нам понадобился Jmeter

  • Процесс настройки Jmeter для нагрузочного тестирования

  • Нестандартные задачи, которые мы решаем с помощью Jmeter

  • API тесты

  • С какой проблемой мы столкнулись, и возможные пути ее решения

Почему Apache JMeter

Для себя мы увидели шесть плюсов в этом инструменте, поэтому остановили выбор на нем.

  1. Кроссплатформенность. Jmeter может быть запущен на любой ОС с установленной Java.

  2. GUI — в JMeter графический интерфейс и, как следствие, низкий порог вхождения.

  3. Описать простые сценарии может любой тестировщик, даже без знания языков. Кроме того, в JMeter гибкая настройка сценариев. Для нас это круто, поскольку мы строим достаточно сложные сценарии, берем значения из ответов, обрабатываем всевозможными способами и пробрасываем в следующие запросы, попутно прикручивая дополнительную логику. 

  4. Есть много плагинов, как официальных, так и кастомных. Для расширения функционала не нужно прибегать к написанию своих скриптов — вероятнее всего до вас их кто-то уже сделал.

  5. Инструмент долгое время на рынке, поэтому по нему есть большое количество документации, поддержка сообщества, примеры практического использования — Ютуб, гайды как для опытных пользователей, так и для новичков. Легко изучить и начать работу.

  6. Бесплатный — очень приятный пункт. 

Что из себя представляет

JMETER
JMETER

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

Для чего нам понадобился Jmeter

Первая задача, которая перед нами стояла — определить, какой клиентский поток выдержит наш продукт — при каком количестве запросов в секунду наши сервера смогут оставаться стабильными. Еще хотелось постоянно наблюдать за производительностью системы и держать при себе ответ на вопрос: «Выдержим ли мы следующую Черную пятницу или Новый год?» 

Что сделали первым делом:

  1. Когда мы начали работать с Jmeter, провели нагрузочное тестирование. Поняли, что близки к пику производительности, и высокий сезон, скорее всего, не выдержим. Начали выявлять узкие места, создали задачи на оптимизацию и приступили к работе. 

  2. Оптимизировали эти узкие места, исправили основные проблемы. Нагрузка значительно упала, сервер стал дышать легче — мы увидели, что движемся в правильном направлении и продолжили работу.

  3. В результате получили то, что ожидали: количество пользователей увеличилось в два раза, при этом сервера работали в нормальном режиме и даже был запас мощности.

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

  1. Первым делом запускаем Jmeter с параметрами для увеличения размера кучи.

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

  3. Есть много способов передавать значения внутри теста — нужно попробовать разные и выбрать для себя менее требовательные, оптимальные. 

  4. Добавлять ассерты только там, где это необходимо — чем их меньше, тем проще будет Jmeter. 

  5. Можно запускать JVM в режиме сервера с аргументом server — это переключает JVM в серверный режим с оптимизацией параметров времени выполнения. Сам Jmeter будет стартовать немного медленнее, но общая производительность будет выше. 

  6. Отдельная тема со своими нюансами и бесконечными обсуждениями — это сборщик мусора: можно поэкспериментировать с его настройками. 

Следуя этим рекомендациям, мы добились стабильной работы сценариев без ошибок. Если ничего не помогает, и мы все равно упираемся в мощности железа, то Jmeter может нам предложить распределенный запуск. Можно запускать сценарии с одной машины, а он подключит остальные, что позволяет нам использовать ресурсы удаленных машин для достаточно сложных и тяжелых сценариев. 

На сегодняшний день нам хватает возможностей и производительности Jmeter. Единственную ошибку, с которой мы столкнулись, я описал выше. Также инструмент подойдет для тестирования надежности и стресс-тестов. Огромным плюсом был быстрый переход на JMeter благодаря большому количеству документации в свободном доступе — нам нужно было начать тестировать быстро и обучить этому инструменту большое количество тестировщиков — все прошло достаточно гладко и просто.

Если у вас есть вопросы по использованию JMeter — задавайте в комментариях.

Комментарии (6)


  1. iridiumhawk
    17.03.2022 00:06

    Спасибо за статью! Случайно на нее сегодня наткнулся и оказалось это именно то, что мне нужно для автоматического нагрузочного тестирования страниц с большим объемом SQL-запросов.

    Уже поиспользовал JMeter и возникло пару вопросов:
    1. Параметр Rump-up period (Thread Group) - за что отвечает? Какой-то разогрев? Как это работает и какое значение оптимально использовать по вашему опыту?
    2. Сколько Threads можно запустить одновременно в дефолтной настройке (без тюнинга)? По опыту на какие ограничения стоит рассчитывать?


    1. Taumer
      17.03.2022 09:36
      +2

      Я не автор, но тоже имею немного опыта в нагрузочном тестировании с jmeter.

      1) Rump-up period - время в секундах, за которое jmeter должен стартовать потоки этого Thread Group.

      Сам по себе Thread Group не очень гибкий инструмент, лучше притащить что-нибудь такое: https://jmeter-plugins.org/wiki/UltimateThreadGroup/

      2) Зависит от сценария. В моем случае jmeter загибался при ~1300 тредах. Решилось добавлением памяти (параметры Xmx и Xms)


    1. Somalil Автор
      17.03.2022 10:10
      +1

      @Taumer Уже ответил на вопрос, спасибо! Немного подробностей для понимания:

      1) Если вы устанавливаете количество пользователей (Threads) = 100, а Rump-up period = 20, то это будет значить, что jmeter запустит 100 потоков в течении 20 секунд, т.е. будет добавлять по 5 потоков в секунду (100/20=5).

      2) Зависит от кол-ва слушателей, семплеров, и остальных элементов тест плана. При ошибках OutOfMemory добавьте ему выделяемой памяти и запускайте тест в режиме без GUI.


  1. mSnus
    17.03.2022 02:05

    Спасибо! А как вы собирали метрики, каким-то отдельным инструментом?


    1. 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 отчет)


    1. Taumer
      17.03.2022 10:37
      +2

      Также во время прогона сценария jmeter умеет складывать метрики, например, в InfluxDB, откуда потом можно смотреть на красивые графики в Grafana

      https://jmeter.apache.org/usermanual/realtime-results.html