TailSampler — паралельная отправка GET-запросов в Apache.JMeter

1d7d542f5aff4a60a71849b9a1da54a1.jpg
 

1. Назначение плагина «HTTP Request Tail»


Плагин упрощает загрузку встроенных ресурсов, позволяет параллельно выполнять указанные GET-запросы. Делая тест максимально близким к работе браузера по составу загружаемых ресурсов и по способу загрузки этих ресурсов.

TailSampler выручает если нужно:

  • выполнить группу GET-запросов паралельно;
  • выполнить 1000 GET-запросов, не создавая 1000 компонентов HTTP Request;
  • протестировать сайт, активно использующий AJAX, Adobe Flash, Adobe AIR, SilverLigth, …


2. Инструкция по применению


HTTP Request Tail преобразует список ссылок в HTML-документ, загрузка встроенных ресурсов которого создаст GET-запрос по каждой из указанных ссылок.

Процесс подготовки данных для плагина <b>TailSampler</b> и их использование» /><br /><span>Рисунок 1. <i>Процесс подготовки данных для плагина <b>TailSampler</b> и их использование</i></span></p><ol><li>Запустить <b>Fiddler</b>.</li>
<li>Открыть в веб-браузере страницу, загрузку которой надо детально имитировать в тесте — это может быть страница с <b>Adobe Flash</b>, с <b>Adobe AIR</b>, с <b>Microsoft SilverLigth</b>, с <b>ActiveX</b>-компонентами.</li>
<li>Выполнить на странице нужные действия.</li>
<li>Скопировать из <b>Fiddler</b> ссылки на GET-запросы, которые нужно выполнить в тесте параллельно, так, как если бы их выполнял браузер.</li>
<li>Вставить ссылки в <b>TailSampler</b>, при необходимости параметризировать.</li>
<li>Получить параллельное выполнение указанных запросов в тесте, степень параллельности настраивается.</li>
</ol><br /><div><div><div><iframe webkitAllowFullScreen mozallowfullscreen allowFullScreen webkitAllowFullScreen mozallowfullscreen allowFullScreen src=[embedded content]

3. Работа стандартных html-парсеров JMeter

Стандартный способ получения HTML-документа по протоколу HTTP в JMeter — использование HTTP Request sampler. В HTTP Request есть простой способ запросить встроенные ресурсы страницы — галочка [v] Retrieve Embedded Resources. Стандартным парсером, формирующим ссылки на ресурсы страницы является LagartoBasedHtmlParser. Парсер можно поменять в настройке htmlparser.classname файла jmeter.properties.

Исследование парсеров Apache.JMeter для пяти популярных сайтов приведено в статье «Выбираем html-парсер для Apache.JMeter»:

При использовании парсеров загружаются почти все нужные ресурсы. Но для разных сайтов полнота загрузки разная. Так если веб-сайт реализован на Microsoft Silverlight, то эффективность работы парсера Apache.JMeter будет около 0%. Тогда как, используя, TailSampler, можно будет подать нагрузку, аналогичную работе браузера простым способом.

3.1. Пример работы со сложным сайтом atlas.mos.ru


1bf9b60bb308436185939c92dfb486aa.png
Рисунок 2. Сайт atlas.mos.ru в браузере — 85 запросов к основному домену
0619d5e1561c41ddb1c71d8da98c5172.png
Рисунок 3. Сайт atlas.mos.ru в JMeter — 2 запроса к основному домену
462219bece014910bb052df61433b873.png
Рисунок 4. Трассировку выполнения запросов можно увидеть в webpagetest.org
c29afbdf73ee415994e00040119c7e70.png
Рисунок 5. Браузер выполняет 85 запросов к основному домену, а JMeter только 2 — эффективность 2,35%, см. логи в google docs

При открытии сайта atlas.mos.ru, активно использующего AJAX, видна разница:

Таким образом, при использовании HTTP Request с настройкой [v] Retrieve Embedded Resources для адреса atlas.mos.ru 83 GET-запрос не будет отправлен.
daf51c3684a846d599d8fc978aa66883.jpg
Маловато будет
«Падал прошлогодний снег»

Чтобы сэмулировать отправку 83 GET-запроса, нужно будет добавить 83 компонента HTTP Request в скрипт JMeter:

Добавленные 83 HTTP Request будут обрабатываться последовательно друг за другом — браузер же отправляет запросы на встроенные ресурсы параллельно:

