Shift-Left Performance Tests у CI/CD: k6, Gatling, Locust

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

Shift left performance testing: де ламається конвеєр

Навантажувальний тест, запущений за тиждень до релізу, майже завжди показує не те, що потрібно.

Профіль навантаження знято з продакшену місячної давності, кеші холодні, обсяг даних менший за бойовий — деградація продуктивності під піком спливає вже після викатки, коли користувачі йдуть, а не у звіті.

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

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

Окрема проблема — вузьке місце збирання. Повний навантажувальний прогін займає десятки хвилин і тримає чергу релізів, тому його виносять за межі конвеєра.

Навантажувальне тестування в конвеєрі перетворюється на ручну операцію перед великим релізом: регресії накопичуються місяцями, а винним виявляється «повільний стенд».

Shift left performance testing — це перенесення перевірки продуктивності на етап, де ціна виправлення ще низька: короткі сценарії на кожну зміну, розширений профіль на гілку, повний — за розкладом. Нижче розбираємо, як це закривається на практиці.

Що дає раннє навантажувальне тестування

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

Раннє навантажувальне тестування переносить той самий прогін у контур збирання — наприклад, сценарії на k6 — і відповідає на питання «скільки тримає» на етапі, де правка коштує правки, а не переписування.

  • Час зворотного зв’язку. Вердикт за навантажувальним профілем надходить у тому самому прогоні, що й модульні тести: інженер бачить регрес через хвилини після надсилання правки, а не через дні очікування окремого стенда.
  • Частка дефектів продуктивності, знайдених до релізу. Витоки з’єднань, необмежені вибірки, блокування за конкурентного доступу виявляються на тестових даних і йдуть у роботу раніше за промисловий контур. Цілимося в 80% і вище.
  • Стійкість під навантаженням. Піковий профіль — сезонний сплеск, нічне пакетне оброблення, розсилання — проганяється регулярно, тому поведінка на межі відома заздалегідь, а не з’ясовується на інциденті.
  • Вартість простою. Дефект із контуру збирання — це години правки; той самий дефект у промисловому контурі — години недоступності сервісу й розбір інциденту.
  • Регресія за базовими лініями. Час відповіді ключових операцій і частка помилкових відповідей зберігаються поруч із кодом і порівнюються від збирання до збирання: деградація на 10–15% видна як невдала перевірка, а не як скарга користувача.
  • Порогові значення як умова випуску. Сценарій із порогом за часом відповіді та часткою помилок зупиняє збирання — правило одне для всіх, тлумачити нічого.

Режими запуску навантажувальних перевірок: порівняння

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

Чим частіше прогін, тим коротший профіль навантаження й вужчий набір сценаріїв, інакше перевірка перестає встигати за темпом збирань.

Режим Коли доречний Чим обмежений
Короткий профіль на кожен коміт Регресія за гарячими сценаріями: поріг за 95-м перцентилем, частка помилок, пропускна здатність Одиниці хвилин бюджету збирання, малий обсяг даних і віртуальних користувачів; не покаже витоки й деградацію на довгій серії
Прогони за розкладом Тренди та стабільність: серія раз на добу, пошук витоків, порівняння з минулими результатами Зворотний зв’язок надходить через години; результати треба десь зберігати й порівнювати між собою
Передрелізні заміри Ємність перед викаткою: тривалий і ступінчастий профіль, дані, близькі до бойових Дорого за стендом і часом, потрібна ізоляція; не ловить регресію окремого коміту

Режими доповнюють один одного: сценарій переноситься між k6, Gatling і Locust без переписування логіки, відрізняються лише профіль навантаження й правила зупинки збирання.

Провал порогового значення на коміті блокує злиття, нічний прогін заводить задачу на розбір, передрелізний замір зупиняє викатку до з’ясування причин.

Етапи впровадження навантажувальних перевірок у конвеєр

Навантажувальні перевірки в конвеєрі не з’являються одним комітом: спочатку потрібно зрозуміти, що саме і в якому режимі навантажувати.

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

  1. Аудит контуру. Розбираємо, з яких сервісів складається система, які зовнішні залежності беруть участь у запиті й де в конвеєрі точка, куди вбудовується запуск. На виході — карта контуру та список сценаріїв, які має сенс навантажувати.
  2. Зняття базового профілю навантаження. Збираємо статистику реальних звернень: співвідношення читання й запису, пікові вікна, розподіл за ендпоінтами. Без цього профілю результат прогону немає з чим порівняти.
  3. Проєктування схеми перевірок. Фіксуємо, що запускається на кожен коміт, а що — перед викаткою, задаємо бюджет часу й пороги, за якими збирання зупиняється.
  4. Налаштування стенда й сценаріїв. Розгортаємо ізольоване середовище, зіставне з продуктивом, описуємо сценарії на k6, налаштовуємо подавання даних і збирання метрик.
  5. Перевірка на реальному релізі. Проганяємо схему на бойовій зміні, звіряємо прогноз із фактичною поведінкою та калібруємо пороги, щоб перевірки не спрацьовували на природних коливаннях.
  6. Передавання й супровід. Віддаємо конфігурації, панелі метрик, регламент реакції на падіння та порядок оновлення сценаріїв у разі зміни продукту.

Артефакти впровадження: конфігурації, схеми, регламенти

