TailSampler — паралельна відправка GET-запитів в Apache.JMeter


 
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> і їх використання
Малюнок 1. Процес підготовки даних для плагіна TailSampler і їх використання

  1. Запустити Fiddler.
  2. Відкрити в браузері сторінку, завантаження якої потрібно детально імітувати в тесті — це може бути сторінка з Adobe Flash, Adobe AIR, Microsoft SilverLigth, ActiveX-компонентами.
  3. Виконати на сторінці потрібні дії.
  4. Копіювати Fiddler посилання на GET-запити, які потрібно виконати в тесті паралельно, так, як якщо б їх виконував браузер.
  5. Вставити посилання в TailSampler, при необхідності параметризировать.
  6. Отримати паралельне виконання зазначених запитів в тесті, ступінь паралельності налаштовується.


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


Малюнок 2. Сайт atlas.mos.ru в браузері
85
запитів до основного домену

Малюнок 3. Сайт atlas.mos.ru JMeter
2
запиту до основного домену


Малюнок 4. Трасування виконання запитів можна побачити в webpagetest.org

Малюнок 5. Браузер виконує
85
запитів до основного домену, а JMeter тільки
2
— ефективність
2,35%
, див. логи google docs
При відкритті сайту atlas.mos.ru, активно використовує AJAX, видна різниця:
  • 2
    GET-запиту, якщо працює LagartoBasedHtmlParser, HTTP Request, JMeter 3.0;
  • 85
    GET-запит, якщо працює браузер Chrome.
Таким чином, при використанні HTTP Request з налаштуванням [v] Retrieve Embedded Resources для адреси atlas.mos.ru
83
GET-запит не буде відправлено.

Замало буде
«Падав торішній сніг»
Щоб сэмулировать відправку
83
GET-запиту, потрібно буде додати
83
компонента HTTP Request скрипт JMeter:
  • скрипт JMeter стане громіздким.
Додані
83
HTTP Request будуть оброблятися послідовно один за одним — браузер ж відправляє запити на вбудовані ресурси паралельно:
  • сумарна тривалість завантаження ресурсів сторінки буде більше, ніж в браузері, послідовна завантаження виконується довше паралельної на незавантаженому сервері;
  • кількість одночасно відкритих з'єднань з сервером буде менше, ніж при роботі браузера, кількість з'єднань з сервером побічно впливає на продуктивність.



Малюнок 6. Звіт по завантаженню сайту pflb.ru у Firefoxhttp://www.webpagetest.org/result/160319_RQ_Q3W/1/details/ — видно групи паралельної завантаження
6
запитів


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


Малюнок 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/MSBin1JMeter посилав команди цього сервісу SOAP/XML, а сервіс надсилав запити до нагружаемому сайту вже по SOAP/MSBin1 і повертав відповіді до JMeter.

І при високому навантаженні проксі-сервіс став вузьким місцем, не зміг він генерувати запити і обробляти відповіді так, щоб навантажуються сервери зажурилися і приліг. Навантаження досліджувані сервери отримали, але якщо вони відповідали проксі-сервісу за
10
секунд, проксі-сервіс відповідав JMeter-за
110
секунд. За статистикою з логів JMeter виходило, що навантажується сервіс зажурився, і так, навантаження подавалася хороша, але навантажується сервіс відповідав бадьоро, бадьоріше, ніж свідчили логи JMeter. Оперативне додавання докладного логування в проксі-сервіс виправило ситуацію, але коли проксі-сервіс зависав, то і логування на ньому запізнювалася — треба було масштабувати проміжний сервіс або переписувати його повністю, один примірник не тягнув на роль «Цар-гармати».

Малюнок 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. Налаштування за замовчуванням


Малюнок 9. Налаштування за замовчуванням

За замовчуванням використовуються параметри:
  • [v] Retrieve All Embedded Resources   за замовчуванням галочка поставлена, її можна зняти, але тоді не будуть виконуватися підпорядкований, і HTTP Request Tail стане марним;
  • [v] Use concurent pool   за замовчуванням галочка поставлена на великій кількості вбудованих ресурсів багатопотокова завантаження збільшує швидкість закачування;
  • Use concerent pool Size
    4
      за умовчанням використовується значення 4, це значення використовується JMeter в якості базового:
    • HttpClient4 при налаштуванні Use concerent pool Size
      4
      буде посилати до 4 запитів одночасно, кожен потік буде використовувати по 1 постійному з'єднання на кожен домен:
      • запуститься група потоків, розмір групи визначається настроюванням Use concerent pool Size;
      • при налаштуванні [v] Use keepalive кожен потік для кожного унікального домену буде створювати одне постійне з'єднання (persistent-connection);
    • Браузер Mozilla Firefox 44.0 за замовчуванням посилає до
      6
      одночасних запитів на кожен домен (див.
      about:config
      ):
      • 256
          network.http.max-connections — максимальне число з'єднань;
      • 6
          network.http.max-persistent-connections-per-server — максимальне число постійних з'єднань з сервером (keepalive);
      • 32
          network.http.max-persistent-connections-per-proxy — максимальне число постійних з'єднань з проксі-сервером (keepalive);
    • Якщо орієнтуватися на налаштування Mozilla Firefox 44.0, і те, що посилання на вбудовані ресурси в проектах навантажувального тестування зазвичай належать одному домену, то в Use concerent pool Size можна ставити значення
      6
      , замість стандартного значення
      4
      .