9b7e30e9fec8482ea7229eeb3ebf27c3.png
Рисунок 6. Отчёт по загрузке сайта pflb.ru в Firefox — http://www.webpagetest.org/result/160319_RQ_Q3W/1/details/ — видны группы параллельной загрузки по 6 запросов

Таким образом, используя только HTTP Request не удастся полностью повторить загрузку встроенных ресурсов так, чтобы точно замерить время загрузки html-страницы со всеми подзапросами.

6df8e903de274468a7372d3e8f8afbef.jpg
Рисунок 7. HTTP Request не позволяет увидеть картину целиком, реализовать хвост подзапросов поможет HTTP Request Tail

4. История создания


Плагин HTTP Request Tail для JMeter создан в качестве альтернативы Tile Server — сервису на python, описание смотри ниже.

Первое знакомство с сервисом Tile Server произошло, когда коллеги Женя Бороденков и Максим Конышев рассказывали про нагрузочное тестирование веб-проекта, загружающего большие изображения кусочками, тайлами. Тогда мы решали задачу нагрузочного тестирования одной из версий этого веб-проекта, использующей SilverLight на клиенте и потоковое получение содержимого от сервера по протоколу SOAP/MSBin1. Послать из JMeter запросы по протоколу SOAP/MSBin1 и обработать ответы на них мы сначала не знали как, обсуждали варианты.

Рассказ был примерно таким:

— Если бы тут был Вова, он бы сказал использовать промежуточный сервис для формирования нужных запросов.

— Промежуточный сервис, это слишком сложно (отвечал им). Давайте напишем плагин для JMeter. Плагин — просто и надёжно.

— Вот когда было предыдущее тестирование, Андрей Пищулин написал сервис Tile Server на python, этим сервисом до сих пор пользуемся, сервис для работы с тайлами:

  • JMeter отправляет серверу Tile Server список ссылок методом POST через HTTP Request;
  • Tile Server реализует веб-сервер, принимает список ссылок, формирует из ссылок html-документ со списком iframe-ов, указывающих на ссылки и возвращает html-документ JMeter;
  • JMeter парсит html-документ и выполняет нужные GET-запросы, как подзапросы.
Давай делать также.

— Хорошо, давай сделаем промежуточный сервис для реализации работы с SOAP/MSBin1.


Забегая вперёд скажу, сделали мы также, как когда-то. Сделали прокси-сервис на .NET, который формировал запросы по SOAP/MSBin1 — JMeter посылал команды этому сервису по SOAP/XML, а сервис посылал запросы к нагружаемому узлу уже по SOAP/MSBin1 и возвращал ответы к JMeter.

И при высокой нагрузке прокси-сервис стал узким местом, не смог он генерировать запросы и обрабатывать ответы так, чтобы нагружаемые серверы приуныли и прилегли. Нагрузку тестируемые серверы получили, но если они отвечали прокси-сервису за 10 секунд, прокси-сервис отвечал JMeter-у за 110 секунд. По статистике из логов JMeter выходило, что нагружаемый сервис приуныл, и да, нагрузка подавалась хорошая, но нагружаемый сервис отвечал бодро, бодрее, чем свидетельствовали логи JMeter. Оперативное добавление подробного логирования в прокси-сервис исправило ситуацию, но когда прокси-сервис зависал, то и логирование на нём запаздывало — надо было масштабировать промежуточный сервис или переписывать его полностью, один экземпляр не тянул на роль «Царь-пушки».
b8e0dbc6d298450c9ddb0ee4ac9aea0e.jpg
Рисунок 8. Царь-пушка

Прокси-сервис стал точкой отказа. Тогда вернулись к идее плагина для JMeter, и сделали из JSR223, библиотек JNA и прокси-клиента на .NET пулемёт для работы по протоколу SOAP/MSBin1, вышло здорово. Плагину уже не приходится обрабатывать несколько входящих потоков. Накладных расходов на оперативную память, конечно, больше, но работает это быстрее.

Тогда же возникла идея написать sampler JMeter на java, на замену Tile Server, вдруг и он является точкой отказа при нагрузке. Даже название будущего sampler-а появилось — «HTTP Request Tail» или «Tail Sampler». Из-за плохого знания английского языка услышал слово «Tile», как «Tail», немного не понял, причём тут «тайлы» и слово, которое переводится как «хвост». Глухие телефоны, хвост так хвост, образ русалки дополнил картину. Задумка закрепилась, идея ясна, название есть. Оставалось самое малое — сделать. Тут помогла Саша Перевозчикова Sanchez92 — эксперт по разработке плагинов.