Впровадження навантажувальних перевірок дає ефект, коли результат залишається в репозиторії та базі знань, а не в листуванні й головах.

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

  • Сценарії навантажувальних тестів — версіонуються поруч із кодом сервісу: користувацькі шляхи, підготовка даних, очікувані відповіді. Сценарій прив’язаний до гілки й запускається на зміни в зачеплених модулях, а не «колись перед релізом».
  • Профілі навантаження — ступінчастий розгін, стабільне плато, піковий сплеск; для кожного задано тривалість, інтенсивність і умови дострокової зупинки.
  • Порогові значення у вигляді коду — частка помилок, час відповіді на повільному хвості запитів, пропускна здатність. Збирання падає за формальною ознакою, а не за тлумаченням чергового.
  • Регламент реагування — хто дивиться звіт і в якому вікні, що робить у разі деградації: блокує злиття, відкочує реліз або заводить розбір із долученим профілем.
  • Документація контуру — схема стендів, джерела тестових даних, чим навантажувальне середовище відрізняється від продуктивного і які перевірки на ньому недостовірні.
  • Інструкція із запуску — прогін локально, у конвеєрі та на виділеному стенді: які параметри задати, де дивитися звіт, як повторити проблемний запуск.
  • Базові лінії продуктивності — зафіксовані результати минулих релізів і правило їх оновлення, щоб завжди було з чим вести порівняння.
  • Зберігання звітів і артефактів — строк життя, прив’язка до збирання й коміту.

Далі комплект живе як звичайний код: правки проходять рев’ю, а застарілі сценарії видаляються разом із виведеними з експлуатації шляхами.

Кейс: прибрали деградацію перед піковим релізом

В одному з проєктів — сервіс із плановими піками навантаження — регрес продуктивності регулярно спливав уже після випуску: вузьке місце в зміненому запиті знаходили на проді, коли частина замовлень переставала оформлюватися. Розбір інциденту й ручний відкат з’їдали ніч, а наступна спроба релізу зсувалася на добу.

Що перебудували

Навантажувальний контур перенесли в основне збирання: сценарії на k6 проходять на кожній зміні гілки, а пороги за часом відповіді та часткою помилок зашиті в сам сценарій і призводять до падіння збирання в разі виходу за них.

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

Метрика До Після
Прогін навантажувального контуру раз на добу, вручну на кожній зміні гілки
Дефекти продуктивності, знайдені до релізу близько 30% понад 90%
Вікно відкату в разі провалу релізу години ручної роботи хвилини, перемикання тегу
Тривалість прогону зростала разом із кількістю сценаріїв вкладається в бюджет збирання завдяки паралельним виконавцям

Деградації тепер виявляються на етапі збирання, коли правка коштує хвилини. Вікно відкату стиснулося до перемикання тегу — реліз, що провалився, перестав бути подією з нічною переробкою та перенесенням строків.

Чим shift left відрізняється від передрелізних замірів?

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

Передрелізні заміри стоять на виході: стенд збирається з уже прийнятого коду, повний прогін іде перед випуском.

Із цього випливає, хто першим отримує сигнал про деградацію. У зсунутому вліво конвеєрі це розробник — у тому самому обговоренні зміни, поки він пам’ятає, що і навіщо змінював, і поки розбір коштує однієї правки.

За передрелізних замірів сигнал надходить релізному інженеру або тестувальнику вже за день-два до випуску, і далі починається пошук винуватця по всій накопиченій історії.

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

На передрелізному стенді вибір бідніший — або зсувати дату випуску, або випускати з відомим відхиленням і закривати його в наступному релізі.

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

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

Водночас зсунуті вліво перевірки не замінюють передрелізні. Короткі прогони не покажуть поведінку під тривалим навантаженням, накопичення пам’яті та роботу з реальним профілем даних. Робоча схема — два рівні: швидкий контроль на кожній зміні та повний прогін перед випуском. Нижче розбираємо, як це влаштовано і за якими ознаками вибирати пороги.

Часті технічні сумніви та відповіді

Сумніви на старті зазвичай одні й ті самі: чи не стане контур джерелом хибних падінь збирання, чи вистачить ресурсів стенда, що робити з тестовими даними й чи доведеться ламати те, що вже розгорнуто власними силами.

Зсув навантажувальних перевірок вліво (shift-left) упирається не в інструменти, а саме в ці питання, тому відповідаємо по суті.

Хибні спрацювання не почнуть блокувати збирання?

Пороги ставимо на p95 і p99, а не на середній час відгуку, і вимагаємо повторюваності відхилення у двох прогонах поспіль. Деградація відділяється від разового викиду на рівні даних — збирання падає лише на відтворюваному регресі.

Що робити з нестабільним стендом?

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

Як готуються тестові дані?

Набір версіонуємо разом із профілем навантаження й наповнюємо до прогону, а не в його процесі. Склад і обсяг фіксовані, персональні дані знеособлені — прогони відтворювані й не зачіпають робочі записи.

У нас уже розгорнуто свій контур — усе доведеться міняти?

Ні. Підключаємося до того, що є, — k6, Gatling або Locust, — і добудовуємо те, чого бракує: пороги, звіти, гейт у складальній лінії та зв’язок результату з конкретною зміною в коді.

Що буде після передавання?

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

Обговоримо вашу задачу й повернемося з планом

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

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

Розбираємо надіслане й повертаємося з конкретикою:

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

Опишіть задачу своїми словами — обговоримо її й повернемося з оцінкою контуру, планом впровадження перевірок і строками за кожним етапом.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1393
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1139