Невикористані налаштування — налаштування для POST-запитів, значення ніяк не використовуються ні головним запитом ні подзапросами:
  • [ ] Use multipart/form-data for POST;
  • [ ] Browser-compatible headers.
Головний запит генерується, а не відправляється, на нього налаштування для POST-запитів не діють. Підпорядкований використовують метод GET, для них також не діють налаштування для POST-запитів.
Інші налаштування діють на підпорядкований.

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


5.2. Налаштований HTTP Request Tail


Малюнок 10. Налаштований HTTP Request Tail
Посилання на вбудовані ресурси зазначаються в текстовому полі Embedded resources. Можна вказувати відносні й абсолютні посилання.

5.2.1. Абсолютні посилання
Опис формату абсолютних посилань дивись в RFC: https://tools.ietf.org/html/rfc3986.
Абсолютні посилання починаються з протоколу:
  • file://
  • http://
  • https://
Інші протоколи не обработаются HTTP Request Tail.
Приклади абсолютних посилань:
  • file://C:\Data\htmlDocument.html#Part1
  • <a rel="nofollow" href="http://www.pflb.ru/">http://www.pflb.ru/</a>
  • <a rel="nofollow" href="https://yandex.ru/?q=Testing&amp;client=Mozilla">https://yandex.ru/?q=Testing&client=Mozilla</a>


5.2.2. Відносні посилання
Відносні посилання доповнюються значеннями полів:
  • Path   каталог для тих посилань, що є відносними щодо сторінки, а не щодо хоста, тут може бути вказано протокол хост і порт.
  • Web Server   вузол і порт:
    • Server Name or IP;
    • Port Number;
  • Protocol [http]   протокол, якщо в Path не вказано протокол значення враховується, допустимі значення
    file
    ,
    http
    ,
    https
    .
Приклад відносних посилань:
  • image1.png
  • /images/image1.png
  • /ResourceGenerator.aspx?id=0121
  • subFolder/style.css
  • subFolder/1/2/3/test.php


5.2.3. Параметризація з використанням змінних і функцій
Для параметризації GET-запитів можна використовувати змінні і функції JMeter. Приклад:
  • <b>${variable_URL}</b>
  • /search.php?q=<b>${variable_Query_String}</b>
  • /search.php?q=<b>${variable_Query_String}</b>&client=Opera
  • /search.php?q=<b>${__urlencode(${variable_Query_String})}</b>&client=Opera


5.2.4. Особливості обробки Unicode і html-сутностей
При формуванні html-сторінки з посилань використовується html-екранування. Тому при написанні посилань можна використовувати:
  • кириличні домени;
  • спеціальні символи, такі як
    <
    ,
    >
    ,
    &
    та інші;
  • будь-unicode-символи.
Структура html-сторінки не порушиться, посилання обработаются коректно і у повному обсязі.
Повний список html-сутностей для html4 дивись тут:
Якщо якась сутність специфікації не екранується, то оформіть зауваження до плагіну.
Не потрібно попередньо екранувати спеціальні символи. Так якщо є необхідність вказати URL виду:
  • /search.php?q=Testing<b>&</b>client=Opera
      правильно.
То так і треба писати — просто
&
, заздалегідь екранувати
&amp;
не треба:
  • /search.php?q=Testing<b>&<u>amp;</u></b>client=Opera
      неправильно.


5.2.5. Unicode для java
Помічено, що якщо в адресі є unicode-символ, наприклад, ®, Ω π, ≈:
  • /search.php?q=Microsoft®
І в налаштуванні Implementation значення
Java
, то в підзапитів unicode-символ буде замінений на квадратик:
  • /search.php?q=Microsoft□
При запуску JMeter з Windows з допомогою bat-файлу кодуванням для java призначається
windows-1251
, припускаю це причина заміни unicode-символу на квадратик. Щоб задати кодування потрібно вказати в bat-файл аргумент для java:
Dfile.encoding=UTF-8
. При використанні
HttpClient4
та
HttpClient3.1
такої небажаної трансформації не відбувається.

5.3. Генерований відповідь


Малюнок 11. Відповідь на основний запит — генерований відповідь
Відповідь на основний запит генерується. Запиту немає, є тільки тіло відповіді.

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