Претензий к Tile Server не имею, коллеги говорят — это быстрый и надёжный инструмент. Плагин создавался из любопытства и интереса к новому для меня инструменту JMeter, и Сашу надо было чем-то занять, а то скучала девица.

Все имена в этой истории невымышленные, явно или косвенно плагин «HTTP Request Tail» сделали:



5. Описание

5.1. Настройки по умолчанию


b00fe12ab7c44ed6b20decd841ba9fc2.PNG
Рисунок 9. Настройки по умолчанию

По умолчанию используются настройки:


Неиспользуемые настройки — настройки для POST-запросов, значения никак не используются ни главным запросом ни подзапросами:

Главный запрос генерируется, а не отправляется, на него настройки для POST-запросов не действуют. Подзапросы используют метод GET, для них также не действуют настройки для POST-запросов.
Остальные настройки действуют на подзапросы.

HTTP Request Tail является наследником HTTP Request, описание настроек можно посмотреть в документации на HTTP Request:

5.2. Настроенный HTTP Request Tail


4017bbe3372d4f6f9d846506dcbafdac.png
Рисунок 10. Настроенный HTTP Request Tail
Ссылки на встроенные ресурсы указываются в текстовом поле Embedded resources. Можно указывать относительные и абсолютные ссылки.5.2.1. Абсолютные ссылки
Описание формата абсолютных ссылок смотри в RFC: https://tools.ietf.org/html/rfc3986.
Абсолютные ссылки начинаются с протокола:

Другие протоколы не обработаются HTTP Request Tail.
Примеры абсолютных ссылок:
5.2.2. Относительные ссылки
Относительные ссылки дополняются значениями полей:

Пример относительных ссылок:
5.2.3. Параметризация с использованием переменных и функций
Для параметризации GET-запросов можно использовать переменные и функции JMeter. Пример:
5.2.4. Особенности обработки Unicode и html-сущностей
При формировании html-страницы из ссылок используется html-экранирование. Поэтому при написании ссылок можно использовать:

Структура html-страницы не нарушится, ссылки обработаются корректно и в полном объёме.
Полный список html-сущностей для html4 смотри тут:

Если какая-то сущность из спецификации не экранируется, то оформите замечание к плагину.
Не нужно предварительно экранировать специальные символы. Так если есть необходимость указать URL вида:

То так и надо писать — просто &, заранее экранировать на & не надо:
5.2.5. Unicode для java
Замечено, что если в адресе есть unicode-символ, например, ®, Ω, π, ≈:

И в настройке Implementation стоит значение Java, то в подзапросе unicode-символ будет заменен на квадратик:

При запуске JMeter из Windows с помощью bat-файла кодировкой для java назначается windows-1251, предполагаю это причина замены unicode-символа на квадратик. Чтобы задать кодировку нужно указать в bat-файле аргумент для java: -Dfile.encoding=UTF-8. При использовании HttpClient4 и HttpClient3.1 такой нежелательной трансформации не происходит.

5.3. Генерируемый ответ


9d76139e750242c5a9145dd949fa100f.PNG
Рисунок 11. Ответ на основной запрос — генерируемый ответ
Ответ на основной запрос генерируется. Запроса нет, есть только тело ответа.

Тело ответа представляет собой html-документ, текст с кодировкой UTF-8, где для каждой ссылки на встроенный ресурс сгенерирован тег iframe.

Пример документа:

 
 
 
   
  	Embedded resources
   
   
 	
 	
 	
 	
 	
   











 

80b6996620724c6293e4e6ca4a3ffa04.PNG
Рисунок 12. Статистика выполнения генерируемого запроса5.3.1. Планы на изменение
При написании статьи про парсеры JMeter в комментариях появился разработчик JMeter Philippe M. philmdot и попросил запостить дефект на счёт рекурсивной обработки:

Планирую запостить дефект, и даже исправить его. Сделав так, чтобы для ответов на запросы из тегов img не выполнялся рекурсивный поиск ссылок на ресурсы. Чтобы в JMeter парсинг работал также, как это делает браузер. Вот если iframe, то надо выполнять парсинг, а если просто img, то выполняется единичный запрос.

И тогда же надо будет изменить плагин TailSampler так, чтобы при генерации использовались теги img вместо тегов iframe.

Сегодня Philippe написал, что хотел бы увидеть этот код в ядре JMeter, что это будет хороший способ работы с AJAX. Попробую успеть в этом году, будет интересный опыт.

5.4. Известные эффекты

