Інструменти навантаження: JMeter, k6, Gatling
Зміст
«Яким інструментом ганяти навантаження?» — питання, яке на співбесіді звучить так, ніби в нього є одна правильна відповідь. Її немає, і саме це від вас хочуть почути: (load testing tool) обирають під протокол і під команду, а не за списком фіч на головній сторінці.
Друге, на чому валяться, — спроба гнати навантаження тим, чим гнали e2e: у нас же є на Playwright, запустимо її в тисячу потоків. Глава пояснює, чому так не роблять, — не гаслом «Selenium повільний», а механізмом.
Карта інструментів: три ролі замість трьох продуктів
Канон розкладає інструментарій навантаження не на продукти, а на три ролі, і кожен продукт закриває їх у різній мірі:
| Роль | Що робить |
|---|---|
| Генератор навантаження | Створює й виконує багато клієнтських екземплярів, що імітують поведінку користувача за заданим операційним профілем; він же збирає метрики для звіту |
| Консоль керування | Дає контроль запуску й зупинки генераторів, агрегує метрики транзакцій, показує звіти й графіки |
| Засіб моніторингу | Працює одночасно із системою під тестом і спостерігає її поведінку — типово черги вебсервера, памʼять і місце на диску |
У сучасних інструментах перші дві ролі зазвичай злиті в одному інструменті, а третя майже завжди лишається окремою системою. Тому корисне питання при виборі — не «який кращий», а що інструмент робить сам, а що доведеться добудувати.
Мета генератора — імітувати реальний світ настільки, наскільки це практично, і часто це означає, що запити мусять іти з різних місць, а не лише з місця тестування. Ціна названа одразу: кілька точок присутності додають реалізму, але можуть спотворити результати, якщо проміжні мережеві стрибки дають .
Самі інструменти описують себе по-різному: k6 називає себе відкритим і розширюваним, а мету зводить до запобігання помилкам і порушенням SLO; Gatling вводить поняття популяції (population) — сценарій разом із injection profile, і популяцій в одній симуляції може бути кілька. Різниться й форма виводу: зведена статистика відповідає «пройшли чи ні», окремі точки з мітками часу — «коли саме почалася деградація».
Протокольний рівень: чому JMeter — не браузер
Це несуче твердження глави, і дока JMeter формулює його без пом'якшень: JMeter не є браузером — він працює на протокольному рівні. Щодо вебсервісів він виглядає як браузер (точніше, як кілька браузерів), проте не виконує JavaScript, знайдений у HTML-сторінках, і не рендерить HTML як браузер.
З цього одного речення випливає майже все інше:
- дешевий. Немає , немає виконання скриптів (див. Виконання JavaScript та event loop і Архітектуру браузера) — лишається робота з сокетами.
- Клієнтської частини досвіду ви не виміряли. Час, за який сервер віддав HTML, і час, за який людина побачила сторінку, — різні величини.
- Послідовність запитів доводиться відтворювати самому. Канон описує імплементацію скрипта як запис або програмування послідовності запитів: перше зазвичай гарантує точну імітацію реальної системи, друге спирається на знання правильної послідовності. Саме звідси береться кореляція — підстановка динамічних значень, які браузер підставляв би сам (окрема глава розділу).
Браузерний рівень робить протилежний вибір: браузерний модуль k6 додає API рівня браузера й збір фронтендових метрик. Ціна названа прямо — потрібен браузер на основі Chromium, установлений на машині.
Питання, на які відповідає саме браузерний рівень, названі поіменно: що відбувається з фронтендом, коли застосунок приймає тисячі одночасних запитів із протокольного рівня; чи всі елементи інтерактивні; чи немає спінерів, які довго не зникають. Останнє найпоказовіше — спінер, що висить, не має жодного відображення в коді відповіді HTTP. Метрики двох рівнів у зведенні стоять окремими блоками (BROWSER і WEB_VITALS), тож порівнювати http_req_duration з browser_web_vital_lcp безглуздо.
Тож відповідь на «чому не Selenium для навантаження» має дві половини. Перша: кожен віртуальний користувач тягне справжній браузер, тобто тисяча користувачів — це ферма машин. Друга, важливіша: обидва рівні потрібні, але для різного, і k6 прямо змішувати браузерні тести з іншими в одному прогоні — протокол створює фон, а браузерний користувач міряє, що бачить людина.
JMeter: групи потоків, семплери й таймери
У JMeter конкурентність змодельована потоками: багатопотоковий каркас дає одночасне семплювання багатьма потоками й — окремо — одночасне семплювання різних функцій окремими групами потоків. Друге варте уваги більше: це прямий інструментальний відповідник міксу із моделі навантаження. «Пошук» і «оформлення замовлення» тут зазвичай не один сценарій із розгалуженням, а дві групи потоків.
Кроки всередині групи звуть семплерами (samplers), і саме перед кожним семплером інструмент обробляє таймери своєї області дії. Таймери — інструментальна форма (think time): ISTQB описує моделювання робочого навантаження зазвичай саме цією парою — кількість віртуальних користувачів (потоків виконання) і час на роздуми. Постійна пауза тримає однаковий проміжок між запитами, випадкова — проміжок, де всі інтервали однаково ймовірні, а загальна затримка є сумою випадкового значення й зміщення.
А ось граблі, на які наступають усі: таймер обробляється перед семплером, а не після нього.
- Таймери обробляються перед кожним семплером у своїй області дії; якщо їх кілька — обробляються всі.
- Таймер, який не в тій самій області, що семплер, не обробиться взагалі.
- Щоб застосувати таймер до одного семплера, його додають дочірнім елементом цього семплера.
- Щоб отримати паузу після семплера, таймер додають до наступного семплера або роблять дочірнім елементом
Flow Control Action Sampler.
k6: сценарій кодом і чотири стадії скрипта
Інструменти «сценарій кодом» дають ту саму модель функціями замість дерева елементів. Але код перф-скрипта не є одним блоком: у k6 в нього чотири стадії, і вони завжди йдуть в одному порядку — це й зветься життєвим циклом перф-скрипта (test lifecycle).
| Стадія | Що робить | Скільки разів |
|---|---|---|
| Ініціалізація | Завантажує файли, імпортує модулі, оголошує функції | Раз на віртуального користувача |
| Підготовка (опційна) | Готує середовище й генерує дані | Раз |
| Код користувача | Виконується стільки разів, скільки задають опції | Раз на ітерацію |
| Прибирання (опційне) | Постобробка даних і закриття середовища | Раз |
Знати поділ треба не заради архітектури, а тому що в кожної стадії свої заборони, і саме вони визначають, де готувати дані.
- Ініціалізація не вміє HTTP — навмисно: заборона гарантує відтворюваність стадії між прогонами, бо відповідь на протокольний запит динамічна й непередбачувана. Наслідок: «залогінитися й дістати токен» тут зробити не можна — це робота підготовки, де доступний повний API. Дзеркальна межа: код користувача не читає локальних файлів і не імпортує модулів.
- На кожній ітерації користувач скидається: дійшовши до кінця функції, він повертається на початок, і в межах цього перезапуску куки очищаються, а TCP-зʼєднання можуть бути розірвані. «Залогінився раз і ходить увесь тест» без окремих заходів не виходить — звідси й тема кук і сесій у перф-скриптах.
- Впала підготовка — не буде, тож дані невдалого прогону лишаються в системі й псують наступний. ISTQB окремо вимагає відновити початкові дані перед наступним циклом.
- У підготовки власний — типово 60 секунд; перевищення валить тест ще до старту віртуальних користувачів. Це окремий клас падінь, який не є системи під навантаженням.
У Gatling межа стоїть дзеркально: хуки до й після прогону є (before і after), але користуватися SDK в них не можна — тільки власним кодом. Окремо Gatling дає фіктивну дію, що імітує виклик віддаленої системи із заданим часом відповіді, — коли справжню систему викликати не можна, а метрики міряти треба.
Перевірки вмісту: без них ви міряєте швидкість помилки
Перф-тест без перевірки вмісту відповіді міряє швидкість сторінки помилки. Канонічний набір перевірок перф-сценарію — код відповіді плюс вміст. Тут ми дивимось на це з боку інструмента: чим саме кожен із трьох перевіряє тіло відповіді. Валідація відповідей як предмет — у главі Кореляція, параметризація і тестові дані.
- Перевірка без явної умови нічого не стверджує про значення. У Gatling, якщо крок валідації не визначено явно, виконується неявний
exists— тобто «щось знайшлося», а не «значення правильне». - тривалості змінює семантику звіту. JMeter має елемент, який перевіряє, що кожна відповідь надійшла в межах заданого часу: довша позначається як невдала. Тобто повільна відповідь потрапляє в , а не лише в хвіст розподілу.
- Дві найчастіші причини «асерт не спрацював» банальні: в асерті відповіді JMeter шаблон за замовчуванням працює в багаторядковому режимі, тобто метасимвол
.не збігається з переносом рядка, і регістр теж важливий. - Перевірка мусить витримувати відмову системи: «скрипт не повинен нічого припускати про HTTP-відповідь». Приклад — перевірка довжини тіла: вона працює, поки система віддає нормальні відповіді, а коли та починає падати, тіла може не бути, і замість зафіксованої відмови ви отримуєте помилку в самому скрипті.
Окремо — компроміс, який не люблять називати вголос. Настанови JMeter радять уживати якомога менше асертів, а k6 попереджає, що результат кожної перевірки записується окремо. Це не «перевірки шкідливі»: без перевірок тест дешевший і брехливіший. Канон SRE додає вимогу згори — навантажуючи stateful-сервіс, тест має відстежувати стан і перевіряти правильність під високим навантаженням: саме там проявляються тонкі помилки конкурентності.
Пороги: єдиний машинний вердикт прогону
Поріг (threshold) — це критерій pass/fail, який ви задаєте для метрик свого тесту: якщо продуктивність системи не задовольняє його умов, тест завершується зі статусом провалу. Призначення назване прямо: пороги — спосіб кодифікувати SLO (вимоги до продуктивності — окрема глава).
Вираз порога має форму <aggregation_method> <operator> <value> — наприклад, http_req_duration: ['p(95)<500']. Усі пороги виконано — код виходу нуль, хоч один провалено — ненульовий; довга форма дозволяє ще й обірвати прогін на провалі.
Найважливіша межа теми — та, на якій плутаються найчастіше: чеки (checks) у k6 тест не валять. Невдалі чеки не спричиняють переривання й не завершують тест провалом — інструмент лише веде облік частки невдалих чеків. Кожен чек створює rate-метрику, і щоб чек обірвав або провалив тест, його треба поєднати з порогом. При цьому чеки потрібні: іноді навіть відповідь 200 містить повідомлення про помилку.
Розподілена генерація: коли одна машина не тягне
(distributed load generation) — це навантаження, розподілене між кількома машинами. Дока k6 називає дві причини, коли вона потрібна: імітувати навантаження з кількох локацій одночасно і масштабувати понад те, що тягне одна машина. JMeter формулює те саме з боку симптому: варіант існує, коли клієнтська машина не здатна зімітувати достатньо користувачів або обмежена на рівні мережі. Друге — мережеве обмеження — потужнішим процесором не лікується.
Спершу варто довести, що одна машина не тягне. Числа дає дока k6: один процес ефективно використовує всі ядра, один екземпляр тягне 30 000–40 000 одночасних користувачів, і якщо вам не треба більше за 100 000–300 000 запитів за секунду, одного екземпляра, найімовірніше, досить.
Далі — найдорожча пастка теми. Дві найпоширеніші реалізації працюють протилежно:
| Інструмент | Що робить із профілем |
|---|---|
| JMeter | Той самий план виконують усі сервери; навантаження між ними не розподіляється — 1000 потоків на 6 серверах дають 6000 потоків |
| k6 | Навантаження ділиться між екземплярами через сегмент виконання (execution segment) |
Сплутати їх означає помилитися рівно в кратність кількості вузлів. Решта підводних каменів:
- Керівна машина сама стає вузьким місцем: у JMeter при багатьох серверах перевантажитися може сама керівна машина, бо семпли за замовчуванням повертаються синхронно, щойно згенеровані, і це може вплинути на максимальну () тесту.
- Пороги не зводяться самі. У k6 кожен екземпляр обчислює пороги незалежно, метрики звітуються окремо — тобто «p95 усього тесту» в розподіленому прогоні не існує з коробки.
- Дані на вузли не їдуть: у JMeter файли даних керівна машина не розсилає, вони мусять лежати на кожному сервері.
- Крок «один користувач по токен» ламається першим. У Gatling Enterprise Edition профіль за замовчуванням розподіляється між генераторами, тож користувача, який дістає токен авторизації, виконає лише один вузол — решта лишиться без токена.
- Де ставити генератори. Мета — щоб запити йшли з різних місць; але виконувати генератор на машині застосунку хоч і можна, це додає їй навантаження, і результати будуть дещо зіпсовані.
Критерії вибору: чому «який інструмент кращий» — не питання
Перше, що каже канон: загалом інструмент обирають для організації, а не лише для проєкту. Далі — чотири групи критеріїв:
- Сумісність — які протоколи підтримує (це названо «дуже важливим аспектом вибору»), які має інтерфейси до зовнішніх компонентів, серед яких прямо згадана інтеграція в процес CI, і на яких платформах працює.
- Масштабованість — кількість ліцензій, вимоги до машини генерації, здатність генерувати навантаження з кількох точок присутності.
- Зрозумілість — який рівень технічних знань потрібен для роботи.
- Моніторинг — чи достатній вбудований і, головне, чи можна звʼязати його з визначеними .
Найдорожчу помилку вибору канон коментує різко: зрозумілість часто недооцінюють, і це призводить до того, що невмілі тестувальники неправильно налаштовують тести, а ті натомість дають неточні результати. Тобто «візьмемо open-source, у нас же є QA» — рішення про бюджет, а не про його економію: для будь-якого обраного інструмента розуміння того, як він працює, потребуватиме часу й бюджету.
Звідси й порядок питань: спершу протокол (а не мова скриптів), потім хто це писатиме, потім чи звʼяжеться моніторинг із транзакціями.
Типові помилки
«Час відповіді виріс — система деградує». Межі генератора як окремий предмет розбирає глава Середовище, генератори навантаження і достовірність; тут вони цікавлять нас як властивість інструмента. Виглядає як знахідка, а насправді першим треба виключити генератор: якщо інструмент використовує 100% процесора, тест зазнає обмежень , і метрики покажуть значно більший , ніж є насправді. Пороги здоровʼя генератора названі числами: щонайменше 20% простою процесора, памʼять не вище 90%, мережа не в поличці.
«У звіті помилки — значить система відмовляє». Виглядає як відмова системи, а насправді помилки розводяться за : socket: too many open files — це генератор досяг межі відкритих дескрипторів; read: connection reset by peer — зʼєднання скинула цільова система; context deadline exceeded — запит пішов, але система не відповіла вчасно.
«Швидший сервер розвантажує генератор». Виглядає логічно, а насправді навпаки: швидший сервер змушує JMeter працювати більше, бо повертає відповідь швидше. Звідси й наступна пастка: якщо неправильно підібрати кількість потоків, ви зіткнетеся з проблемою Coordinated Omission, яка може дати хибні або неточні результати.
«Подивлюся в дерево результатів під час прогону». Виглядає як зручний контроль, а насправді тест починає міряти власний інтерфейс: більшість елементів Listener тримає копію кожного семпла, який показує. Канон радить протилежне — режим командного рядка, якнайменше елементів Listener, CSV замість XML.
Підсумок
- Інструментарій навантаження — це три ролі, а не три продукти: генератор, керування й засіб моніторингу. Питання при виборі — що інструмент робить сам, а що доведеться добудувати.
- JMeter не є браузером — він працює на протокольному рівні: не виконує JavaScript зі сторінок і не рендерить HTML. Звідси і його дешевизна, і його сліпа зона.
- «Чому не Selenium» має дві половини: ціна (кожен віртуальний користувач тягне браузер) і предмет виміру (клієнтський досвід протоколом не зміряти).
- Вердикт прогону дає поріг, а не перевірка: невдалі чеки лише накопичують частку невдач.
- Розподілену генерацію треба доводити, а не оголошувати — і перед тим, як писати «система деградує», показати графік ресурсів генератора.
Можливі питання
«Чому для навантажувального тестування не використовують Selenium або Playwright?» Дивляться, чи розумієте ви механізм, а не гасло: інструменти навантаження працюють на протокольному рівні й не запускають браузера, тому один процес тягне тисячі віртуальних користувачів. І одразу друга половина — браузерний рівень усе одно потрібен, бо протокольний не бачить рендерингу й інтерактивності.
«Що JMeter не вміє, хоча виглядає як браузер?» Перевіряють, чи знаєте ви несуче обмеження: JMeter не виконує JavaScript зі сторінок і не рендерить HTML. Наслідок — послідовність запитів і динамічні значення доводиться відтворювати вручну, звідси кореляція.
«Чим check відрізняється від threshold?» Класична пара на плутанину. Чек нічого не валить — він лише веде облік частки невдалих перевірок; поріг це машинний критерій pass/fail, який змінює код виходу прогону.
«Як запустити навантаження з кількох машин і що там ламається?» Слухають, чи ставите ви спершу питання «а одна машина точно не тягне», і чи знаєте, що інструменти поводяться протилежно: один виконує той самий план на кожному вузлі, інший ділить профіль між екземплярами.
«За якими критеріями ви обиратимете інструмент?» Питання не про назви — очікують структуру: протоколи й платформи, інтеграція з CI, масштабованість, знання команди, звʼязок моніторингу з транзакціями. Відповідь «візьмемо безкоштовний» без згадки про час і навчання читається як брак досвіду.
Джерела
Карта інструментів: три ролі замість трьох продуктів
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — три ролі інструментарію, мета генератора й ціна кількох точок присутності.
- Grafana k6 — documentation home — самоопис k6 і його мета через SLO.
- Gatling — Simulation — популяція як сценарій із
injection profile, кілька популяцій паралельно. - Grafana k6 — Results output — дві форми виводу: зведена статистика й окремі точки з мітками часу.
Протокольний рівень: чому JMeter — не браузер
- Apache JMeter — головна сторінка проєкту — «JMeter is not a browser, it works at protocol level»: не виконує JavaScript зі сторінок і не рендерить HTML.
- Grafana k6 — Using k6 browser — призначення браузерного рівня, вимога Chromium на машині, окремі блоки браузерних метрик.
- Grafana k6 — documentation home — змішування браузерних тестів з іншими тестами продуктивності в одному прогоні.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — запис проти програмування послідовності запитів як два способи імплементації скрипта.
JMeter: групи потоків, семплери й таймери
- Apache JMeter — головна сторінка проєкту — конкурентність через потоки, окремі групи потоків для одночасного семплювання різних функцій.
- Apache JMeter — User's Manual: Component Reference (таймери, екстрактори, асерти, набір даних) — постійна й випадкова паузи, параметри затримки, правила області дії таймерів.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — моделювання навантаження через кількість віртуальних користувачів і час на роздуми.
- ISTQB Glossary — означення
think timeіload generator.
k6: сценарій кодом і чотири стадії скрипта
- Grafana k6 — Test lifecycle — чотири стадії скрипта, заборони кожної, скидання користувача між ітераціями, таймаут підготовки.
- Gatling — Simulation — хуки
before/afterі заборона користуватися SDK всередині них. - Gatling — Scenario — фіктивна дія із заданим часом відповіді замість виклику недоступної системи.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — вимога відновити початкові дані перед наступним циклом тестування.
Перевірки вмісту: без них ви міряєте швидкість помилки
- Gatling — Checks — код відповіді плюс вміст як набір перевірок перф-сценарію й неявний
exists. - Apache JMeter — User's Manual: Component Reference (таймери, екстрактори, асерти, набір даних) — асерт тривалості й усталені режими шаблону в асерті відповіді.
- Apache JMeter — Best Practices — рекомендація вживати якомога менше асертів.
- Grafana k6 — Running large tests — ціна кожної перевірки й вимога не припускати нічого про відповідь.
- Google SRE Book — Chapter 22: Addressing Cascading Failures — перевірка правильності під високим навантаженням для stateful-сервісів.
Пороги: єдиний машинний вердикт прогону
- Grafana k6 — Thresholds — означення порога, форма виразу, код виходу, обрив прогону на провалі.
- Grafana k6 — Checks — чеки не валять тест і потребують порога, щоб дати вердикт.
- Grafana k6 — Metrics — , на які накладають пороги.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — критерії продуктивності як предмет вимірювання прогону.
Розподілена генерація: коли одна машина не тягне
- Apache JMeter — Remote (Distributed) Testing — симптом-причина розподіленого прогону, множення потоків на кількість серверів, вартість керівної машини, файли даних.
- Grafana k6 — Running large tests — коли розподілена генерація потрібна, ємність одного екземпляра, ділення навантаження й незалежний розрахунок порогів.
- Gatling — Injection — шардування профілю між генераторами й крок отримання токена одним користувачем.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — запити з різних місць як мета й спотворення проміжними стрибками.
Критерії вибору: чому «який інструмент кращий» — не питання
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — вибір інструмента для організації, чотири групи критеріїв, ціна недооціненої зрозумілості, ліцензійні моделі.
- Grafana k6 — documentation home — розширюваність та інтеграція як заявлені властивості інструмента.
- Gatling — Simulation — популяції як спосіб описати кілька профілів в одному прогоні.
- Grafana k6 — Results output — форма виводу результатів як критерій інтеграції з наявним інструментарієм.
З чого складається інструментарій навантажувального тестування?
Не з продуктів, а з трьох ролей, і сильна відповідь починається саме з цього. (load generator) піднімає багато клієнтських екземплярів, які ходять у систему за заданим , і паралельно збирає виміри для звіту. керування дає кнопки «старт» і «стоп», зводить метрики докупи й малює графіки. Засіб моніторингу дивиться не на клієнтів, а на саму систему під тестом — черги вебсервера, памʼять, вільне місце на диску — і працює одночасно з прогоном. Сучасні продукти зазвичай суміщають перші дві ролі в одній коробці, а третю доводиться докуповувати чи піднімати самотужки. Практичний сенс такої розкладки: питання «який інструмент кращий» перетворюється на «що він закриває сам, а що я добудовуватиму руками», і саме друга частина зʼїдає час на проєкті.
Чому кажуть, що JMeter — не браузер?
Бо він живе на рівні протоколу: для сервера він виглядає як клієнт (навіть як багато клієнтів одночасно), але JavaScript зі сторінок не виконує і HTML не рендерить. З цього обмеження ростуть три наслідки. Перший — дешевий: без й без виконання скриптів лишається робота із сокетами, тому тисячі користувачів вміщаються в один процес. Другий — клієнтську частину досвіду ви не зміряли: скільки сервер віддавав розмітку і скільки людина чекала на готову картинку — величини різні, і друга з протоколу не виводиться. Третій — послідовність запитів доводиться відтворювати самому, бо динамічні значення ніхто за вас не підставить; звідси й кореляція. На співбесіді відповідь «JMeter повільний, тому браузер не тягне» слабка: справа не у швидкості, а в тому, що браузера там немає взагалі.
Чому для навантаження не беруть готову e2e-сюїту на Selenium чи Playwright?
Відповідь має дві половини, і половинчаста відповідь читається як брак досвіду. Перша половина — ціна: кожен віртуальний користувач тягне справжній браузер, тож тисяча користувачів перетворюється на ферму машин, а не на один процес. Друга, важливіша, — предмет виміру: e2e- міряє один сценарій в одному браузері, тоді як від перф-прогону чекають поведінки системи під заданим . Але з цього не випливає «браузери в перфі не потрібні»: обидва рівні потрібні для різного, і k6 прямо дозволяє змішувати браузерний тест з іншими в одному прогоні — протокольний рівень створює фон, а кілька браузерних користувачів міряють те, що бачить людина.
Що дає браузерний рівень, чого не дає протокольний?
Він відповідає на питання про фронтенд, які кодом відповіді не ловляться: чи всі елементи інтерактивні, як почувається інтерфейс, поки бекенд обробляє тисячі одночасних протокольних запитів, чи немає спінера, який висить і не зникає. Останній приклад найпоказовіший: у мережі всі відповіді успішні, а користувач дивиться на крутилку — жодна метрика протокольного рівня цього не покаже. Механізм простий: браузерний модуль k6 піднімає справжню сторінку, дає керувати нею через API рівня браузера й знімає фронтендові виміри, а ціна названа прямо — на машині має стояти браузер на основі Chromium. Метрики двох рівнів у зведенні йдуть окремими блоками, тож ставити поруч http_req_duration і browser_web_vital_lcp безглуздо: це різні предмети виміру, а не два способи зміряти те саме.
Що таке група потоків у JMeter і навіщо їх кілька в одному плані?
Конкурентність у JMeter змодельована потоками: скільки потоків — стільки одночасних віртуальних користувачів. Цікавіше друге: різні функції системи семплюються окремими групами потоків, і саме так мікс операційних профілів із моделі навантаження перекладається мовою інструмента. Тобто «пошук» і «оформлення замовлення» — це зазвичай не один сценарій із розгалуженням усередині, а дві групи потоків зі своєю кількістю користувачів і своїми паузами. Різниця не косметична: саме кількість потоків у кожній групі й задає, у якій пропорції операції зайдуть у прогін. Кроки всередині групи звуться семплерами (samplers), і саме навколо них крутиться вся решта конфігурації — таймери, екстрактори, .
Ви поставили таймер, а пауза виявилась не там, де очікували. Чому?
Бо таймер відпрацьовує до кроку, а не слідом за ним, і накриває всі семплери своєї області дії. Звідси три типові промахи. Перший: таймер кинули в кінець групи, розраховуючи на паузу після останнього кроку, — насправді він відпрацює перед кожним семплером у цій області. Другий: таймер лежить поза областю дії потрібного семплера — тоді він не обробиться взагалі, і пауз у сценарії просто немає. Третій: у тій самій області опинилося кілька таймерів, і склалися, бо обробляються всі. Правила виходу з цього прості: щоб таймер діяв на один-єдиний крок, його підвішують дочірнім до потрібного семплера; а щоб пауза лягла саме після кроку, таймер переносять на наступний семплер або на Flow Control Action Sampler. І окремо варто памʼятати, навіщо таймери взагалі: ними задають (think time), а робоче навантаження в каноні описують якраз парою «скільки віртуальних користувачів» плюс «які паузи між їхніми діями».
Які стадії має скрипт k6 і навіщо тестувальнику знати цей поділ?
Стадій чотири, і йдуть вони завжди в одному порядку: ініціалізація, підготовка, код користувача, . Ініціалізація вантажить файли, імпортує модулі й оголошує функції — раз на кожного віртуального користувача. Підготовка (стадія необовʼязкова) піднімає середовище й робить дані — один раз на прогін. Код користувача крутиться рівно стільки ітерацій, скільки замовили опції запуску. Прибирання (теж опційне) закриває середовище й розгрібає дані — знову один раз. Знати поділ треба не заради архітектурної краси: кожна стадія має власний список того, чого в ній не можна, і саме ці заборони диктують, де готувати дані: спроба залогінитися «десь на початку файлу» просто не запуститься, а спроба прочитати файл усередині ітерації — теж.
Чому в стадії ініціалізації k6 не можна зробити HTTP-запит?
Заборона навмисна й тримає стадію відтворюваною: відповідь на мережевий запит динамічна й непередбачувана, тож якби ініціалізація ходила в мережу, два прогони стартували б з різних станів. Наслідок прямий: «залогінитися й дістати токен» на цій стадії зробити неможливо — це робота підготовки, де повний API вже доступний, а результат передається користувачам як дані. Межа працює і в інший бік: усередині ітерації не можна ні відкрити локальний файл, ні підтягнути модуль — це справа ініціалізації. На співбесіді тут перевіряють не знання назв функцій, а розуміння, що перф-скрипт — не звичайний скрипт зверху вниз, і що дані готуються не там, де зручно, а там, де дозволено.
Що стається з віртуальним користувачем наприкінці ітерації?
Він скидається: дійшовши до кінця своєї функції, користувач стартує наново, і цей перезапуск зносить куки, а відкриті TCP-зʼєднання може й закрити. Тому улюблена схема «залогінився один раз і ходить увесь прогін» без окремих заходів не працює — на другій ітерації сесії вже немає. Лікується це передачею стану явно: токен готують у підготовці й підставляють у заголовок кожного запиту, або логін роблять частиною самого сценарію, якщо він теж має бути під навантаженням. Побічний ефект розриву зʼєднань теж варто памʼятати: якщо на кожній ітерації відкривається нове TCP- і TLS-, ви міряєте систему в режимі, у якому реальний браузер її не тримає.
Чим check відрізняється від threshold у k6?
Це класична пара на плутанину, і межа тут різка: чек тест не валить, а поріг валить. Провалена перевірка не перериває прогін і не робить його статус провальним — інструмент просто рахує, яка частка перевірок не пройшла, бо кожен чек створює rate-метрику. Поріг (threshold) — умова, яку ви самі накладаєте на метрику прогону, щоб інструмент виніс за нею вердикт: не вклалися — тест позначено провальним і код виходу ненульовий, а довга форма запису вміє ще й обірвати прогін одразу. Вираз має форму «метод агрегації, оператор, значення» — наприклад, http_req_duration: ['p(95)<500']. Практичний висновок для CI: гейтом працює саме поріг, тож щоб перевірки впливали на вердикт, їхню rate-метрику треба накрити порогом. І це ж відповідь на питання «як пороги повʼязані з SLO»: вони і є спосіб записати SLO машинною мовою.
Перф-тест зелений, часи чудові — а система насправді віддавала помилки. Як це можливо?
Так виглядає прогін без перевірки вмісту відповіді: він чесно міряє швидкість, з якою система віддає сторінку помилки. Канон вимагає перевіряти дві речі одразу: і код відповіді, і те, що всередині, — бо навіть 200 цілком може нести повідомлення про збій. Тут же сидить друга пастка, характерна для Gatling: якщо крок валідації не описали явно, спрацьовує неявний exists, тобто перевірка стверджує «щось знайшлося», а не «значення правильне». Тож на питання «які асерти в перф-тесті» правильна відповідь — не «статус 200», а «статус плюс маркер того, що операція справді відбулася».
Скільки перевірок ставити в перф-скрипт?
Тут доводиться шукати баланс, про який зазвичай мовчать. З одного боку, настанови JMeter прямо просять не розкидатися асертами, а дока k6 нагадує: підсумок кожної перевірки лягає у звіт власним записом, тобто перевірки коштують ресурсів генератора. З іншого — прогін без перевірок обходиться дешевше, а бреше більше, бо міряє швидкість . Розумна межа: перевіряти те, що відрізняє успішну транзакцію від невдалої, і не перевіряти те, що не змінює вердикту. Окремо варто памʼятати вимогу «нічого не припускати про відповідь»: класична перевірка довжини тіла працює, поки система здорова, а щойно вона починає падати, тіла може не бути взагалі — і тоді замість чесно зафіксованої відмови прогін дає падіння самого скрипта. Для stateful-сервісів канон додає ще один пункт: під високим навантаженням тест мусить стежити за станом і звіряти коректність даних, бо саме там вилазять тонкі помилки конкурентності, яких на одному користувачі не видно.
Скрипт краще записати чи запрограмувати?
Обидва способи канонічні, і різниця в тому, чим ви платите. Запис обміну зазвичай дає точнішу імітацію реальної системи: інструмент фіксує ту саму послідовність запитів, яку насправді робив клієнт. Але масштабованим і підтримуваним записаний скрипт стає лише після параметризації й документування, а сама параметризація буває довгою роботою. Програмування спирається на ваше знання правильної послідовності — і тому легко пропускає крок, без якого сценарій на бойових даних не відтворюється. На практиці записом користуються як розвідкою, а далі переписують сценарій руками — бо записаний трафік майже завжди треба чистити: прибирати сторонні домени, виносити в набір і, головне, робити кореляцію — підставляти динамічні значення (ідентифікатори сесій, , ідентифікатори кошика), які браузер підставляв би сам.
Чому не варто дивитися дерево результатів під час прогону?
Бо прогін починає міряти сам себе. Більшість елементів Listener у JMeter тримає копію кожного показаного семпла, тож на довгій дистанції ці копії зʼїдають памʼять і процесор тієї самої машини, що генерує навантаження, — і виміри поїдуть. Канонічна порада протилежна звичці: запускати в режимі командного рядка, тримати мінімум елементів Listener, писати вивід у CSV, а не XML. Дивитися на прогін у реальному часі при цьому можна — але через окремий канал моніторингу, а не через елемент, який складає всі відповіді в памʼять. Це той випадок, коли зручність GUI прямо конвертується в неправильні числа у звіті.
Час відповіді в нічному прогоні виріс удвічі. Це деградація системи?
Поки не подивилися на машину-генератор — це ще не висновок, а гіпотеза. Якщо інструмент упирається в 100% процесора, він сам потрапляє під , і в звіті часи виявляються значно більшими за реальні. Тому перед тим, як писати «сервіс деградує», показують графік ресурсів машини навантаження, і пороги здоровʼя тут названі числами: щонайменше пʼята частина процесора має лишатися вільною, памʼять — не вище девʼяноста відсотків, мережа — не в поличці. Побічний, але корисний факт з тієї ж опери: швидший сервер навантажує генератор сильніше, а не слабше, бо відповіді повертаються частіше й інструмент встигає робити більше роботи. І окремо — неправильно підібрана кількість потоків призводить до проблеми Coordinated Omission, а вона, за настановами JMeter, дає хибні або неточні результати.
У звіті прогону сотні помилок. Це система відмовляє?
Не обовʼязково — помилки треба спершу розвести за , і текст помилки це прямо каже. socket: too many open files означає, що межі досяг генератор: у нього скінчилися дескриптори файлів, і жодного стосунку до системи під тестом ця помилка не має. read: connection reset by peer — навпаки, зʼєднання скинула цільова система, і це вже її поведінка під навантаженням. context deadline exceeded — запит пішов, але вчасної відповіді не було, тобто система жива, але не встигає. Практичний порядок дій такий: спочатку відфільтрувати помилки генератора, потім рахувати частку відмов від того, що лишилося, і тільки після цього заводити дефект. Звіт, у якому всі помилки звалені в одне число «error rate», для розмови з розробниками не годиться.
Коли розподілена генерація справді потрібна і як це довести?
Причин рівно дві: імітувати навантаження одночасно з кількох локацій і масштабуватися понад те, що тягне одна машина. Другу причину треба доводити числами, а не відчуттям: один екземпляр k6 ефективно використовує всі ядра й тримає порядку тридцяти-сорока тисяч одночасних користувачів, а якщо цільова інтенсивність не перевищує сотні-трьохсот тисяч запитів за секунду, одного екземпляра, найімовірніше, вистачить. З боку JMeter те саме формулюється через симптом: клієнтська машина не здатна зімітувати потрібну кількість користувачів або впирається в мережу. Друге лікується тільки розподілом — потужніший процесор мережевого обмеження не знімає. І окремо про розміщення генераторів: сенс кількох майданчиків у тому, щоб трафік ішов не з однієї точки, але додають вони не лише реалізму, а й , бо проміжні мережеві стрибки самі вносять затримки; а генератор на машині застосунку взагалі псує вимір, бо додає навантаження тій системі, яку ви міряєте.
Прогін переїжджає на шість машин. Що зламається першим?
Найдорожча помилка — сплутати дві протилежні моделі розподілу. У JMeter кожен вузол бере план цілком і нічого ні з ким не ділить, тож тисяча потоків, розкладена на шість серверів, обертається шістьма тисячами; k6 навпаки ділить навантаження між екземплярами через сегмент виконання. Помилитися тут означає промахнутися рівно в кратність кількості вузлів — або в шість разів перевантажити прод, або в шість разів недовантажити стенд і закрити задачу зеленою. Далі йде список дрібниць, які валять саме перший розподілений прогін: файли з тестовими даними клієнт на вузли не розсилає, тож вони мусять лежати на кожному; там, де профіль шардується між генераторами, крок «один користувач іде по токен авторизації» виконає лише один вузол, а решта лишиться без токена; у k6 пороги кожен екземпляр рахує окремо, тому спільного p95 по всьому тесту з коробки не існує; а керівна машина JMeter при багатьох генераторах стає вузьким місцем, бо семпли повертаються до неї синхронно й це може обмежити тесту.
На що ви дивитиметесь, обираючи інструмент навантаження?
Від кандидата тут чекають структуру, а не назву улюбленого продукту, і починається структура з рамки: інструмент обирають для організації, а не під один проєкт. Далі йдуть чотири групи. Сумісність: перелік протоколів (найважливіший пункт — тут інструмент або підходить, або відпадає), інтерфейси до зовнішніх систем, зокрема заїзд у CI, і підтримані платформи. Масштабованість: ліцензійна модель, вимоги до машин генерації, уміння лити трафік із кількох майданчиків одночасно. Зрозумілість: наскільки технічно підкованою має бути людина, щоб цим користуватися. Моніторинг: чи вистачає вбудованого і чи вміє він привʼязувати свої числа до ваших транзакцій, бо графік процесора, який ні з чим не корелює, вирішує мало. Порядок питань із цього й випливає: протокол — перший, далі людина, яка це писатиме й підтримуватиме, і аж потім звʼязка метрик із транзакціями — а не «якою мовою пишуться сценарії».
Чому «беремо безкоштовний інструмент — і зекономимо» зазвичай не спрацьовує?
Бо зрозумілість інструмента — найчастіше недооцінений критерій, і платити за неї доводиться в будь-якому разі. Канон формулює наслідок жорстко: коли інструмент складніший за рівень команди, тести конфігурують неправильно, а неправильно налаштований прогін дає неточні результати — тобто ви платите не грошима, а хибними рішеннями, ухваленими за цими результатами. Хоч би що ви обрали, команді доведеться витратити час і гроші, щоб розібратися, як воно влаштоване: на навчання, на перші зіпсовані прогони, на побудову звітності. Тому в порівнянні варіантів чесно ставити поруч не тільки ціну ліцензій, а й вартість входу команди — і питання «хто це писатиме та підтримуватиме через півроку» задавати до вибору, а не після.
Три ситуації, у яких інструмент вирішує, чи буде висновок про продуктивність правдою: звіт нічного прогону, де «деградацію» дав не сервіс, а машина навантаження; скрипт k6, де дані готують на дозволеній стадії, гейтом працює поріг, а браузерний сценарій домішаний до протокольного; і переїзд прогону на шість машин, де найдорожча помилка — сплутати множення з діленням. Скрізь — що дивитися і чому саме це.
Кейс 1. Звіт нічного прогону: здала система чи задихнувся генератор
Уранці в чаті: «сервіс просів удвічі, заводьте баг». Ось що насправді лежить у звіті — разом із метриками самої машини, з якої лився трафік.
Прогін 03:00–03:40, ціль: 1200 VU, профіль checkout
http_req_duration ....... avg=1.94s p(90)=4.1s p(95)=6.4s p(99)=11.8s
http_req_failed ......... 7.31% (4 118 з 56 308)
iterations .............. 56 308
vus_max ................. 1 200
Розкладка помилок:
socket: too many open files ............. 3 402
read tcp: connection reset by peer ......... 618
context deadline exceeded ................... 98
Машина-генератор, той самий інтервал:
CPU ..... 99–100% (idle 0–1%)
RAM ..... 68%
NIC ..... 942 Mbit/s з 1 Gbit/s
Що дивитися і чому:
- Перший рядок висновку робить не сервіс, а
CPU 99–100%на генераторі. Інструмент, який упирається в процесор, працює під : він не встигає надсилати й вичитувати вчасно, і у звіті виходить помітно більшим за справжній. Орієнтир здоровʼя простий — щонайменше пʼята частина процесора має лишатися вільною, памʼять не заходити за девʼяносто відсотків, мережа не стояти в поличці. Тут порушено два пункти з трьох: процесор і мережа (942 з 1000 Mbit/s — це вже стеля каналу, а не запас). - Понад чотири пʼятих «помилок системи» — помилки генератора.
socket: too many open filesозначає, що на машині навантаження скінчилися дескриптори файлів; система під тестом цих запитів навіть не бачила. Заводити за ними дефект — витрачати час розробників на чужу проблему. - Дві інші помилки — уже про систему, і вони різні.
read: connection reset by peer— зʼєднання розірвала цільова сторона (типово черга чи ліміт з боку сервера або балансувальника).context deadline exceeded— запит пішов, а вчасної відповіді не було: система жива, але не встигає. Це два різні діагнози, і зводити їх в одне число «error rate 7.31%» означає втратити всю діагностичну інформацію. - Правильний наступний крок — не баг, а повторний прогін. Підняти ліміт дескрипторів, рознести навантаження на кілька машин або знизити кількість користувачів до тієї, яку машина тягне чесно, — і тільки з чистого прогону робити висновок про продуктивність сервісу.
- Контрінтуїтивний бонус до цієї історії. Якщо після оптимізації сервер став швидшим, генератор навантажується сильніше, а не слабше: відповіді повертаються частіше, і на кожен цикл інструмент має зробити більше роботи. Тож «раніше вистачало однієї машини» після релізу може перестати бути правдою.
- Окремо про Coordinated Omission. Настанови JMeter називають цей клас прямо: якщо неправильно підібрати кількість потоків, ви зіткнетеся з проблемою Coordinated Omission, а вона дає хибні або неточні результати. Це та сама тема, що й межі генератора: кількість потоків підбирають під машину, а не призначають.
- І про звичку дивитися прогін «наживо». Відкрите дерево результатів у GUI зберігає копію кожного показаного семпла, тобто зʼїдає памʼять тієї самої машини. Довгі прогони запускають у режимі командного рядка з мінімумом елементів
Listenerі виводом у CSV, а спостерігають за ними через окремий канал моніторингу.
Кейс 2. k6: де готувати дані, що робить гейтом і як домішати браузерного користувача
Задача типова: тримати чотиригодинний протокольний фон на API замовлень і паралельно міряти, що при цьому бачить людина в інтерфейсі. Скрипт нижче показує обидва рівні в одному прогоні й розкладає код за стадіями життєвого циклу.
import http from 'k6/http';
import { check } from 'k6';
import { browser } from 'k6/browser';
// Стадія ініціалізації: імпорти й константи. HTTP тут неможливий.
const BASE = __ENV.BASE_URL;
// Бюджет клієнтської метрики беруть із канону Core Web Vitals — глава про фронтенд-продуктивність.
const LCP_BUDGET_MS = __ENV.LCP_BUDGET_MS;
export const options = {
scenarios: {
api: {
executor: 'ramping-vus',
exec: 'protocolUser',
startVUs: 0,
stages: [
{ duration: '3m', target: 300 },
{ duration: '30m', target: 300 },
{ duration: '2m', target: 0 },
],
},
ui: {
executor: 'constant-vus',
exec: 'browserUser',
vus: 2, // браузерний рівень міряє, а не навантажує
duration: '35m',
options: { browser: { type: 'chromium' } },
},
},
thresholds: {
// саме пороги дають прогону машинний вердикт
'http_req_failed{scenario:api}': ['rate<0.01'],
'http_req_duration{scenario:api}': ['p(95)<500'],
'checks{scenario:api}': ['rate>0.99'],
// поріг клієнтської метрики сюди теж можна поставити — але його значення
// задає канон Core Web Vitals, а він розбирається в окремій главі розділу
'browser_web_vital_lcp': [`p(95)<${LCP_BUDGET_MS}`],
},
};
// Стадія підготовки: виконується один раз, тут доступний повний API.
export function setup() {
const res = http.post(`${BASE}/api/login`, JSON.stringify({
user: __ENV.LOAD_USER,
pass: __ENV.LOAD_PASS,
}), { headers: { 'Content-Type': 'application/json' } });
if (res.status !== 200) {
throw new Error(`логін у setup впав зі статусом ${res.status}`);
}
return { token: res.json('token') };
}
// Код користувача: виконується на кожній ітерації.
export function protocolUser(data) {
const res = http.get(`${BASE}/api/orders?page=1`, {
headers: { Authorization: `Bearer ${data.token}` },
});
check(res, {
'статус 200': (r) => r.status === 200,
'у тілі є список замовлень': (r) => Array.isArray(r.json('items')),
});
}
export async function browserUser() {
const page = await browser.newPage();
try {
await page.goto(`${BASE}/orders`);
await page.waitForSelector('[data-testid="orders-table"]', { state: 'visible' });
// спінер, що не зникає, кодом відповіді не ловиться взагалі
await page.waitForSelector('[data-testid="orders-spinner"]', { state: 'hidden' });
} finally {
await page.close();
}
}
// Стадія прибирання: один раз, і лише якщо підготовка відпрацювала.
export function teardown(data) {
http.del(`${BASE}/api/test-data/orders`, null, {
headers: { Authorization: `Bearer ${data.token}` },
});
}
Що дивитися і чому:
- Логін стоїть у підготовці, і це не стильова примха. На стадії ініціалізації HTTP недоступний навмисно: відповідь сервера непередбачувана, а стадія має бути відтворюваною між прогонами. Тому «дістати токен» — робота підготовки, звідки він їде до користувачів як звичайні дані.
- Токен передається явно, бо на межі ітерацій користувач скидається. Куки очищаються, зʼєднання можуть рватися — схема «залогінився й ходжу весь прогін» без окремих заходів не працює. Якщо логін теж має бути під навантаженням, його роблять кроком сценарію, а не разовою підготовкою.
- Виняток у
setup— свідомий вибір. Мертвий логін валить прогін одразу, а не через сорок хвилин порожніх401. Зворотний бік теж треба знати: якщо підготовка впала, не виконається, і сміття попереднього прогону поїде в наступний. Тому очищення даних не тримають на одному лишеteardown. - У підготовки є власний — типово хвилина. Якщо логін і даних у нього не вкладаються, тест помирає ще до того, як стартує перший . Читати таке падіння як системи під навантаженням — помилка діагностики.
checkтут нічого не валить. Провалена перевірка не перериває прогін і не робить статус провальним — вона лише накопичує частку невдач уrate-метриці. Вердиктом її робить рядок'checks{scenario:api}': ['rate>0.99']у порогах: усі пороги виконано — нульовий код виходу, хоч один провалено — ненульовий, і CI бачить червоне.- Перевірка вмісту потрібна, бо
200успіху не гарантує. Без на список замовлень прогін чесно виміряє, як швидко система віддає порожню відповідь чи повідомлення про помилку — тобто швидкість збою. - Двоє браузерних користувачів проти трьохсот протокольних — правильна пропорція. Браузерний рівень дорогий: на кожного такого користувача потрібен справжній Chromium на машині. Його роль тут — не створювати навантаження, а зафіксувати, що бачить людина, поки бекенд тримає протокольний фон.
- Спінер — саме той дефект, заради якого браузерний рівень і додають. Усі запити можуть повертати
200, а таблиця так і не зʼявиться: рендер заблокований, дані не змержилися, крутилка висить. У метриках протокольного рівня цього немає ніде. - Метрики двох рівнів не змішують.
browser_web_vital_lcpіhttp_req_durationстоять у зведенні окремими блоками, бо міряють різне; порівнювати їх між собою — все одно що порівнювати температуру з вагою. Пороги на них теж ставлять окремо, як у прикладі.
Кейс 3. Прогін переїжджає на шість машин
Одна машина в стелі за процесором, потрібно вдвічі більше користувачів. Команда вирішує розкидати навантаження на шість вузлів — і саме тут інструменти поводяться протилежно, тож копіювати досвід із JMeter у k6 (чи навпаки) не можна.
| Що робите | JMeter (remote testing) | k6 (кілька екземплярів) |
|---|---|---|
| План на 1000 потоків, 6 вузлів | Кожен вузол виконує план цілком → 6000 потоків | Профіль ділиться сегментами виконання → загалом 1000 |
| Тестові дані з файлу | Керівна машина файли не розсилає — вони мусять лежати на кожному сервері | Кожен екземпляр читає свій файл локально |
| Зведення метрик і вердикт | Семпли синхронно повертаються керівній машині, і вона сама стає вузьким місцем | Кожен екземпляр звітує метрики й рахує пороги незалежно |
Що дивитися і чому:
- Спершу доведіть, що переїзд узагалі потрібен. Один екземпляр k6 ефективно використовує всі ядра й тягне десятки тисяч одночасних користувачів, а до сотні тисяч запитів за секунду розподілена схема зазвичай зайва. Виняток, який процесором не лікується, — упертий мережевий ліміт машини: ось із ним допомагає лише рознесення.
- Множення проти ділення — помилка ціною в кратність вузлів. Перенести план «1000 потоків» на шість серверів JMeter і чекати тих самих 1000 означає накрити систему вшестеро сильнішим навантаженням; зробити зворотне припущення в k6 — недовантажити стенд і закрити задачу зеленим прогоном, який нічого не довів.
- Крок «один користувач бере токен» ламається першим. Коли профіль шардується між генераторами, такий крок дістанеться лише одному вузлу, а решта піде в прогін без токена й дасть лавину
401. Виглядає як зламана авторизація в продукті, а насправді — наслідок шардування. - «p95 усього тесту» в розподіленому прогоні з коробки не існує. Пороги кожен екземпляр обчислює на своїй частині вибірки, метрики звітуються окремо. Якщо потрібен єдиний вердикт, метрики зводять зовні — у спільне сховище чи хмарний сервіс, — і саме там рахують зріз.
- Керівну машину теж треба моніторити. У JMeter семпли повертаються до неї синхронно, щойно згенеровані, тож при багатьох генераторах вузьким місцем стає вона сама, і це прямо обмежує тесту. Симптом упізнаваний: додали вузол — сумарна інтенсивність не зросла.
- Не ставте генератор на машину застосунку. Так робити технічно можна, але ви додаєте навантаження тій самій системі, яку міряєте, і результат виходить зіпсованим. З тієї ж причини кілька географічних точок присутності — не безкоштовний реалізм: проміжні мережеві стрибки додають власні , і це видно у звіті як «повільна система».
Карта інструментів і два рівні
- Знаю три ролі інструментарію — , керування, засіб моніторингу — і що перші дві зазвичай приїжджають одним продуктом, а третю беруть окремо; тому обираю не за гаслом «найкращий інструмент», а за відповіддю, що доведеться добудовувати самому.
- Знаю різницю протокольного й браузерного рівнів: перший дешевий, але сліпий до фронтенду, другий тягне справжній Chromium і ловить те, чого код відповіді не показує, — спінер, який не зникає, і мертві елементи інтерфейсу.
- Можу відповісти на «чому не Selenium для навантаження» двома половинами — ціна одного і предмет виміру — та додати, що обидва рівні потрібні для різного й змішуються в одному прогоні.
JMeter: потоки, семплери, таймери
- Памʼятаю несуче обмеження: JavaScript зі сторінок не виконується, HTML не рендериться — звідси і дешевий віртуальний користувач, і потреба відтворювати послідовність запитів самому, з кореляцією динамічних значень.
- Знаю, навіщо в плані кілька груп потоків: різні функції системи розводять по окремих групах, і саме так задають мікс , а не гілками всередині одного сценарію.
- Знаю головні граблі таймера: він обробляється перед семплером, діє на всю свою область, а поза областю не спрацює взагалі; щоб отримати паузу після кроку, таймер вішають на наступний семплер або на
Flow Control Action Sampler.
k6: життєвий цикл і вердикт прогону
- Знаю чотири стадії скрипта в їхньому порядку — ініціалізація, підготовка, код користувача, — скільки разів виконується кожна і чому в ініціалізації немає HTTP: заборона тримає стадію відтворюваною, тож логін по токен — робота підготовки, а імпорти й читання файлів — робота ініціалізації.
- Памʼятаю, що на межі ітерацій користувач скидається: куки чистяться, зʼєднання можуть рватися, тож «залогінився раз і ходжу весь тест» без окремих заходів не працює.
- Знаю два класи падінь, які не є системи: підготовка впала — прибирання не виконається й дані лишаються брудними; підготовка не вклалася у власний (типово 60 секунд) — тест помер ще до старту віртуальних користувачів.
- Не плутаю
checkіthreshold: перший лише накопичує частку невдач черезrate-метрику, а машинний вердикт (код виходу, за потреби обрив прогону) дає поріг у формі «метод агрегації, оператор, значення» — якhttp_req_duration: ['p(95)<500'].
Перевірки вмісту
- Розумію, чому прогін без перевірки вмісту міряє швидкість сторінки помилки, і памʼятаю канонічний набір: код відповіді плюс вміст, бо навіть
200може містити повідомлення про збій. - Знаю про неявний
existsу Gatling — без явної умови перевірка підтверджує лише факт наявності, а не коректність значення — і що тривалості в JMeter переводить повільну відповідь у розряд помилок, змінюючи читання звіту. - Тримаю в голові баланс і його межу: асертів радять якнайменше й кожен чек коштує ресурсів, але прогін без перевірок обходиться дешевше і бреше більше, а для stateful-сервісів під навантаженням перевіряють ще й правильність стану.
Розподілена генерація
- Спершу доводжу, що одна машина не тягне: один екземпляр k6 використовує всі ядра й тримає близько тридцяти-сорока тисяч одночасних користувачів, тож до сотні тисяч запитів за секунду розподіл зазвичай зайвий.
- Не плутаю множення з діленням: у JMeter кожен вузол бере план цілком (тисяча потоків на шести серверах — це шість тисяч), а k6 розкладає профіль по екземплярах сегментами виконання.
- Знаю, що ламається в першому розподіленому прогоні: файли даних не їдуть на вузли; там, де профіль шардується, крок «один користувач бере токен» виконає лише один вузол; у k6 кожен екземпляр рахує пороги окремо (спільного p95 з коробки немає), а керівна машина JMeter сама стає вузьким місцем.
Вибір інструмента й читання результатів
- Можу назвати чотири групи критеріїв — сумісність (протоколи, інтеграція з CI, платформи), масштабованість, зрозумілість, моніторинг із привʼязкою до — і тримаю порядок питань: спершу протокол, далі виконавець, і аж потім звʼязка метрик із транзакціями.
- Розумію, чому недооцінена зрозумілість дорого коштує: неправильно налаштований прогін дає неточні результати, за якими ухвалюють рішення, а вхід команди в будь-який інструмент потребує часу й бюджету.
- Перед висновком «система деградує» дивлюся на здоровʼя генератора (щонайменше пʼята частина процесора вільна, памʼять до девʼяноста відсотків, мережа не в поличці) і розводжу помилки за :
socket: too many open files— дескриптори генератора,read: connection reset by peer— зʼєднання скинула цільова система,context deadline exceeded— вчасної відповіді не було. - Памʼятаю три контрінтуїтивні речі прогону: швидший сервер навантажує генератор сильніше, невдало підібрана кількість потоків дає проблему Coordinated Omission з хибними або неточними результатами, а відкриті елементи
Listenerзмушують тест міряти власний інтерфейс — тому запуск у режимі командного рядка й вивід у CSV.
Квіз
Перед стартом
- Питань: 17
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Які три ролі складають інструментарій навантаження і як вони розкладені по продуктах?
