Performance-тести в CI/CD
Зміст
Перф-тест поза — це подія: раз на квартал команда виділяє тиждень, знімає числа й пише звіт. продуктивності приїжджає не раз на квартал, а з кожним : додали зайвий запит у циклі, підняли залежність, увімкнули ще один сторонній скрипт. Між подією і мерджем — три місяці, за які причину вже не відновити, бо змін накопичилося двісті.
Звідси й тема глави: як перетворити перф-тестування з події на властивість процесу. Це рівень сеньйора не тому, що тут складна механіка, а тому, що ціна помилки лежить не в тесті, а в довірі: гейт, який моргає червоним без причини, вимикають, — і канон SRE називає цей результат прямо. Далі — що ставити гейтом, на якому рівні запускати і з чим порівнювати. Як улаштований сам пайплайн — стадії, , тригери, артефакти, секрети — розбирає розділ про Git і CI/CD: будова пайплайна і стратегія якості в пайплайні.
Що перф-тест робить у пайплайні — і чого не робить
Канон ISTQB відповідає одним реченням: у безперервній інтеграції головна мета перф-тестів — переконатися, що зміна не погіршила продуктивність. Це інше питання, ніж те, на яке відповідає повноцінний навантажувальний прогін: там ми шукаємо межу системи, тут — різницю між «до» і «після». Звідси й обмеження, з якого починається весь дизайн: через короткий час, доступний у CI, тести в пайплайні можуть бути підмножиною ширших тестів, які в інший час ганяє спеціалізована команда. Ця сама вимога робить перф-роботу ранньою: канон наполягає, щоб аналіз починався рано й повторювався регулярно, а не зводився до одного прогону наприкінці системного тестування.
Друга половина рамки — застереження від протилежної крайності. Дока k6 формулює її без пом'якшень: автоматизація часто означає прогін із pass/fail у CI/CD, однак не всі перф-тести придатні для CI/CD- й не зводяться до статусу «зелено/червоно» та ролі воротаря релізу. Більше того, запуск тестів тільки з CI на зміни коду обмежує цілі перф-тестування. Альтернативи названі поіменно: cron і cron-, ручний запуск як пункт релізного чекліста. Мета всієї конструкції там само сформульована як зміна режиму роботи: продуктивність у багатьох організаціях лишається невідчутною, і на неї реагують, лише коли стається погане, — автоматизація переводить команду з реактивного режиму в проактивний.
Практичний висновок для дизайну: пайплайн не має бути єдиним місцем, звідки стартують перф-тести. У ньому живе швидка підмножина, решта — за розкладом і руками.
Перф-смоук на PR: найдешевший рівень
у перф-контексті — це не «маленький load-тест», а перевірка, що прогін узагалі має сенс. Дока k6 радить починати саме з нього: перед більшими прогонами валідувати, що скрипт працює як очікується і що система нормально почувається під мінімальним навантаженням. Параметри задані там само: низьке навантаження, тривалість у секундах або хвилинах, привід — зміна відповідного системного чи застосункового коду, а перевіряє він функціональну логіку, базові метрики й відхилення.
Зверніть увагу на привід: «зміна відповідного коду» — це буквально опис тригера PR. Тому смоук і є природним мешканцем цього рівня. Він коштує хвилини, вписується в час джоби й ловить найдорожчий клас поломок — зламаний сценарій. Скрипт, який після переїзду збирає 404 замість замовлень, у нічному прогоні виявиться о шостій ранку, коли три години генератора вже витрачено; на PR він виявиться за дві хвилини.
Друга роль смоуку — тримати свіжим (performance baseline), тобто набір метрик для порівняння поточних і раніше досягнутих вимірів. Канон окремо каже, що базовий вимір може бути потрібно спершу створити, використовуючи знеособлені дані з бази, — тобто це підготовлений артефакт, а не зріз проду, і саме тому він відтворюваний. Без нього фактичні результати прогону неможливо оцінити: без набору базових вимірів, що визначають прийнятну й неприйнятну продуктивність, «700 мс» лишається числом без вердикту. Сам вид тесту й склад знімка розбирає глава про види перф-тестів.
Поріг як гейт релізу, а не як вердикт прогону
Поріг (threshold) як критерій pass/fail самого прогону — предмет глави про вимоги до продуктивності. Тут питання інше: чи має цей вердикт когось зупиняти.
Технічно міст між прогоном і пайплайном вузький до непристойності. Якщо всі пороги виконано, інструмент виходить із кодом 0; якщо провалено хоч один — з ненульовим. Це весь інтерфейс: решта — звіти, дашборди, гарні графіки — призначена людям, а не гейту. Звідси перше правило: перф-джоба без порогів гейтом не є ніколи, скільки б артефактів вона не лишала. Те саме стосується чеків: невдалі чеки не переривають тест і не завершують його зі статусом провалу, інструмент лише веде облік їхньої частки, — щоб чек щось блокував, його треба поєднати з порогом. А саме число береться не з інструмента, а з , які канон вимагає прив'язувати до цілей перф-тесту, SLA і базових значень.
Тепер найцікавіше — форма гейта. Найближчий задокументований аналог у нашій індустрії — гейт на коду, і Google називає розвилки поіменно: гейт на все проти гейта лише на новий код; гейт на жорстко задане число проти гейта на дельту від попередньої версії. Друга розвилка для продуктивності і є головною. Абсолютний поріг («p(95) оформлення нижчий за 500 мс») перевіряє вимогу й не залежить від історії, але на слабкому CI-середовищі він або постійно червоний, або настільки послаблений, що не ловить нічого. Дельта від базового виміру («не гірше ніж на 10% проти попереднього релізу») ловить саме регресію, але мовчить, коли система повільна вже давно. Робочий гейт зазвичай тримає обидва критерії. названий у тому самому джерелі: гейт може вистрілити у зворотний бік, якщо перетвориться на чекбокс, бо «тиск влучити в метрику майже ніколи не дає бажаного результату» — а найпростіший спосіб «влучити» у перф-метрику — послабити поріг, і зроблено це буде о другій ночі перед релізом.
І дві механічні пастки, через які фраза «у нас усе під гейтом» частіше за все неправдива. Обов'язкова перевірка вважається пройденою, якщо вона в стані successful, skipped або neutral, — тобто перф-джоба, яку пропустила умова if у самій джобі, лишає гейт зеленим і нікого не турбує. А зелений CI взагалі не є апрувом: у формулюванні доки зміни лише «готові до рецензії або злиття». Локальна перевірка гейтом не є за побудовою: pre-commit обходиться опцією --no-verify, тож хук дає швидкий фідбек, а не блокує. Сам напрямок руху перевірок канон CTFL називає прямо: CI просуває shift-left, підштовхуючи віддавати код разом із компонентними тестами й , — перф-смоук у цю логіку вкладається природно. Механіку захищених гілок розбирає стратегія якості в пайплайні.
Порівняння з базовим виміром: що з чим і за якою метрикою
Найважливіше твердження глави канон SRE формулює в темі , і воно переноситься на перф-гейт один в один: оскільки час є одним із найбільших джерел зміни спостережуваних метрик, оцінити деградацію продуктивності порівнянням «до й після» важко. Механізм простий: деградацію міг спричинити , а могла вона статися й у контрольній системі теж. Канонічний приклад — реліз у понеділок означає порівняння поведінки в робочий день із поведінкою у вихідні, «вносячи великий обсяг шуму».
Наслідок для CI прямий: «прогін сьогодні проти прогону тижневої давнини» — слабкий доказ регресії. Сильніші дві конструкції. Перша — серія прогонів на одному : вона показує власну дисперсію вимірів, тобто ту саму різницю, яку ви інакше приписали б зміні. Друга — паралельний контрольний прогін: обидві версії міряються в тому самому часі й у тих самих умовах. Канон і тут застерігає: контроль та кандидат часто ділять бекенди, мережу й сховище, а спільний домен псує обидві сторони порівняння.
Розкид при цьому лікують повтореннями, а не ширшим порогом. Lighthouse CI прямо тримає в переліку своїх можливостей ганяти аудит багато разів, щоб зменшити дисперсію, — це канонічне визнання того, що одиничний перф-вимір шумний, і механічна відповідь на шум — повторення, а не послаблення критерію.
Друге питання — за якою метрикою порівнювати. Канон відповідає й на нього: найкращі метрики — коди відповіді HTTP і відповіді, бо їх деградація найточніше відповідає реальній проблемі, що впливає на користувачів; натомість метрики використання процесора не такі корисні — зростання витрат ресурсу не обов'язково впливає на сервіс і може дати нестабільний, шумний процес. Далі йде наслідок, який пояснює смерть половини перф-гейтів: шумний процес оператори можуть вимкнути або почати ігнорувати, а це знецінює саму ідею. Число теж назване: беріть кілька найкращих метрик, можливо, не більш ніж дюжину, бо забагато метрик дають спадну віддачу, а з певного моменту вигоду перекриває вартість підтримки або втрата довіри до релізного процесу. Коди 4xx при цьому з оцінки виключають, додавши перевірку наявності конкретного URL: 404 може означати і зламаний сервер, і просто те, що користувачі йдуть за неправильним посиланням. Над усім цим стоїть одна вимога — джерело змін у спостережуваних метриках має бути чітко віднесене до зміни, яку ми перевіряємо, і не мусить залежати від зовнішніх чинників; саме тому гейт ставлять не на «процесор системи», а на час процесора, витрачений на обслуговування запиту.
Оцінювати сам гейт зручно словником, який канон дає в темі сповіщень: точність (частка спрацювань, які були значущими), повнота (частка значущих подій, які виявлено), час виявлення і час скидання — причому довгий час скидання призводить до плутанини або до ігнорування проблем. Там же названа й межа однопорогового правила, і названа числом: швидкість витрачання 35 не спрацьовує ніколи, хоча з'їдає весь місячний за 20,5 години. Мораль для CI: один поріг завжди має сліпу зону, і саме тому рівнів запуску більше ніж один.
Рівні запуску: PR-смоук, нічний load, релізний повний
Канон дає готову модель рівнів — знову ж таки в темі канарки: замість оцінювати один етап, використовують кілька, що відображають нашу здатність міркувати про метрики. На малому етапі перевагу надають метрикам, які найясніше вказують на проблему, — падінням застосунку, відмовам запитів, — а тонші метрики стають придатними лише на більшій вибірці. Перекладіть це на пайплайн — і рівні запуску вибудовуються самі.
Механіка розділення на диво проста: шлях до скриптів у дії запуску задається шаблоном, тобто різні шаблони дають різні набори тестів із того самого репозиторію. Ще одна деталь того самого джерела варта уваги — підготовка середовища й власне прогін рознесені на дві різні дії, тож у джобі видно, що саме впало: не встановився інструмент чи не пройшов тест. Це рівно та різниця, яку «зелено/червоно» приховує.
Розкладка по рівнях у типовому проєкті виглядає так:
type PerfLevel = {
trigger: 'pull_request' | 'schedule' | 'release';
scriptGlob: string; // './tests/smoke*.ts' | './tests/load*.ts'
duration: string; // 'хвилини' | 'десятки хвилин' | 'години'
gate: 'blocking' | 'report-only';
compareWith: 'none' | 'baseline' | 'previous-release';
};
Ключове поле тут gate — і саме його значення канон не приписує. Він дає модель етапів: кілька замість одного, на малому етапі перевагу мають найгрубіші метрики, тонші стають придатними лише на більшій вибірці. Який з етапів блокує мердж, який лише звітує, а який має право зупинити реліз — рішення проєкту, а не вимога стандарту, і залежить воно від апетиту команди до ризику. Те, що частина перф-тестів у CI не поміщається взагалі, дока k6 каже прямо, називаючи cron і ручний запуск як штатні альтернативи.
Шум спільного ранера
Почнемо з того, що документоване. Специфікації hosted-ранерів GitHub залежать від видимості репозиторію: станом на 2026-08-01 та сама мітка ubuntu-latest дає 4 процесори й 16 ГБ у публічному репозиторії й 2 процесори та 8 ГБ у приватному. з суфіксом -latest — це останні стабільні образи, які можуть не бути найсвіжішою версією ОС від постачальника, тобто мітка версію не закріплює. Що саме виконувало джобу, видно в логах прогону — і це єдине надійне джерело відповіді на питання «чому вчора було швидше». Так само не закріплена й версія самого інструмента: дія встановлення k6 бере останню версію, якщо версію не задано явно, тож стрибок цифр може бути наслідком оновлення, а не змін у системі.
Тепер про сусідів. Канон SRE описує цей клас точно, хоч і не про CI: у великій популяції машин ймовірні викиди — перевантажені (oversubscribed) машини, машини з іншими ядрами й іншими характеристиками продуктивності або машини в перевантаженому сегменті мережі. І дає вердикт, який прямо переноситься на спільний ранер: сильно поруч із нашим процесом — очевидна проблема, але вона не спричинена зміною, яку ми перевіряємо, тож не має позначатися як провал. Рецепт той самий, що вище: обирати метрику, віднесену до самої роботи, — не загальне використання процесора системою, а час процесора, витрачений на обслуговування запиту.
Наша практика (не канон). Далі — те, як це роблять команди, з якими ми працювали; окремого стандарту чи специфікації під це немає. Абсолютні числа зі спільного ранера між прогонами не порівнюють: ранер тримають пусковим механізмом, а не вимірювальним приладом. Навантаження генерують у виділене середовище, а гейт на PR лишають грубим — відмови запитів, явно зламаний сценарій, кратне погіршення, — тоді як тонке порівняння з базовим виміром роблять на виділеному залізі й на нічному рівні. У звіт джоби корисно класти рядок про те, який ранер виконував прогін: без нього розслідування «чому в четвер було вдвічі повільніше» починається з нуля. І чесна межа: скільки саме повторів достатньо і який розкид вважати «однаковими прогонами» — числа не дає жодне джерело, яке ми перевіряли. Канон каже лише «повторюйте, щоб зменшити дисперсію»; конкретний команда встановлює сама, за власними вимірами, і фіксує його як домовленість, а не як факт.
Lighthouse CI і бюджети продуктивності
у CI має власний артефакт — (performance budget): набір обмежень, накладених на метрики, що впливають на продуктивність сайту. Це може бути загальний розмір сторінки, час її завантаження в мобільній мережі або навіть кількість надісланих HTTP-запитів. Роль бюджету канон формулює як точку відліку для рішень щодо дизайну, технологій і додавання функцій, і підпирає мотивом, який варто цитувати дослівно: хороша продуктивність рідко буває побічним ефектом.
Складається бюджет із трьох класів метрик: кількісних (максимальний розмір зображень, кількість вебшрифтів, розмір скриптів разом із фреймворками, загальна кількість зовнішніх ресурсів), часових віх (події при завантаженні сторінки, і найкорисніші тут — користувацькі метрики, доступні через API браузера й у звітах Lighthouse) і правил-балів (Lighthouse і WebPageTest рахують бали за загальними правилами кращих практик). Канон радить комбінацію, а не один клас, і застерігає: кількісні межі мало кажуть про досвід, бо дві сторінки з однаковою кількістю запитів або однаковою вагою можуть рендеритися по-різному залежно від порядку, у якому запитуються ресурси.
Формулюють бюджет разом із контекстом виміру — сторінкою, пристроєм і мережею: «сторінка товару має віддавати менше ніж 170 КБ JavaScript на мобільному», «блог має мати бал понад 80 в аудиті продуктивності Lighthouse». Числа тут не абсолютні: джерело прямо каже, що вони пораховані на основі реальних базових пристроїв і швидкості мережі 3G, а сама сторінка датована 2018 роком — тож цитувати їх можна лише разом із датою й умовами. Чинний набір клієнтських метрик розбирає глава про фронтенд-продуктивність і Core Web Vitals.
Гейтом бюджет робить перелік із трьох дій при перевищенні: оптимізувати наявну функцію чи ресурс, прибрати наявну функцію чи ресурс або не додавати нову. Третя дія і є суттю: бюджет змушує вибирати, а не просто повідомляє. Технічно він живе у збірці — канон називає можливості продуктивності Webpack, bundlesize і Lighthouse CI, — а сам Lighthouse CI описує свою роль сумісно: задавати й тримати бюджети продуктивності на скрипти й зображення. На боці навантажувального тесту ту саму роль виконують пороги; різниця лише в предметі виміру.
Одне застереження, без якого бал Lighthouse у гейті приносить більше шкоди, ніж користі. Підсумковий бал — це позиція відносно решти вебу: сире значення метрики перетворюється на бал за положенням у логнормальному розподілі, побудованому на реальних даних HTTP Archive. Ваги метрик змінюються між версіями інструмента, тож бали, зняті різними версіями, незіставні — версію в CI закріплюють так само, як версію . І головне: сам інструмент радить думати про продуктивність як про розподіл балів, а не про одне число, — тобто один прогін Lighthouse гейтом не є. Плюс межа лабораторного виміру: це один пристрій, одна мережа, одне географічне розташування, і реального розкиду він навмисно не відтворює. Цінність лабораторії при цьому в іншому — вона дає перевірку фічі до релізу й ловить регресію заздалегідь, там, де ще сліпі. А от гонитву за ідеальним балом суто заради SEO Google Search називає, найімовірніше, не найкращим витрачанням часу.
Тренд і зберігання історії результатів
Тренд не існує сам собою — він існує рівно настільки, наскільки збережені результати. Тут корисно розрізняти дві форми виводу, які дає інструмент навантаження: агрегована статистика прогону або окремі точки з мітками часу. Перша відповідає на питання «пройшли чи ні», друга — на питання «коли саме почалася деградація», і саме вона годиться для порівняння прогонів між собою: агрегати різних прогонів не складаються. Потік точок пишуть у файл або стрімлять у сервіс.
На фронтенді ту саму задачу закриває Lighthouse CI, і його самоозначення варто прочитати як перелік обов'язків: безперервно ганяти, зберігати, діставати й перевіряти результати Lighthouse. У переліку можливостей це розкладено детальніше — відстеження метрик і балів у часі та порівняння двох версій сайту, щоб знайти покращення й регресії окремих ресурсів. Останнє й відрізняє тренд від дашборда: питання не «бал упав», а «що саме потовстішало». Під зберігання історії в проєкті передбачено окремий сервер — тобто сховище є частиною конструкції, а не бонусом.
Дві дрібниці, які роблять історію придатною до вжитку. По-перше, закріплена версія інструмента — і генератора навантаження, і CLI Lighthouse (у канонічному прикладі це @0.15.x): без цього ряд точок змішує зміни системи зі змінами вимірювача. По-друге, вимір не закінчується релізом: канон бюджету прямо каже, що переконатися, що сайт достатньо швидкий, означає продовжувати міряти після початкового запуску, а моніторинг метрик у часі й дані від реальних користувачів показують, як зміни в продуктивності впливають на бізнес-метрики. Другу половину цієї пари — збір із проду — розбирає глава про моніторинг, APM і спостережуваність.
Типові помилки
- «Той самий коміт дав інші числа — тест флакітний» → виглядає як дефект тесту, а насправді одиничний перф-вимір шумний за побудовою, і задокументована відповідь на це — прогнати аудит багато разів, щоб зменшити дисперсію, а не послабити критерій.
- «Порівняли з прогоном тижневої давнини — просіли на 15%» → виглядає як регресія, а насправді час є одним із найбільших джерел зміни спостережуваних метрик: реліз у понеділок порівнює робочий день із вихідними й вносить великий обсяг шуму.
- «Поставили гейт на утилізацію процесора — це найчутливіша метрика» → виглядає як рання діагностика, а насправді зростання витрат ресурсу не обов'язково впливає на сервіс і може дати шумний, нестабільний процес; шумний процес оператори можуть вимкнути або почати ігнорувати, і сама ідея гейта знецінюється.
- «Гейт червоний — винен наш реліз» → виглядає як спрацювання за призначенням, а насправді сильно перевантажена сусідня машина є проблемою, але не спричинена зміною, яку ми перевіряємо, тож провалом позначатися не має.
- «Порівнюємо сорок метрик, щоб нічого не проґавити» → виглядає як ретельність, а насправді забагато метрик дають спадну віддачу, і з певного моменту вигоду перекриває вартість підтримки або втрата довіри до релізного процесу; канон радить не більш ніж дюжину.
- «Гейт не спрацював жодного разу за квартал — отже, все добре» → виглядає як доказ стабільності, а насправді одне порогове правило має сліпу зону: швидкість витрачання 35 не спрацьовує ніколи, хоча з'їдає весь місячний бюджет помилок за 20,5 години.
- «Ганяємо на
ubuntu-latest, залізо однакове» → виглядає як контрольована умова, а насправді та сама мітка дає 4 процесори в публічному репозиторії й 2 у приватному (станом на 2026-08-01), а образи-latestє лише останніми стабільними й можуть не бути найсвіжішою версією ОС; що виконувало джобу, видно тільки в логах прогону. - «Сторінка важить стільки ж, отже швидкість та сама» → виглядає як арифметика, а насправді дві сторінки з однаковою вагою або однаковою кількістю запитів рендеряться по-різному залежно від порядку, у якому запитуються ресурси.
Підсумок
- У пайплайні перф-тест відповідає на питання «чи погіршила це зміна», а не «скільки система тримає». Через короткий доступний час у CI живе підмножина тестів; повний профіль ганяється за розкладом або руками, і канон це прямо передбачає.
- Гейтом прогін робить поріг, а не звіт. Єдиний інтерфейс до пайплайна — код виходу; джоба без порогів не блокує нічого, а джоба, пропущена умовою, лишає гейт зеленим.
- Порівняння «до й після» ненадійне за побудовою, бо час — одне з найбільших джерел зміни метрик. Сильніші конструкції — серія прогонів на одному коміті й паралельний контроль; розкид лікують повтореннями, а не ширшим порогом.
- Метрика гейта мусить бути віднесеною до зміни. Коди відповіді й затримка — так, утилізація процесора — ні: шумний критерій вимикають, і разом із ним помирає вся ідея.
- Тренд існує рівно настільки, наскільки збережені результати. Потрібні окремі точки з мітками часу, сховище історії й закріплені версії інструментів — інакше ряд змішує зміни системи зі змінами вимірювача.
Можливі питання
- «Який перф-тест ви поставите на кожен PR?» — перевіряють відчуття вартості: очікують смоук на хвилини з грубими критеріями, а не «маленький load». Сильна відповідь одразу називає, що саме він ловить — зламаний сценарій і явні відмови — і що тонкі метрики на цьому рівні не читають.
- «Ви порівнюєте прогін на PR із прогоном минулого тижня. Що з цим не так?» — питання про час як змінну. Дивляться, чи назве кандидат шум, який вносить сама відстань у часі, і чи запропонує повтори на одному коміті або паралельний контроль.
- «На що ви поставите поріг у CI — на абсолютне число чи на дельту від базового виміру?» — очікують не вибір, а розбір: абсолютний поріг перевіряє вимогу й мовчить про повільну систему, дельта ловить регресію й мовчить про давню повільність. Згадка про гейт «лише на новий код» додає ваги.
- «Ваш перф-гейт тиждень блимає червоним. Що робите?» — перевіряють, чи розуміє кандидат, що шумний гейт помирає: його вимикають або ігнорують. Сильна відповідь іде до причини — метрика не віднесена до зміни, замало повторів, спільний ранер — а не до послаблення порогу.
- «Скільки метрик ви візьмете в критерій?» — дивляться на знання про спадну віддачу й вартість підтримки; канонічний орієнтир — не більш ніж дюжина, з кодами відповіді й затримкою на першому місці.
- «Чим бюджет продуктивності відрізняється від порога?» — предметом виміру: бюджет обмежує вагу й час завантаження сторінки, поріг — метрики прогону під навантаженням. Плюс три дії при перевищенні, третя з яких — не додавати нову функцію.
- «Чому не можна просто поставити гейт на бал Lighthouse?» — питання рівня сеньйора: бал є позицією відносно розподілу реальних даних, ваги метрик змінюються між версіями інструмента, а сам інструмент радить думати про розподіл балів, а не про одне число.
- «Де ви зберігаєте результати перф-прогонів і навіщо?» — очікують розрізнення агрегованого підсумку й окремих точок із мітками часу, згадку про сховище історії й закріплені версії інструментів.
Джерела
Що перф-тест робить у пайплайні — і чого не робить
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — головна мета перф-тестів у CI, тести в пайплайні як підмножина ширших через короткий доступний час, вимога починати аналіз ризиків рано й повторювати регулярно.
- Grafana k6 — Automated performance testing — не всі перф-тести придатні для CI/CD, запуск тільки з CI обмежує цілі, cron і ручний запуск як названі альтернативи, перехід із реактивного режиму в проактивний.
Перф-смоук на PR: найдешевший рівень
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — базовий вимір як набір метрик для порівняння, створення базового виміру на знеособлених даних, неможливість оцінити результати прогону без базових вимірів.
- Grafana k6 — Load test types — порада починати зі смоуку й перевіряти працездатність скриптів; параметри смоуку: низьке навантаження, секунди-хвилини, привід — зміна коду, перевірка логіки, базових метрик і відхилень.
- Grafana k6 — Automated performance testing — порівняння з наявним базовим виміром як перша ціль регулярних прогонів.
Поріг як гейт релізу, а не як вердикт прогону
- Grafana k6 — Thresholds — код виходу 0 при виконаних порогах і ненульовий при провалі як єдиний інтерфейс прогону до CI; поріг як кодифікація SLO.
- Grafana k6 — Checks — невдалі чеки не валять прогін, ведеться лише облік їхньої частки, і чек блокує щось лише в парі з порогом.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — критерії приймання для всіх релевантних вимірів і їх прив'язка до цілей тесту, SLA та базових значень.
- Google Testing Blog — Code Coverage Best Practices — розвилки форми гейта: усе проти лише нового коду, жорстко задане число проти дельти від попередньої версії; ризик перетворення гейта на чекбокс і теза про тиск «влучити в метрику».
- GitHub Docs — About protected branches — обов'язкова перевірка проходить у станах successful, skipped або neutral, тож пропущена джоба лишає гейт зеленим.
- GitHub Docs — Continuous integration (GitHub Actions) — зелений прогін означає лише готовність до рецензії або злиття, а не апрув.
- Git Reference — githooks —
pre-commitобходиться опцією--no-verify, тож хук лишається швидким фідбеком, а не блокуванням. - ISTQB Certified Tester Foundation Level Syllabus v4.0 — §2.1.4: CI просуває shift-left, підштовхуючи віддавати код разом із компонентними тестами й статичним аналізом.
Порівняння з базовим виміром: що з чим і за якою метрикою
- Google SRE Workbook — Chapter 16: Canarying Releases — час як найбільше джерело зміни метрик і ненадійність порівняння «до й після», приклад понеділка проти вихідних, спільні домени відмови, вибір метрик (коди й затримка проти утилізації процесора), шумний процес вимикають, ліміт у дюжину метрик, виключення
4xx, віднесеність метрики до зміни. - Google SRE Workbook — Chapter 5: Alerting on SLOs — чотири властивості критерію (точність, повнота, час виявлення, час скидання) і сліпа зона однопорогового правила зі швидкістю витрачання 35.
- GoogleChrome/lighthouse-ci — README — прогін багато разів заради зменшення дисперсії.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — базовий вимір як набір метрик для порівняння поточних і раніше досягнутих вимірів.
- Grafana k6 — Automated performance testing — базовий вимір, тренд і виявлення регресій релізів як три окремі цілі регулярних прогонів.
- Grafana k6 — Results output — для порівняння прогонів придатні окремі точки з мітками часу; розбір форм — у підрозділі про історію результатів.
- grafana/setup-k6-action — README — закріплення версії інструмента, без якого зміна цифр може бути наслідком оновлення.
- GitHub Docs — GitHub-hosted runners reference — машина, на якій виконується порівняння; наслідки спільного заліза — в окремому підрозділі нижче.
Рівні запуску: PR-смоук, нічний load, релізний повний
- Google SRE Workbook — Chapter 16: Canarying Releases — кілька етапів замість одного, найгрубіші метрики на малому етапі й тонші на більшій вибірці.
- grafana/setup-k6-action — README — шаблон шляху до скриптів як механізм розділення наборів; підготовка й запуск як дві різні дії.
- ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — тести в пайплайні як підмножина ширших тестів через короткий доступний час.
- Grafana k6 — Automated performance testing — не всі перф-тести придатні для CI/CD; cron-ранери й ручний запуск як альтернативи.
- GoogleChrome/lighthouse-ci — README — звіт поруч із кожним PR як окремий рівень зворотного зв'язку.
- Grafana k6 — Results output — форма результату, у якій нічний прогін живить тренд, а не вердикт.
- Google SRE Workbook — Chapter 5: Alerting on SLOs — чому одного порогу замало й звідки береться потреба в кількох рівнях.
- GitHub Docs — GitHub-hosted runners reference — ліміти й залізо, у які впирається вибір рівня; наслідки — в наступному підрозділі.
- GitHub Docs — GitHub-hosted runners reference — специфікації Linux-ранера для публічного й приватного репозиторію станом на 2026-08-01, незакріпленість образів
-latestі рядок про ранер у логах прогону. - grafana/setup-k6-action — README — усталене встановлення останньої версії інструмента, якщо версію не задано явно.
- Google SRE Workbook — Chapter 16: Canarying Releases — викиди у великій популяції машин, перевантажений сусід як проблема, що не є провалом перевірюваної зміни, і вибір метрики, віднесеної до самої роботи.
- Google SRE Workbook — Chapter 5: Alerting on SLOs — властивості критерію, за якими оцінюють, чи гейт узагалі придатний до вжитку.
- GoogleChrome/lighthouse-ci — README — повторення прогонів як задокументована відповідь на дисперсію виміру.
- Grafana k6 — Results output — форма результату, у якій зберігається мітка часу кожної точки, потрібна для розбору розкиду.
- Grafana k6 — Automated performance testing — регулярність прогонів як спосіб побачити варіацію, а не одиничне число.
Lighthouse CI і бюджети продуктивності
- web.dev — Performance budgets 101 — означення бюджету продуктивності й трьох класів метрик, вимога комбінувати класи, застереження про порядок завантаження ресурсів, приклади формулювань зі сторінкою, пристроєм і мережею, умовність чисел (базові пристрої й 3G), три дії при перевищенні та інструменти вбудовування бюджету в збірку.
- GoogleChrome/lighthouse-ci — README — роль інструмента: задавати й тримати бюджети продуктивності на скрипти й зображення, звіт поруч із кожним PR, багаторазовий прогін заради зменшення дисперсії.
- Grafana k6 — Thresholds — пороги як відповідник бюджету на боці навантажувального прогону: кодифікація SLO й провал тесту при невиконанні.
- Chrome for Developers — Lighthouse Performance scoring — бал як положення в логнормальному розподілі даних HTTP Archive, зміна ваг між версіями інструмента й порада думати про розподіл балів, а не про одне число.
- web.dev — Why lab and field data can be different (and what to do about it) — лабораторний вимір як один пристрій, одна мережа й одне розташування, що навмисно не відтворює реальний розкид.
- web.dev — Web Vitals — місце лабораторного інструмента в процесі: перевірка до релізу й раннє виявлення регресії.
- Google Search Central — Understanding page experience in Google Search results — застереження проти гонитви за ідеальним балом як самоціллю.
Тренд і зберігання історії результатів
- Grafana k6 — Results output — дві форми результату: агрегована статистика проти окремих точок із мітками часу, і запис потоку у файл або стрімінг у сервіс.
- GoogleChrome/lighthouse-ci — README — безперервний прогін, збереження, отримання й перевірка результатів, відстеження метрик і балів у часі, порівняння двох версій до окремого ресурсу, окремий сервер під історію, закріплена версія CLI у прикладі.
- grafana/setup-k6-action — README — усталене встановлення останньої версії, через яке версію інструмента доводиться закріплювати явно.
- Google SRE Workbook — Chapter 16: Canarying Releases — час як джерело зміни метрик, через яке ряд точок цінніший за пару «до й після».
- Google SRE Workbook — Chapter 5: Alerting on SLOs — й час скидання як властивості, що визначають придатність критерію поверх ряду.
- GitHub Docs — GitHub-hosted runners reference — рядок про ранер у логах прогону як частина метаданих, без якої точка ряду не інтерпретується.
- Grafana k6 — Automated performance testing — спостереження за пласким або змінним трендом як окрема ціль регулярних прогонів.
- web.dev — Performance budgets 101 — вимір не закінчується релізом: продовжувати міряти після початкового запуску, моніторинг метрик у часі й дані реальних користувачів як показник впливу на бізнес-метрики.
Навіщо ганяти перф-тести в пайплайні, якщо повний навантажувальний прогін усе одно роблять окремо?
Бо це два різні питання. Великий прогін шукає межу: скільки система витримає, де вона зламається, як поводиться під тиском. Прогін у CI цікавить лише одне — чи зробила конкретна зміна гірше; саме так ISTQB описує головну мету перф-тестування в безперервній інтеграції. Різниця цілком практична: продуктивність псується поступово й буденно — зайвий запит усередині циклу, оновлена бібліотека, ще один сторонній скрипт, — і між двома квартальними замірами таких дрібниць накопичуються сотні, серед яких винну вже не вибереш. дає те, чого не дасть жоден захід «раз на квартал»: він прив'язує погіршення до конкретного , поки автор ще пам'ятає, що робив. Дока k6 описує ту саму вигоду ширше — продуктивність у багатьох організаціях лишається невідчутною, і реагують на неї, лише коли стається погане, а автоматизація витягує роботу з реактивного режиму в проактивний.
Чому в CI не можна тримати весь перф-набір?
Усе впирається в час, який має право зайняти. Через це ISTQB і називає перф-тести пайплайна лише частиною набору, решту якого спеціалізована команда ганяє поза CI. Дока k6 додає другу половину рамки: далеко не кожен перф-тест узагалі лягає у формат «зелено/червоно» й роль воротаря релізу, а якщо запускати їх виключно на зміни коду з пайплайна, цілі перф-тестування звужуються. Штатні альтернативи там названі поіменно — розклад на cron- й ручний старт як пункт релізного чекліста. Тому робочий дизайн має кілька точок входу, і питання «що з цього блокує мердж» вирішується для кожної окремо; відповідь «усе» тут неправильна.
Що саме ви ганятимете на кожному PR?
— причому не «зменшений load-тест», а перевірку того, що прогін узагалі має сенс. У k6 його параметри описані так: навантаження низьке, тривалість — секунди чи хвилини, привід для запуску — зміна відповідного коду, а дивиться він на функціональну логіку, базові метрики й відхилення. Формулювання приводу буквально збігається з тим, що робить тригер PR, тому смоук тут і оселяється. За кілька хвилин роботи ви отримуєте найдорожчу знахідку — сценарій, який більше не працює. Уявіть скрипт, який після переїзду замість замовлень набирає 404: у нічному прогоні це спливе аж під ранок, коли години генератора вже спалено, а на PR те саме видно одразу. Друга роль смоуку — не давати протухнути. Читати тут тонкі метрики немає сенсу: вибірка замала, щоб їм вірити.
Що таке базовий вимір (performance baseline) і чому без нього поріг безглуздий?
Це збережений набір метрик, що править за точку відліку для нових вимірів. ISTQB окремо зауважує, що такий еталон може бути потрібно спершу створити — зокрема на знеособлених даних із бази, — тобто це рукотворний артефакт із відомим станом даних, а не випадковий зріз проду, і саме тому його можна відтворити. Далі йде наслідок: поки немає набору базових значень, які розмежовують прийнятну й неприйнятну продуктивність, оцінити результат прогону нічим. «700 мс» без еталона — просто число: невідомо, це нормальний робочий стан чи вдвічі гірше за вчорашній. Практично це означає, що базовий вимір версіонують і супроводжують нарівні зі скриптами: оновлюють після свідомих архітектурних змін і перезнімають, коли переїхало середовище. Команда, яка має пороги, але не пояснює чисел у них, насправді має випадкові константи.
Як прогін перф-тесту технічно перетворюється на гейт?
Через код виходу — іншого каналу немає. Виконано всі пороги — процес завершується нулем і джоба зелена; провалено хоча б один — код ненульовий і джоба червона. Усе решта (HTML-звіти, дашборди, красиві графіки) адресоване людям, а пайплайн їх не читає взагалі. Звідси залізне правило: джоба, у якій порогів немає, не блокує нічого — навіть якщо складає у сховище гори артефактів. І дзеркальне до нього: щоб гейт щось означав, число в порозі має походити з , привʼязаних до цілей тесту, SLA й базових значень, а не з того, що показав перший вдалий прогін.
У скрипті є чеки на статус відповіді. Цього достатньо, щоб прогін падав?
Ні, і це класична пастка. Провалений чек у k6 тест не перериває й проваленим його не робить — інструмент просто веде статистику успішних та невдалих чеків. Тобто сценарій, у якому половина запитів отримала 500, спокійно завершиться нулем, якщо на цю частку ніхто не поставив критерій. Щоб із чека вийшло блокування, поверх нього ставлять поріг на відповідну метрику — умовно «невдалих чеків не більш ніж один відсоток». Практичний наслідок для рев'ю чужого перф-скрипта: дивитися треба не на список чеків, а на наявність порогів, бо саме вони відрізняють гейт від звіту.
Поріг у CI: жорстке число чи відсоток від еталона?
Тут не вибирають одне, тут розбирають компроміс. Найближчий задокументований аналог — гейт на коду, де Google перелічує ті самі розвилки: фіксоване число проти дельти щодо попередньої версії й окремо — увесь код проти лише нового. Абсолютний критерій («p(95) оформлення замовлення тримається під 500 мс») спирається на саму вимогу й історії не потребує; біда в тому, що на кволому CI-залізі він або світиться червоним щодня, або опущений так низько, що не помічає нічого. Відносний критерій («не гірше за попередній реліз більш ніж на десять відсотків») ловить власне , зате нічого не скаже про систему, яка повільна вже рік і лишається такою. Робочий гейт зазвичай тримає обидва, а сильна відповідь на співбесіді додає третій вимір — рахувати лише те, що прийшло в цьому PR, а не весь спадок.
Чим ризикований сам факт наявності гейта?
Тим, що з нього легко виходить чекбокс — і тоді гейт стріляє у зворотний бік. Google формулює це на прикладі покриття: тиск заради влучання в метрику рідко дає той результат, якого від нього чекали. Для продуктивності найдешевший спосіб «влучити» очевидний — підняти планку, і робиться це не на спокійному рефакторингу, а вночі перед релізом, коли всі втомлені й випуск треба випхати. Друга форма тієї самої хвороби — критерій, який червоніє без причини: шумний гейт або вимикають, або привчаються прокручувати, і разом із довірою зникає сенс усієї конструкції. Тому дизайн гейта — це не тільки «яке число поставити», а й «чи зможу я захистити це число перед розробником увечері в п'ятницю».
У нас усі перф-перевірки обов'язкові. Чому гейт усе одно може виявитися фікцією?
Бо статус «обов'язкова перевірка пройдена» покриває три стани, а не один: successful, skipped і neutral. Отже, перф-джоба, яку відрізала власна умова if, лишає дозволеним, і формально при цьому «все під гейтом». Друга дірка: зелений пайплайн апрувом не є — GitHub описує цей статус лише як готовність зміни до рецензії чи злиття. Третя: локальний хук блокуванням не є за побудовою, бо pre-commit знімається прапорцем --no-verify і дає швидкий фідбек, а не заборону. Перевіряється все це одним експериментом: свідомо зламати перф-скрипт у draft-PR і подивитися, чи справді мердж закритий. Команди, які цього ніколи не робили, зазвичай дізнаються про свій пайплайн багато нового.
Свіжий прогін проти прогону тижневої давнини показав просідання на 15%. Що з цим не так?
Те, що сама дистанція в часі є однією з найпотужніших причин, чому метрики змінюються, — і через це звичайне зіставлення двох точок «до» і «після» доказом не працює. Просідання міг дати ваш , а могло воно однаково статися й у незміненій системі: інше навантаження, інші дані, інша поведінка сусідів. Канонічна ілюстрація SRE — понеділковий реліз, який фактично зіставляє будній день із вихідними й вкидає в порівняння величезний шум. Тобто тиждень між вимірами — не нейтральна умова, а окрема змінна, якою ви не керуєте. Сильна відповідь на це питання не зупиняється на «можливо, шум», а одразу пропонує конструкцію, де часу менше: повторні заміри того самого коміту або контроль, що йде паралельно.
Які конструкції порівняння сильніші за «сьогодні проти минулого тижня»?
Дві. Перша — прогнати той самий коміт кілька разів поспіль: так видно власний розкид виміру, тобто рівно ту різницю, яку інакше повісили б на зміну коду; поки цей розкид невідомий, будь-яка дельта не має інтерпретації. Друга — контрольний прогін, що йде одночасно з кандидатським: обидві версії міряються в одну мить і в однакових умовах, тож час випадає з рівняння. У другої конструкції є своя вада, і канон про неї попереджає: кандидат і контроль зазвичай стоять на спільній інфраструктурі — ті самі бекенди, та сама мережа, те саме сховище, — тож збій у спільному шарі просідає обидві половини порівняння відразу, і різниця зникає саме тоді, коли вона справжня. Практично це означає, що дешевих варіантів тут немає: перший коштує часу ранера, другий — окремого середовища й дисципліни щодо спільних залежностей.
Розкид результатів великий. Чи не простіше розширити поріг?
Простіше, але це лікування симптому: ширша планка не робить вимір точнішим, вона лише перестає помічати проблеми. Задокументована реакція на дисперсію інша — міряти повторно: Lighthouse CI тримає багаторазовий аудит у переліку своїх можливостей саме заради зменшення розкиду. Це офіційне визнання того, що поодинокий замір продуктивності шумить за природою, а не через кривий тест. Тому в діагностиці «той самий коміт дав інші числа» першим кроком іде серія повторів, другим — питання, чи взагалі метрика описує ту роботу, яку ми міряємо, і лише третім — розмова про саму планку. Чесна межа: скільки повторів вистачає й котрий розкид ще означає «однакові умови», жодне канонічне джерело числом не задає — цей команда виводить із власних вимірів і фіксує як домовленість, а не як факт.
На яку метрику ставити перф-гейт?
Найкращі кандидати — коди відповідей і : їхнє погіршення найточніше збігається з тим, що реально відчує користувач. Показники споживання процесора для цієї ролі значно гірші: більше витраченого ресурсу ще не означає гіршого сервісу, зате дає нестабільний шумний процес, а шумний процес зрештою вимикають або перестають читати. Над вибором стоїть головна вимога: зміна метрики має однозначно вказувати на ту зміну, яку ви перевіряєте, і не бути заручником зовнішніх обставин — саме тому критерієм беруть процесорний час, витрачений на обслуговування запиту, а не завантаженість процесора машиною загалом. Окремий нюанс — 4xx із оцінки прибирають, натомість додають перевірку доступності конкретного URL, бо 404 однаково пояснюється і зламаним сервером, і користувачем, який пішов за неправильним посиланням. Придатність метрики перевіряється одним питанням: чи може вона зрушити без жодної зміни у вашому коді.
Скільки метрик брати в критерій?
Небагато: орієнтир канону SRE — кілька найкращих, у стелі десь дюжина. Причина не в лінощах — після певної кількості метрики дають дедалі менше користі, а вигоду з'їдає вартість супроводу або, що гірше, підірвана довіра до релізного процесу. Механіка деградації проста: сорок критеріїв на шумному середовищі майже гарантують регулярне випадкове червоне, після чого команда вчиться перезапускати джобу, навіть не читаючи, що впало. Тому правильний рух — не «додамо метрику, щоб нічого не проґавити», а спершу відповісти, яку дію команда виконає, коли саме ця метрика почервоніє. Немає відповіді — метриці місце у звіті, а не в гейті.
Як зрозуміти, чи ваш гейт узагалі придатний до вжитку?
Зручний словник дає канон SRE у темі сповіщень: точність (яка частка спрацювань виявилася значущою), повнота (яку частку значущих подій узагалі помічено), час виявлення й час скидання, причому надто довге скидання породжує плутанину або звичку махати рукою на проблему. Ці ж чотири властивості читаються й на перф-гейті: критерій, що червоніє через сусіда по ранеру, має погану точність, а критерій, який проґавлює повільне сповзання, — погану повноту. Там же наведено числову ілюстрацію сліпої зони: правило зі швидкістю витрачання 35 не спрацьовує взагалі ніколи, хоча за 20,5 години такий темп вичерпує місячний повністю. Висновок для CI прямий — у будь-якого одного порога є ділянка, якої він не бачить, і саме тому рівнів запуску роблять кілька. Питання «а чого ваш гейт не ловить» на співбесіді добре відрізняє того, хто його будував, від того, хто про нього читав.
Розкладіть рівні запуску перф-тестів у пайплайні.
Модель приходить із : замість одного етапу оцінювання беруть кілька, і кожен відповідає тому, наскільки впевнено ми вміємо міркувати про метрики на цій вибірці. На малому етапі читають найгрубіші ознаки — застосунок упав, запити відмовляють, — а делікатніші показники стають придатними лише тоді, коли вибірка виросла. У перекладі на пайплайн виходить три рівні. На PR — смоук на хвилини з грубими критеріями, і саме він блокувальний. Уночі за розкладом — повний , який звітує в тренд і мерджу не заважає: він довгий, вердикт приходить, коли гілку вже злито, а цінність його не у вердикті, а в ряді точок. На релізі — повний набір із порівнянням проти базового виміру, і цей рівень має право зупинити випуск. Механіка розділення проста: набір скриптів у дії запуску задають шаблоном шляху, тож із того самого репозиторію різні шаблони дають різні набори; корисно ще й тримати підготовку середовища й сам прогін окремими кроками, щоб у червоній джобі було видно, що впало — установка інструмента чи тест. Сама розкладка стандартом не є: канон дає лише поетапну модель, а який саме рівень блокує — рішення команди за її апетитом до .
Чому абсолютні числа зі спільного hosted-ранера не порівнюють між прогонами?
Бо ранер — не вимірювальний прилад. Мітка ubuntu-latest нічого не гарантує: за нею в публічному репозиторії стоїть машина на 4 процесори й 16 ГБ памʼяті, а в приватному — удвічі скромніша, 2 процесори і 8 ГБ (дані GitHub станом на 2026-08-01). Суфікс -latest теж не про свіжість системи: це просто останній стабільний , який не зобов'язаний нести найновішу версію ОС, і яке саме залізо вам дісталося, чесно повідомляє лише лог прогону. Версія інструмента поводиться так само: якщо її не задати явно, дія встановлення візьме найновішу, тож стрибок цифр цілком може виявитися апдейтом генератора, а не регресією системи. Додайте сусідів: серед великої кількості машин трапляються перевантажені (oversubscribed) вузли, машини з іншими ядрами й вузли в перевантаженому сегменті мережі, — і канон дає прямий вердикт, що такий сусід є справжньою проблемою, але спричинений він не вашою зміною, тож помічати прогін проваленим не можна. Робочий висновок: ранер лишають пусковим механізмом, навантаження генерують у виділене середовище, а в звіт джоби кладуть рядок про конкретну машину — інакше розбір «чому у вівторок усе повзло вдвічі довше» починається з порожнього місця.
Чим бюджет продуктивності відрізняється від порога?
Тим, що вони міряють різне. обмежує характеристики самої сторінки — її сумарну вагу, час завантаження в мобільній мережі, ба навіть кількість HTTP-запитів; поріг натомість обмежує метрики прогону під навантаженням. Складають бюджет із трьох класів: кількісного (вага скриптів і картинок, кількість шрифтів і зовнішніх ресурсів), часових віх (події завантаження, з яких найкорисніші — користувацькі метрики) і правил-балів, які рахують Lighthouse та WebPageTest; канон радить комбінувати класи, бо самі лише кілограми про досвід кажуть небагато — дві сторінки з тією самою вагою й тією самою кількістю запитів малюються з різною швидкістю, і вирішує черговість, у якій ресурси йдуть по мережі. Записують обмеження завжди разом з умовами виміру — яка сторінка, який пристрій, яка мережа: «на мобільному сторінка товару не везе більш ніж 170 КБ JavaScript». Числа при цьому не універсальні: канонічні приклади пораховані на базових пристроях та швидкості 3G і датовані 2018 роком, тож переносити їх у проєкт можна тільки разом із датою й умовами, а краще — переміряти самим. Гейтом бюджет стає завдяки трьом реакціям на перевищення: оптимізувати наявне, викинути наявне або відмовитися від нового — і саме третя перетворює його зі звіту на інструмент вибору.
Чому бал Lighthouse — поганий кандидат у гейти?
Бо бал не є виміром, він є позицією. Інструмент бере сире значення метрики й переводить його в оцінку залежно від того, куди воно потрапляє в логнормальному розподілі, побудованому на живих даних HTTP Archive, — тобто число описує, де ви стоїте відносно решти вебу. Вагові коефіцієнти метрик від версії до версії переглядають, тому оцінки, зняті різними складаннями інструмента, між собою не порівнюються — версію CLI в пайплайні закріплюють так само старанно, як версію . Головне ж застереження дає сам інструмент: думати треба не про одну цифру, а про те, як бали розсіяні, — отже, поодинокий прогін гейтом бути не може, звідки й багаторазовий аудит у Lighthouse CI. Додайте обмеження лабораторії: один пристрій, одна мережа, одна географія, і відтворювати реальний розкид користувачів вона й не намагається. Цінність її при цьому реальна — упіймати регресію ще до релізу, коли фізично немає; а от про гонитву за ідеальним балом суто заради SEO Google Search зауважує, що це, найімовірніше, не найкраще витрачання часу.
Де живуть результати перф-прогонів і навіщо їх узагалі зберігати?
Тренд живий рівно доти, доки збережені його точки, тому питання зберігання — не про акуратність, а про здатність узагалі відповісти «коли почалося». Тут важливо розрізняти дві форми виводу: підсумкова статистика описує прогін цілком і відповідає на «пройшли чи ні», а послідовність точок із мітками часу показує, з якого моменту почалося сповзання. Складати підсумки різних прогонів між собою не можна, тому для порівняння беруть саме точки — їх пишуть у файл або відправляють стрімом у сервіс. На фронтенді цю роль виконує Lighthouse CI, який заявляє себе як інструмент «ганяти, зберігати, діставати й перевіряти» результати й має під історію окремий сервер. Найцінніше в такій історії — зіставлення двох версій сайту аж до конкретного ресурсу: питання перестає бути «бал упав» і стає «що саме потовстішало». І дві дрібниці, без яких ряд бреше: закріплена версія кожного інструмента (у канонічному прикладі CLI Lighthouse узято як @0.15.x), інакше ви побачите зміну вимірювача замість зміни системи, і продовження вимірів після релізу, бо дані живих користувачів показують те, чого лабораторія не покаже ніколи.
Три кейси з робочого життя: розслідування червоного перф-гейта, у якому винен не реліз; розкладка рівнів запуску плюс перевірка, чи гейт узагалі щось блокує; і на сторінку товару як гейт для фронтенду. Скрізь — що дивитися і чому саме це.
Кейс 1. «Просіли на 15% проти минулого тижня» — чи це взагалі регресія?
Ранкове повідомлення в каналі: нічний прогін показав p(95) 820 мс проти 715 мс тиждень тому, «схоже, винен вчорашній мердж». Перш ніж заводити дефект на продуктивність, треба відповісти на інше питання — чи належить ця різниця вашій зміні. Час між двома точками сам по собі є одним із найбільших джерел варіації метрик, тож пара «до й після» доказом не є, поки не виключено все нижче.
| Підозра | Як перевіряю | Що означає підтвердження |
|---|---|---|
| Дистанція в часі | Дивлюсь, які дні порівнюються: будній проти вихідного, до й після маркетингової розсилки | Порівняння зіпсоване шумом сезону, а не кодом; потрібна нова точка відліку |
| Власна дисперсія виміру | Ганяю той самий коміт кілька разів поспіль і дивлюсь розкид | Якщо розкид сам по собі перекриває 15%, дельта нічого не доводить |
| Залізо ранера | Читаю в логах прогону рядок про те, яка машина його виконувала | Мітка ubuntu-latest версію не закріплює, а специфікація залежить від видимості репозиторію (2026-08-01: 4 CPU / 16 ГБ у публічному проти 2 CPU / 8 ГБ у приватному) |
| Сусіди по хосту | Порівнюю метрику, віднесену до роботи (процесорний час на запит), із загальною утилізацією | Перевантажена сусідня машина — реальна проблема, але не наслідок нашої зміни, тож провалом бути не має |
| Версія інструмента | Звіряю версію генератора навантаження в обох прогонах | Без явного закріплення дія встановлення бере останню версію — цифри міг зрушити апдейт вимірювача |
| Дані середовища | Перевіряю обсяг тестових даних і стан кешів на стенді | Виріс набір даних — виріс час запиту; це не регресія коду |
Що робити з результатом розслідування:
- Спочатку виключаємо шум, потім звинувачуємо . Найдешевша перевірка тут — повтори на одному коміті: вони дають межу, нижче за яку будь-яка дельта не має сенсу. Якщо 15% усередині власного розкиду — питання закрито без дефекту. Скільки саме повторів достатньо, канонічне джерело не каже: цей команда виводить власним виміром і фіксує як домовленість.
- Не розширюйте поріг «щоб не блимало». Це прибирає симптом і залишає сліпий гейт. Задокументована відповідь на дисперсію — прогнати вимір багато разів, а не пом'якшити критерій.
- Сильніша конструкція замість чергової пари точок — паралельний контроль: обидві версії міряються одночасно, тож час перестає бути змінною. Пам'ятайте про його ваду: спільні бекенди, мережа й сховище просідають одразу з обох боків, і різниця зникає саме тоді, коли вона реальна.
- Метадані точки важать не менше за саму точку. , версія інструмента, коміт, обсяг даних — без них ряд результатів через місяць неможливо інтерпретувати, і кожне таке розслідування починається з нуля.
Кейс 2. Розкладка рівнів і перевірка, чи гейт справді гейт
Типова помилка при впровадженні — зробити один перф- і повісити його блокувальним на PR. Далі він або довгий (і всі чекають), або шумний (і всі перезапускають). Нижче — розкладка одного конкретного проєкту: канон дає лише модель етапів і не приписує, який з них блокує, тож команда з іншим апетитом до розставить колонку «Блокує?» інакше.
| Рівень | Тригер | Набір | Тривалість | Блокує? | З чим порівнюємо |
|---|---|---|---|---|---|
| Перф-смоук | пуш у PR | smoke* | хвилини | так, грубими критеріями | ні з чим: дивимось відмови й кратне погіршення |
| Нічний прогін | розклад | load* | десятки хвилин | ні, звітує у тренд | попередні точки ряду |
| Релізний прогін | реліз | повний профіль | години | так, має право зупинити реліз | базовий вимір |
Три речі, які роблять таблицю робочою, а не декоративною:
- Різні набори беруться шаблоном шляху до скриптів — той самий репозиторій, різні глоби в різних джобах. Не треба ані окремих репозиторіїв, ані прапорців усередині скрипта.
- Установка інструмента й сам прогін — окремі кроки. Тоді в червоній джобі одразу видно, що впало: середовище не піднялося чи тест не пройшов. «Зелено/червоно» одним кроком цю різницю ховає.
- Блокувальним робіть лише той рівень, чиї критерії ви готові захищати перед розробником увечері в п'ятницю. На практиці це із грубими порогами.
Мінімальний PR-смоук на тому, що вже є в проєкті, — Playwright і його API-контекст. Критерії свідомо грубі: жодних тонких , лише й кратне погіршення.
import { test, expect } from '@playwright/test';
import baseline from './perf-baseline.json'; // { "checkout": { "medianMs": 240 } }
test('перф-смоук: сценарій живий і не просів кратно', async ({ playwright }) => {
const api = await playwright.request.newContext({ baseURL: process.env.BASE_URL });
const durations: number[] = [];
let failures = 0;
for (let i = 0; i < 30; i++) {
const started = Date.now();
const res = await api.post('/api/checkout', { data: { sku: 'A-1', qty: 1 } });
durations.push(Date.now() - started);
// грубий критерій: рахуємо саме відмови сервера, 4xx у гейт не беремо
if (res.status() >= 500) failures++;
}
durations.sort((a, b) => a - b);
const median = durations[Math.floor(durations.length / 2)];
expect(failures, 'сервер віддавав 5xx — сценарій або система зламані').toBe(0);
// не «на 10% гірше», а «вдвічі гірше»: на спільному ранері тонше міряти нічим
expect(median).toBeLessThan(baseline.checkout.medianMs * 2);
await api.dispose();
});
Що дивитися і чому:
- Поріг тут один і грубий. Спільний ранер не є вимірювальним приладом, тому на цьому рівні ловлять зламаний сценарій і кратне падіння, а не десять відсотків. Тонке порівняння з живе на нічному рівні й на виділеному залізі.
5xxу критерії,4xx— ні. Клієнтські коди однаково добре пояснюються і зламаним сервером, і кривими , тому їх виносять у звіт, а доступність конкретного URL перевіряють окремою перевіркою.- має бути саме асертом. Тест, який лише пише числа в і завжди зелений, гейтом не є: бачить тільки код виходу.
Окремо перевірте, що гейт узагалі щось блокує, — це п'ятихвилинний експеримент, який рятує квартал самозаспокоєння:
1. Створити чернетковий PR, у якому перф-скрипт свідомо зламано.
2. Переконатися, що джоба червона — а не «пропущена умовою if».
3. Переконатися, що кнопка мерджу заблокована, а не просто підсвічена.
4. Прибрати поламку й повторити для випадку «поріг перевищено на 1 мс».
Пастка тут документована: обов'язкова перевірка вважається пройденою у станах successful, skipped і neutral, тож джоба, яку відрізала власна умова if, лишає гейт зеленим. І пам'ятайте: локальний хук за природою нічого не блокує — pre-commit знімається прапорцем --no-verify, тож він лишається швидким фідбеком.
Кейс 3. Бюджет продуктивності на сторінку товару
Фронтенд у пайплайні гейтять не порогом на , а бюджетом — набором обмежень на те, що впливає на швидкість сторінки. Бюджет корисний рівно тоді, коли сформульований разом із контекстом виміру: без сторінки, пристрою й мережі число нічого не означає.
| Клас метрики | Обмеження | Контекст виміру | Дія при перевищенні |
|---|---|---|---|
| Кількісна | JavaScript сторінки товару — не більш ніж 170 КБ | мобільний профіль, повільна мережа | не додавати нову бібліотеку; шукати заміну |
| Кількісна | не більш ніж 2 вебшрифти й 1 hero-зображення до 120 КБ | той самий профіль | прибрати зайвий шрифт |
| Віха часу | користувацька метрика завантаження не гірша за поточну точку ряду | лабораторний прогін, медіана повторів | оптимізувати наявний ресурс |
| Правило-бал | бал аудиту продуктивності сторінки вище 80 | той самий профіль, медіана прогонів | розбирати, який саме аудит просів |
Що дивитися і чому:
- Три класи метрик комбінують, а не обирають один. Самі лише кілограми про досвід кажуть мало: дві сторінки з тією самою вагою й тим самим числом запитів малюються з різною швидкістю, бо все вирішує черговість, у якій ресурси йдуть по мережі.
- Числа — не універсальні константи. Канонічні приклади пораховані на базових пристроях і швидкості 3G і датовані 2018 роком, тому в проєкт їх переносять не копіюванням, а власним виміром. Цитувати — тільки разом із датою й умовами.
- Головна дія в переліку — третя: не додавати нове. Оптимізувати й прибирати команда вміє й без бюджету; сенс бюджету в тому, що він змушує вибирати між фічами до того, як вони поїхали в прод. Швидкість сама собою, побічним ефектом, з'являється рідко.
- Самотній прогін Lighthouse на роль гейта не годиться. Бал — це позиція серед реальних даних вебу, а вагові коефіцієнти метрик переглядають від версії до версії, тому версію CLI фіксують явно (у канонічному прикладі —
@0.15.x), а рішення ухвалюють за розсіюванням кількох прогонів, не за однією цифрою. - Лабораторія не замінює поле. Один пристрій, одна мережа, одне розташування — реального розкиду користувачів такий прогін не показує. Його цінність в іншому: він ловить до релізу, коли ще фізично немає.
Роль перф-тесту в пайплайні
- Розумію, що в шукають відповідь «чи зробила гірше саме ця зміна», а межу витривалості системи міряють іншим тестом і в інший час.
- Можу пояснити, чому в CI живе лише частина перф-набору (час короткий), і назвати штатні альтернативи — розклад на cron- й ручний запуск як пункт релізного чекліста.
- Можу описати перф- на PR: низьке навантаження, хвилини, привід — зміна коду; його дві ролі — довести, що сценарій живий, і не дати протухнути.
Гейт: поріг, код виходу, форма
- Знаю, що єдиний інтерфейс прогону до пайплайна — код виходу, тож джоба без жодного порога не блокує нічого, хоч би скільки звітів вона склала у сховище.
- Не плутаю чек і поріг: провалений чек тест не валить, інструмент лише рахує його частку — блокування зʼявляється тільки з порогом поверх неї.
- Можу розібрати форму гейта: фіксоване число проти дельти щодо попередньої версії, увесь код проти лише нового, — і пояснити, чому тиск заради влучання в метрику закінчується послабленим порогом уночі перед релізом.
- Знаю дірки у фразі «у нас усе під гейтом»: пройденою вважається перевірка у трьох станах (successful, skipped, neutral), зелений пайплайн апрувом не є, а
pre-commitзнімається прапорцем--no-verify.
Порівняння з базовим виміром
- Можу пояснити, що таке базовий вимір, чому без нього результат прогону оцінити нічим і чому його може бути потрібно спершу створити — зокрема на знеособлених даних із бази.
- Розумію, чому «сьогодні проти минулого тижня» — слабкий доказ: дистанція в часі сама зрушує метрики, а понеділковий реліз фактично зіставляє будні з вихідними.
- Знаю дві сильніші конструкції — повтори того самого (видно власний розкид) і контроль, що йде паралельно, — ваду другої (збій у спільній інфраструктурі просідає обидві половини порівняння) і те, що штатна реакція на розкид — повторити вимір, а не розширити планку.
Метрика гейта і його придатність
- Знаю, що критерієм беруть коди відповідей і , а не завантаженість процесора, і можу сформулювати вимогу віднесеності: метрика має зрушуватися саме перевірюваною зміною, тому міряють процесорний час на обслуговування запиту. Орієнтир за кількістю — кілька найкращих, у стелі дюжина.
- Можу оцінити гейт за чотирма властивостями (точність, повнота, час виявлення, час скидання) і пояснити, чому в будь-якого одного порога є сліпа зона — канонічний приклад зі швидкістю витрачання 35, за якої правило мовчить завжди.
Рівні запуску й шум середовища
- Можу розкласти три рівні: блокувальний смоук на PR із грубими критеріями, нічний повний прогін у тренд без блокування, релізний прогін із порівнянням проти базового виміру; знаю, що набори розводять шаблоном шляху до скриптів.
- Пам'ятаю, що за міткою
ubuntu-latestховається різне залізо (у публічному репозиторії 4 процесори й 16 ГБ памʼяті, у приватному вдвічі менше, дані GitHub на 2026-08-01), суфікс-latestсвіжості ОС не гарантує, а версію інструмента без явного вказання беруть найновішу. - Знаю, що перевантажений сусід по хосту є справжньою проблемою, але провалом перевірюваної зміни не є, тому спільний ранер тримають пусковим механізмом, а тонке порівняння роблять на виділеному залізі.
Бюджети продуктивності та Lighthouse
- Можу дати означення , назвати три класи метрик (кількісні, часові віхи, правила-бали) і пояснити, чому обмеження записують разом із контекстом виміру, а канонічні числа — лише з датою й умовами (базові пристрої, 3G, 2018 рік).
- Пам'ятаю три реакції на перевищення бюджету — оптимізувати наявне, викинути наявне або відмовитися від нового — і розумію, чому рівна вага сторінок ще не означає рівної швидкості: вирішує черговість завантаження ресурсів.
- Можу пояснити, чому бал Lighthouse сам по собі поганий гейт (позиція серед реальних даних вебу, переглянуті вагові коефіцієнти, потреба дивитися на розсіювання оцінок) і де межа лабораторного виміру.
Тренд та історія результатів
- Розрізняю дві форми виводу: підсумкова статистика відповідає «пройшли чи ні», а точки з мітками часу — «коли почалося», і лише друга годиться для порівняння прогонів і для тренду.
- Знаю, навіщо закріплювати версії інструментів і тримати окреме сховище історії: без цього в ряду точок зміни продукту перемішані з апдейтами самого вимірювача.
Квіз
Перед стартом
- Питань: 16
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Чим мета перф-прогону в CI відрізняється від мети повного навантажувального?