Приклад документа:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Embedded resources</title>
</head>
<body>
<iframe src="http://www.google-analytics.com/analytics.js"></iframe>
<iframe src="/sites/all/themes/pro/static/img/icons.png"></iframe>
<iframe src="sites/all/themes/pro/static/img/main_3_block90-s.png"></iframe>
<iframe src="http://pflb.ru/sites/all/themes/pro/static/img/footer-shadow.png"></iframe>
<iframe src="http://staticxx.facebook.com/connect/xd_arbiter.php"></iframe>
</body>
</html>


Малюнок 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 запит в балці
Кореневий запит хоч і не відправляється, але потрапляє в лог:
  • слабо, але завищує значення показника Hits per second   хіти в секунду;
  • опосередковано, впливає на загальну статистику по ловга JMeter;
  • щоб знизити вплив цього одиночного запиту на статистику — кількість реальних підпорядкованого повинно бути великим, десятки посилань у полі Embedded resources.


5.4.2. Візуальний обман для відповіді 302
Якщо стоїть налаштування Follow Redirect, то для кожного вбудованого ресурсу з кодом відповіді
302
(Found):
  • буде виконуватися перенаправлення на сторінку, вказану в значенні Location заголовка відповіді;
  • перенаправлення відображаються у JMeter як підпорядкований — візуально виглядає, як каскад запитів.


5.4.3. Рекурсія
Рідкісний, але можливий ефект — завантаження вбудованих ресурсів для вбудованого ресурсу:
  • з типом вмісту (дивись налаштування htmlParser.Types та wmlParser.Types jmeter.properties):
    • text/html;
    • application/xhtml+xml;
    • application/xml;
    • text/xml;
    • text/vnd.wap.wml;
  • виконується:
    • завантаження вбудованих ресурсів для поточного вбудованого ресурсу — можливо, підпорядкованого буде більше, ніж посилань у полі Embedded resources.


У планах обмежити глибину рекурсії до настроюваного з інтерфейсу плагіна параметра в 3 рівня за замовчуванням. Браузер при завантаженні картинки (тег img) не виконує для неї завантаження вбудованих ресурсів. Тут же, всі ресурси обгорнуті в тег iframe та Apache.JMeter в даний момент не розрізняє, для якого тега здійснювався запит — завжди парсити відповідь на предмет підзапитів, якщо Content Type відповіді підходящий.

Малюнок 13. Видно перший запит test_server.ru, який не виконувався насправді (ефект «+1 запит»). Видно каскад перенаправлень (ефект «Візуальний обман для відповіді 302») і підпорядкованого для підпорядкованого (ефект «Рекурсія»).

5.5. Тимчасові характеристики

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

Опис часових характеристик:
  • Load Time   сумарна тривалість завантаження вбудованих ресурсів;
  • Connect time завжди
    0
    ;
  • Latency завжди
    0
    .


6. Проект на Github


7. Структура проекту
Вихідний код в каталозі:
/src/ru/pflb/jmeter
  • protocol/http/config/gui:
    • TailUrlConfigGui.java   елемент керування з великим полем для введення посилань на вбудовані ресурси;
  • samplers:
    • wrapper — обгортки, щоб використовувати зазначений на формі Implementation:
      • WrapperHTTPFileImpl.java   обгортка, щоб використовувати обробник протоколу
        file://
        для підпорядкованого;
      • WrapperHTTPHC3Impl.java   обгортка, щоб використовувати
        HttpClient3.1
        налаштування Implementation для підпорядкованого;
      • WrapperHTTPHC4Impl.java   обгортка, щоб використовувати
        HttpClient4
        налаштування Implementation для підпорядкованого;
      • WrapperHTTPJavaImpl.java   обгортка, щоб використовувати
        Java
        налаштування Implementation для підпорядкованого;
      • WrapperHTTPSamplerFactory.java   фабрика, для створення обгорток, повертає обробник за значенням протоколу та налаштування Implementation;
    • EscapeUtils.java   реалізація html-екранування, що дозволяє працювати з російськими доменами, юнікодом й спеціальними символами в посиланнях;
    • ITailHTTPImpl.java   базовий інтерфейс для всіх обробників;
    • TailHTTPHC4Impl.java   модифікований HttpClient4, який використовує зазначене тіло відповіді не відправляючи запит;
    • TailHTTPSamplerProxy.java   проксі-клас у якому реалізована вся логіка роботи TailSampler:
      • для першого запиту бере список посилань з поля Embedded resources і передає у TailHTTPHC4Impl   емуляція отримання сторінки зі списком iframe-ів у вмісті;
      • для запитів на вбудовані ресурси створюється і викликається стандартний обробник, зазначений у налаштуванні Implementation   реальна надсилання запитів;
    • TailHttpSamplerGui.java   візуальне подання TailSampler.
Інші допоміжні каталоги, служать для зручності відладки проекту.

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:
  2. Скопіювати плагін в каталог lib/ext JMeter.
  3. Перезавантажити JMeter.

Малюнок 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 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.