5.4.1. +1 запрос в логе
Корневой запрос хоть и не отправляется, но попадает в лог:
5.4.2. Визуальный обман для ответа 302
Если стоит настройка Follow Redirect, то для каждого встроенного ресурса с кодом ответа 302 (Found):
5.4.3. Рекурсия
Редкий, но возможный эффект — загрузка встроенных ресурсов для встроенного ресурса:

В планах ограничить глубину рекурсии до настраиваемого из интерфейса плагина параметра в 3 уровня по умолчанию. Браузер при загрузке картинки (тег img) не выполняет для неё загрузку встроенных ресурсов. Тут же, все ресурсы обёрнуты в тег iframe, и Apache.JMeter в настоящий момент не различает, для какого тега осуществлялся запрос — всегда парсит ответ на предмет подзапросов, если Content Type ответа подходящий.
640bff5949084b1e98f03dc3295db0a9.png
Рисунок 13. Виден первый запрос test_server.ru, который не выполнялся на самом деле (эффект »+1 запрос»). Виден каскад перенаправлений (эффект «Визуальный обман для ответа 302») и подзапросов для подзапросов (эффект «Рекурсия»).

5.5. Временные характеристики


Если снять галочку [ ] Retrieve All Embedded Resources или не указать ни одной ссылки в Embedded resources, то в логах будет написано, что запрос отправился мгновенно, и ответ на него пришел мгновенно.

Описание временных характеристик:

6. Проект на Github


7. Структура проекта


Исходный код в каталоге:
/src/ru/pflb/jmeter

Другие каталоги вспомогательные, служат для удобства отладки проекта.

7.1. Форма


Форма TailUrlConfigGui является модификацией главной формы HTTP Request из Apache.JMeter 2.13, откуда удалены поля для редактирования тела запроса и задания списка параметров, но добавлено одно большое поле для ввода списка ссылок.
А внешний вид TailHttpSamplerGui также является копией HTTP Request, где теперь применяется новый главный элемент управления TailUrlConfigGui.

Тут не обошлось без копипасты. Пошел на этот шаг, чтобы HTTP Request Tail почти не отличался от HTTP Request.

Но в JMeter 3.0 внешний вид HTTP Request был изменён, элементы управления переставлены местами. Теперь HTTP Request Tail отличается HTTP Request для JMeter 3.0. Но это на работу не влияет.

7.2. Обёртки


Хотелось по максимуму использовать существующий код, но копипастой заниматься не хотелось. Поэтому был применён антипатерн «Паблик Морозов», благодаря которому методы sample, notifyFirstSampleAfterLoopRestart и threadFinished стали публичными.

7.3. Утилита для экранирования


Код класса, выполняющего экранирование взят с сайта ibm.com: www.ibm.com/developerworks/ru/library/se-prevent/index.html
Таблица html-сущностей расширена за счёт RFC с описанием HTML4.

8. Установка


  1. Скачать плагин ru.pflb.jmeter.samplers.TailSampler.jar:
    • Все версии: github.com/pflb/Jmeter.Plugin.TailSampler/releases
  2. Скопировать плагин в каталог lib/ext для JMeter.
  3. Перезапустить JMeter.

d086363bd0154c90904e7a1f9f646bf5.png
Рисунок 14. Теперь плагин HTTP Request Tail доступен в JMeter

Пример каталога:

D:\TOOLS\apache-jmeter-2.13\lib\ext\
D:\TOOLS\apache-jmeter-2.13\lib\ext\ru.pflb.jmeter.samplers.TailSampler.jar
D:\TOOLS\apache-jmeter-3.0\lib\ext\
D:\TOOLS\apache-jmeter-3.0\lib\ext\ru.pflb.jmeter.samplers.TailSampler.jar

9. Системные требования

9.1. Для работы с Apache.JMeter 2.13



Apache.JMeter 2.13 собран с использованием Java 6. И если собрать плагин TailSampler с использованием, например, OpenJDK 1.7.0_09-icedtea, и запустить Apache.JMeter 2.13 + собранный плагин на компьютере, где есть только Java 6, то Apache.JMeter 2.13 запустится, а плагин нет. В результате их связка работать не будет. Вопрос сборки проектов и библиотек для различных версий Java и их совместимости заслуживает отдельной инструкции.

9.2. Для работы с Apache.JMeter 3.0



Apache.JMeter 3.0 собран с использованием Java 7. Плагин TailSampler нужно собирать с использованием Java 7 или той версии Java, которая будет использоваться для запуска JMeter и плагина.

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

© Habrahabr.ru