Приручаем JMeter

imageСегодня я хочу рассказать о замечательном инструменте, название которого вынесено в заголовок статьи. Разумеется, моей целью не является написание подробного руководства по Apache JMeter. В своей статье я хочу лишь зафиксировать ряд, на мой взгляд, не очевидных моментов, с которыми мне пришлось столкнуться в своей повседневной работе. Я надеюсь, что моя статья будет полезна (сразу предупреждаю, картинок будет много). 
Конечно, я не первый, кто пишет про JMeter на Хабре, но практически во всех предыдущих статьях, акцент делается на нагрузочное тестирование. Хотя это и основное применение JMeter, но только им его возможности не ограничиваются. Давайте, просто посмотрим, по каким протоколам может работать этот продукт:

  • Web — HTTP, HTTPS
  • SOAP / REST
  • FTP
  • Database via JDBC
  • LDAP
  • Message-oriented middleware (MOM) via JMS
  • Mail — SMTP (S), POP3(S) and IMAP (S)
  • MongoDB (NoSQL)
  • Native commands or shell scripts
  • TCP


Таким образом, если перед вами стоит какая-то задача автоматизации и всё, что вам требуется, перечислено в этом списке, определённо стоит подумать об использовании JMeter, перед тем как с головой погрузиться в программирование на любимом Perl, Python или Java. Возможно, такой подход позволит сэкономить очень много времени.

Установка


С этим всё просто:

  1. Устанавливаем Java (если она еще не установлена)
  2. Выкачиваем и распаковываем свежую сборку JMeter
  3. Устанавливаем переменную среды JMETER_BIN на каталог с исполняемыми файлами JMeter (только для Windows)
  4. Запускаем jmeter.bat или jmeter.sh (в зависимости от операционной системы) из каталога bin


Единственная проблема, с которой я столкнулся на Windows, связана с тем, что значение переменной JMETER_BIN должно завершаться символом прямого или обратного слэша. Подробности можно посмотреть в запускаемом скрипте. Чтение инструкции также не будет лишним.

Запись скрипта


Это, пожалуй, самая эффектная возможность JMeter. Она уже описывалась ранее, но я повторюсь, поскольку в той статье речь шла об уже немного устаревшей версии. JMeter можно запустить в режиме proxy, таким образом, чтобы весь HTTP-трафик проходил через него. Все подробности взаимодействия будут автоматически записываться в выбранную Thread Group или Recording Controller. Для добавления новых узлов в дерево, просто нажимаем на правую кнопку мыши и выбираем требуемый тип из выпадающего меню:

a953931b51d94dad927de4d122529f6a.PNG


Thread Group, управляющая такими настройками как количество потоков, используемых для тестирования и количество запросов в тесте, находится в категории Treads (Users), а сам HTTP (S) Test Script Recorder в Non-Test Elements.

bba78c859d70442a98f3d38b666b4e02.png


Я выделил на рисунке настройки, на которые следует обратить внимание. Порт возможно придётся изменить, если на 8080 уже что-то поднято. В сложных случаях, в Test Plan придётся добавить HTTP Cookie Manager и HTTP Authorization Manager. После нажатия кнопки Start, идём в настройки любимого браузера:

13895ac798d24089b5916b6afe092998.png


Взаимодействие с Яндекс, внезапно, оказывается очень непростым:

55e32062c7c44ff8866dc5df3175f640.PNG


Полученные запросы (HTTP Request) вместе с их настройками (HTTP Header Manager) можно перенести в любое место скрипта, используя любимые всеми команды Copy&Paste (Drag&Drop тоже работает). Даже если вы твердо уверены в том, что происходит на вашем сайте, Script Recorder может быть очень полезен, для того чтобы узнать подробности. Кроме того, автоматическая генерация скриптов куда веселее чем вбивание их руками. Более подробно процесс записи скриптов описан в этой инструкции.

Переменные


Для чего-то мало-мальски серьёзного, нам потребуется возможность параметризации. Для примера, предположим, что нам требуется задать таймауты, в течение которых JMeter будет ожидать ответа сервера. Вбивать их заново в каждый HTTP Request, при любом изменении, было бы слишком утомительно. Заодно определим настройки HTTP Proxy (если он используется):

0f4b897fa3574a169b52595aee9ec119.PNG


В поле Password забито значение ${user_pass}, тут уж вам придётся поверить мне на слово. Сами настройки удобно держать в User Defined Variables (этот элемент можно найти в категории Config Element):

9dbf3a697b854594a30678b113a4e599.PNG


Пустые значения переменных проблемой не являются. В соответствующие настройки будут подставлены пустые строки, как того и требуется, в случае если HTTP Proxy не используется. Можно пойти ещё дальше и действительно разместить все HTTP-настройки в одном месте:

cf18def4a8ab41ec9db6d167ef9dd1d7.PNG


Элемент HTTP Request Defaults, также как и User Defined Variables расположен в категории Config Element.

Отладка


Теперь, было бы неплохо видеть, что происходит при выполнении сценария. Различного вида визуализаторы размещаются в категории Listener. Нам понадобится View Results Tree. Добавим его и запустим сценарий на выполнение командой Run/Start (Ctrl+R). Можно видеть, что ответ сервера также бывает непростым:

