vyvchy
    Теми розділу

    10 · Performance testing

    Інструменти навантаження: JMeter, k6, Gatling

    Зміст

    «Яким інструментом ганяти навантаження?» — питання, яке на співбесіді звучить так, ніби в нього є одна правильна відповідь. Її немає, і саме це від вас хочуть почути: (load testing tool) обирають під протокол і під команду, а не за списком фіч на головній сторінці.

    Друге, на чому валяться, — спроба гнати навантаження тим, чим гнали e2e: у нас же є на Playwright, запустимо її в тисячу потоків. Глава пояснює, чому так не роблять, — не гаслом «Selenium повільний», а механізмом.

    Карта інструментів: три ролі замість трьох продуктів

    Канон розкладає інструментарій навантаження не на продукти, а на три ролі, і кожен продукт закриває їх у різній мірі:

    РольЩо робить
    Генератор навантаженняСтворює й виконує багато клієнтських екземплярів, що імітують поведінку користувача за заданим операційним профілем; він же збирає метрики для звіту
    Консоль керуванняДає контроль запуску й зупинки генераторів, агрегує метрики транзакцій, показує звіти й графіки
    Засіб моніторингуПрацює одночасно із системою під тестом і спостерігає її поведінку — типово черги вебсервера, памʼять і місце на диску

    У сучасних інструментах перші дві ролі зазвичай злиті в одному інструменті, а третя майже завжди лишається окремою системою. Тому корисне питання при виборі — не «який кращий», а що інструмент робить сам, а що доведеться добудувати.

    спостерігає

    спостерігає

    Консоль керування
    запуск, зупинка, агрегація

    Генератор 1

    Генератор 2

    Система під тестом

    Засіб моніторингу

    спостерігає

    спостерігає

    Консоль керування
    запуск, зупинка, агрегація

    Генератор 1

    Генератор 2

    Система під тестом

    Засіб моніторингу

    Мета генератора — імітувати реальний світ настільки, наскільки це практично, і часто це означає, що запити мусять іти з різних місць, а не лише з місця тестування. Ціна названа одразу: кілька точок присутності додають реалізму, але можуть спотворити результати, якщо проміжні мережеві стрибки дають .

    Самі інструменти описують себе по-різному: k6 називає себе відкритим і розширюваним, а мету зводить до запобігання помилкам і порушенням SLO; Gatling вводить поняття популяції (population) — сценарій разом із injection profile, і популяцій в одній симуляції може бути кілька. Різниться й форма виводу: зведена статистика відповідає «пройшли чи ні», окремі точки з мітками часу — «коли саме почалася деградація».

    Протокольний рівень: чому JMeter — не браузер

    Це несуче твердження глави, і дока JMeter формулює його без пом'якшень: JMeter не є браузером — він працює на протокольному рівні. Щодо вебсервісів він виглядає як браузер (точніше, як кілька браузерів), проте не виконує JavaScript, знайдений у HTML-сторінках, і не рендерить HTML як браузер.

    З цього одного речення випливає майже все інше:

    • дешевий. Немає , немає виконання скриптів (див. Виконання JavaScript та event loop і Архітектуру браузера) — лишається робота з сокетами.
    • Клієнтської частини досвіду ви не виміряли. Час, за який сервер віддав HTML, і час, за який людина побачила сторінку, — різні величини.
    • Послідовність запитів доводиться відтворювати самому. Канон описує імплементацію скрипта як запис або програмування послідовності запитів: перше зазвичай гарантує точну імітацію реальної системи, друге спирається на знання правильної послідовності. Саме звідси береться кореляція — підстановка динамічних значень, які браузер підставляв би сам (окрема глава розділу).

    Браузерний рівень робить протилежний вибір: браузерний модуль k6 додає API рівня браузера й збір фронтендових метрик. Ціна названа прямо — потрібен браузер на основі Chromium, установлений на машині.

    протокольний

    браузерний

    Віртуальний користувач

    Який рівень?

    HTTP-запити напряму

    Справжній Chromium

    Дешево, тисячі VU
    без JS і рендерингу

    Дорого, браузер на кожного VU
    метрики фронтенду

    Система під тестом

    протокольний

    браузерний

    Віртуальний користувач

    Який рівень?

    HTTP-запити напряму

    Справжній Chromium

    Дешево, тисячі VU
    без JS і рендерингу

    Дорого, браузер на кожного VU
    метрики фронтенду

    Система під тестом

    Питання, на які відповідає саме браузерний рівень, названі поіменно: що відбувається з фронтендом, коли застосунок приймає тисячі одночасних запитів із протокольного рівня; чи всі елементи інтерактивні; чи немає спінерів, які довго не зникають. Останнє найпоказовіше — спінер, що висить, не має жодного відображення в коді відповіді 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.

    Підсумок

    1. Інструментарій навантаження — це три ролі, а не три продукти: генератор, керування й засіб моніторингу. Питання при виборі — що інструмент робить сам, а що доведеться добудувати.
    2. JMeter не є браузером — він працює на протокольному рівні: не виконує JavaScript зі сторінок і не рендерить HTML. Звідси і його дешевизна, і його сліпа зона.
    3. «Чому не Selenium» має дві половини: ціна (кожен віртуальний користувач тягне браузер) і предмет виміру (клієнтський досвід протоколом не зміряти).
    4. Вердикт прогону дає поріг, а не перевірка: невдалі чеки лише накопичують частку невдач.
    5. Розподілену генерацію треба доводити, а не оголошувати — і перед тим, як писати «система деградує», показати графік ресурсів генератора.

    Можливі питання

    «Чому для навантажувального тестування не використовують Selenium або Playwright?» Дивляться, чи розумієте ви механізм, а не гасло: інструменти навантаження працюють на протокольному рівні й не запускають браузера, тому один процес тягне тисячі віртуальних користувачів. І одразу друга половина — браузерний рівень усе одно потрібен, бо протокольний не бачить рендерингу й інтерактивності.

    «Що JMeter не вміє, хоча виглядає як браузер?» Перевіряють, чи знаєте ви несуче обмеження: JMeter не виконує JavaScript зі сторінок і не рендерить HTML. Наслідок — послідовність запитів і динамічні значення доводиться відтворювати вручну, звідси кореляція.

    «Чим check відрізняється від threshold Класична пара на плутанину. Чек нічого не валить — він лише веде облік частки невдалих перевірок; поріг це машинний критерій pass/fail, який змінює код виходу прогону.

    «Як запустити навантаження з кількох машин і що там ламається?» Слухають, чи ставите ви спершу питання «а одна машина точно не тягне», і чи знаєте, що інструменти поводяться протилежно: один виконує той самий план на кожному вузлі, інший ділить профіль між екземплярами.

    «За якими критеріями ви обиратимете інструмент?» Питання не про назви — очікують структуру: протоколи й платформи, інтеграція з CI, масштабованість, знання команди, звʼязок моніторингу з транзакціями. Відповідь «візьмемо безкоштовний» без згадки про час і навчання читається як брак досвіду.

    Джерела

    Карта інструментів: три ролі замість трьох продуктів

    Протокольний рівень: чому JMeter — не браузер

    JMeter: групи потоків, семплери й таймери

    k6: сценарій кодом і чотири стадії скрипта

    Перевірки вмісту: без них ви міряєте швидкість помилки

    Пороги: єдиний машинний вердикт прогону

    Розподілена генерація: коли одна машина не тягне

    Критерії вибору: чому «який інструмент кращий» — не питання

    Пояснення

    «Поясни» працює з власним API-ключем Anthropic: запит іде з вашого браузера прямо до Anthropic.

    Свій API-ключ (BYOK)

    Вставте власний ключ Anthropic — пояснення працюватиме на реальній моделі. Ключ зберігається лише у вашому браузері (localStorage), нікуди не надсилається, крім api.anthropic.com, і не логується.