adf1675d3a8d4c439adbbab91299b85f.PNG


Такая картина наблюдается, если адрес редиректит нас на другую страницу и с этим может быть связана одна проблема. Если мы попытаемся анализировать ответ сервера (как это делать я покажу ниже), нам будет доступен лишь последний ответ (той страницы на которую произошёл redirect). Если ответ с предыдущей страницы нам также интересен, автоматический redirect придётся отключить. За это отвечает настройка Follow Redirects элемента HTTP Request. Разобрав ответ, мы сможем получить адрес целевой страницы и выполнить повторный запрос вручную.

Есть ещё один элемент, крайне полезный для отладки сценариев. Он находится в категории Sampler и называется Debug Sampler. Каждый раз, когда до него доходит управление, он выводит текущие значения всех переменных. Добавим его в Thread Group и запустим сценарий ещё раз (для того, чтобы очистить вывод предыдущего запуска, удобно использовать комбинацию клавиш Ctrl+E):

1615920742704943a243e4180a974359.PNG


Все переменные как на ладони. Удобно.

JDBC Request


Этот Sampler открывает нам доступ в любую базу данных, поддерживающую протокол JDBC. Для начала, добавим в Test Plan конфигурационный элемент с настройками подключения к серверу БД (JDBC Connection Configuration):

252710a902a74ad9b4545901d118b373.PNG


Помимо собственно настроек подключения к БД, здесь важно заполнить поле Variable Name. Это имя будет использоваться в JDBC Request (Sampler) для доступа к пулу сессий:

70e448dbf25a4f2289f839f5f4fd3f8a.PNG


Если вам интересны результаты select-а, придётся заполнить Variable Names. Сам JMeter парсить SQL-запросы на предмет имён столбцов не умеет. Можно перечислять имена столбцов через запятую и пропускать столбцы, не давая им имени. Вставляем Debug Sampler и смотрим, что получилось:

c171b21c61be454785e4a45d3d4c4881.PNG


Видим, что документация не врёт. Появились переменные urls_1 и urls_2 (количество строк, как и обещали, в urls_#). В этом месте, стоит соблюдать осторожность. Записи выбираются не по одной, а все сразу и прочитав >1000 строк можно легко отожрать слишком много памяти. Теперь, было бы неплохо обойти полученные адреса в цикле:

d0afa3f916f043498974abe25be6ea3f.PNG


Да, именно вот так заковыристо. Набор переменных urls перебираем от 0 до ${urls_#} и текущее значение помещаем в url. Сам ForEach Controller можно найти в категории Logic Controller. Внутри него создадим параметризованный HTTP Request. Запускаем, смотрим:

c9a5a0c1156d4df99c9e60e6f5853a8c.PNG


Всё работает.

Регулярные выражения


Теперь, результаты обращений к Web-серверам хотелось бы проанализировать. Для этого, нам предоставлена вся мощь регулярных выражений. Regular Expression Extractor можно найти в Post Processors. Добавим его в HTTP Request и сконфигурируем:

d45208b0ed7844d683a54ae17e22a8fc.PNG


Здесь, нас интересует только код ответа по HTTP (но, по иллюстрации видно, что можно обрабатывать и содержимое ответа). Будем извлекать цепочку цифр (Regular Expression) и помещать результат применения шаблона (Template) в переменную http_result (Reference Name):

7a0e4520593c436e9005ddd6fd7a4657.PNG


Как и ожидалось, получаем 200. Заодно, можно видеть, каким образом осуществляется захват в переменные регулярным выражением.

Что-то там внутри


Теперь, допустим, что нас интересует время, в течение которого выполнялся HTTP-запрос. И интересует оно нас не просто для статистики, а мы его хотим как-то использовать в сценарии (например сложить в БД). С этой задачей поможет справиться BeanShell. Конкретно, мы используем его Pre — и PostProcessor-ы.

a5cad478bb18429f893c172bf82f8c17.PNG


В первом будем получать timestamp:

Long t = ctx.getPreviousResult().currentTimeInMillis();
vars.put("timestamp", t.toString());


А во втором, получать с его помощью временную задержку:

Long d = ctx.getPreviousResult().currentTimeInMillis() - Long.parseLong(vars.get("timestamp"));
vars.put("delay", d.toString());


В общем, это тоже работает:

710a552f784246bd97fa318621b34307.PNG


Но здесь следует сделать важное замечание. Поскольку, в настоящий момент, я занимаюсь не нагрузочным тестированием, производительность этой конструкции для меня не очень важна. Если в вашем случае это не так, стоит ознакомиться со следующей статьёй.

Запуск


Если бы не было этой возможности, не стоило бы и весь этот разговор заводить. В случае нагрузочного тестирования, сценарий можно запускать из GUI, нет проблем. Но если нас интересует автоматизация, необходимо уметь запускать его молча (например по cron-у). Разумеется такая возможность тоже есть:

./jmeter.sh -n -t test.jmx -l test.log


Сохраняем сценарий в файл с расширением jmx (внутри это XML) и запускаем эту команду. Сценарий отрабатывает без запуска GUI и заодно пишет результаты своей работы в лог. Всё просто и удобно.

© Habrahabr.ru