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

    10 · Performance testing

    Середовище, генератори навантаження і достовірність

    Зміст

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

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

    Достовірність перф-середовища: що мусить збігатися

    (test environment fidelity) — це відповідь на питання «наскільки цифри зі стенда переносяться на прод». Канон вимагає зробити тестове середовище настільки близьким до продакшену, наскільки можливо, а якщо це неможливо — мати чітке розуміння відмінностей і того, як результати проєктуватимуться на продакшн. Друга половина вимоги важливіша за першу: точну копію мало хто може собі дозволити, а от назвати відмінності зобовʼязані всі.

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

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

    Далі те, що пропускають найчастіше. Зменшене середовище потребує іншої конфігурації, а не просто менших очікувань. Якщо на тестових машинах менше фізичної памʼяті, параметри памʼяті ПЗ (наприклад, розмір heap Java) доводиться коригувати, щоб уникнути сторінкової підкачки. Інакше стенд почне свопити там, де прод не свопить, і зміряє власне налаштування.

    Мережа має два зрізи. Географія: для глобальних систем один із підходів — розгорнути генератори там, де є користувачі, а для мобільних емуляція мережі лишається найбільш життєздатним варіантом через різноманіття типів мереж. І те, чого не видно в конфігах: за замовчуванням JMeter користується кешем DNS віртуальної машини Java — саме тому навантаження отримує лише один сервер кластера, і окремий елемент керування кешем DNS існує рівно для застосунків із кількома серверами за балансувальниками (CDN тощо). Сюди ж — підміна IP, тобто симуляція того, що кожен має іншу адресу: ISTQB називає її серед налаштувань інструмента, і без неї балансувальник та засоби обмеження частоти (rate limiting) бачать один клієнт, а не тисячу. Де стоїть сам генератор — теж частина середовища: виконувати JMeter на сервері застосунку можна, але це додає йому обчислювального навантаження, і результати будуть дещо зіпсовані; рекомендований варіант — машини в тому самому сегменті мережі.

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

    import { test, expect } from '@playwright/test';
    
    // передпольотна перевірка: той білд і ті дані, на які ми розраховували
    test('стенд валідний перед прогоном', async ({ request }) => {
      const version = await (await request.get('/api/version')).json();
      expect(version.commit).toBe(process.env.EXPECTED_COMMIT);
    
      const stats = await (await request.get('/api/internal/stats')).json();
      expect(stats.orders).toBeGreaterThan(1_000_000);
    });

    І межа, яку варто знати навіть тим, хто ніколи не бачив власного стенда: прод відтворити не можна в принципі. Канон SRE каже це прямо — продакшн зазвичай не герметичний, бо темп вносить живі зміни малими зрозумілими частинами, а самі зміни можуть потрапляти в прод не в тому порядку, у якому їх додавали в систему контролю версій; висновок джерела ще різкіший: усе продове середовище навмисно не є представницьким для жодної окремої версії бінарника з репозиторію. «Prod-like» — це керована відмінність, а не досяжна рівність.

    Чому не можна множити на коефіцієнт

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

    Механізм найкраще видно на канонічному прикладі (cascading failure). Якщо один кластер відмовляє, запити до сусіднього зростають до 1200 за секунду; фронтенди не здатні обробляти 1200, тож починають вичерпувати ресурси, падати, зривати дедлайни або поводитися неправильно — і в результаті частота успішно оброблених запитів опускається значно нижче за 1000. Навантаження зросло на 20%, а корисна робота впала нижче початкової. Жоден коефіцієнт такого не описує.

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

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

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

    Генератор — теж система під навантаженням

    Машина, що створює навантаження, має ті самі ресурси й те саме , що й система під тестом. Коли впирається вона, тест починає міряти себе — і найгірше, що цифри при цьому виглядають як проблема системи: якщо інструмент використовує 100% процесора для , тест зазнає обмежень (throttling), і метрики результату покажуть значно більший , ніж є насправді.

    Пороги здоровʼя генератора дока k6 дає числами: щонайменше 20% простою процесора (тобто до 80% зайнятості), памʼять не вище 90%, мережа не в поличці — багато машин EC2 мають зʼєднання 1 Гбіт/с, і якщо трафік постійно тримається на цій позначці, тест, імовірно, обмежений мережевою картою. Своп вимикають: підкачка на набагато повільніше сховище дає непередбачувані ефекти й найімовірніше знецінить результати, бо генератор працював по-різному в різних частинах прогону. Памʼять оцінюють заздалегідь: прості тести — приблизно 1–5 МБ на віртуального користувача, тести з вивантаженням файлів — десятки мегабайтів; спосіб порахувати — прогнати тест на 100 користувачах і помножити спожите на цільову кількість.

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

    Як довести, що вперлися саме в генератор:

    • помилки розводяться за : socket: too many open files — це генератор досяг межі відкритих дескрипторів; read: connection reset by peer — зʼєднання скинула цільова система; context deadline exceeded — запит пішов, але система не відповіла вчасно;
    • генератори моніторять як систему: ISTQB вимагає цього прямо, щоб уникнути ситуації, коли навантаження не тримається належно через повільний генератор;
    • ресурс — це не лише процесор і памʼять: у чеклісті USE дескриптори файлів і ліміт задач є повноцінними ресурсами з власною утилізацією й власними помилками.

    процесор під стелю, памʼять під стелю

    є запас

    too many open files

    connection reset by peer

    context deadline exceeded

    Цифри гірші, ніж очікували

    Що з ресурсами генератора?

    Міряємо генератор:
    тротлінг завищує час відповіді

    Яка помилка у звіті?

    Межа генератора:
    дескриптори файлів

    Зʼєднання скинула система

    Система не відповіла вчасно

    процесор під стелю, памʼять під стелю

    є запас

    too many open files

    connection reset by peer

    context deadline exceeded

    Цифри гірші, ніж очікували

    Що з ресурсами генератора?

    Міряємо генератор:
    тротлінг завищує час відповіді

    Яка помилка у звіті?

    Межа генератора:
    дескриптори файлів

    Зʼєднання скинула система

    Система не відповіла вчасно

    Окремий клас — інструмент, що зʼїдає ресурси вимірювача. Більшість елементів Listener у JMeter тримає копію кожного семпла, який показує, тож «подивлюся дерево результатів під час прогону» перетворює тест на вимір власного інтерфейсу; канон радить протилежне — режим командного рядка, якнайменше елементів Listener і , CSV замість XML, дані для рандомізації файлом заздалегідь. У k6 те саме з іншого боку: тіло відповіді за замовчуванням вантажиться в памʼять, а кожен унікальний URL створює новий обʼєкт часового ряду.

    Скільки тягне одна машина — числа з доки k6: один процес ефективно використовує всі ядра, один екземпляр тягне 30 000–40 000 одночасних користувачів, і якщо вам не треба більше за 100 000–300 000 запитів за секунду, одного екземпляра, найімовірніше, досить. Тобто розподілену генерацію треба доводити, а не оголошувати — механіка й пастки в главі про інструменти.

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

    Що стоїть між генератором і системою

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

    Генератор
    власні ресурси й ліміти

    Мережа
    сегмент, смуга, стрибки

    Edge-вузол CDN
    віддає з кешу

    Балансувальник і обмеження частоти
    бачать один клієнт

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

    Те, що ви хотіли зміряти

    Генератор
    власні ресурси й ліміти

    Мережа
    сегмент, смуга, стрибки

    Edge-вузол CDN
    віддає з кешу

    Балансувальник і обмеження частоти
    бачать один клієнт

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

    Те, що ви хотіли зміряти

    CDN (Content Delivery Network) — це спільний кеш. Мережа проміжних серверів стоїть географічно ближче до користувачів і кешує відповіді, тож віддавання статики через CDN знижує навантаження запитами на власні сервери організації; такі керовані кеші (reverse proxy, CDN, service worker разом із Cache API) розгортають самі розробники сервісу, щоб розвантажити origin. Наслідок для перф-тесту прямий: якщо сценарій тягне статику, зміряна (system ) частково описує , а не систему під тестом, і директива s-maxage задає таким кешам окремий термін свіжості. Механіка — у главі Кешування; тут важливий один висновок: перед прогоном треба знати, що зі сценарію взагалі доїжджає до системи.

    Обмеження частоти рахує вас одним клієнтом. Код 429 вказує, що користувач надіслав забагато запитів за проміжок часу, причому RFC свідомо не визначає, як сервер ідентифікує користувача й рахує запити; на практиці рахують за IP клієнта, а за наявності автентифікації — за користувачем чи застосунком, і саме обмеження буває як на весь сервер, так і на окремий ресурс. Заголовок Retry-After при 429 необовʼязковий, а формат його — або HTTP-дата, або кількість секунд; той самий заголовок трапляється й при 503, і при редиректі, тож «побачив Retry-After — значить ліміт» хибно.

    Для прогону з цього випливає три речі. Перша: полиця пропускної здатності може належати обмежувачу, а не системі, — і виглядає вона як ідеально рівне плато. Друга: усі віртуальні користувачі одного генератора йдуть з однієї адреси, тому без підміни IP ви впираєтеся в ліміт швидше за будь-якого реального користувача. Третя: OWASP у редакції 2023 перейменував відповідний на Unrestricted Resource Consumption, змістивши акцент із самого ліміту на вичерпання ресурсів, включно з платними за виклик (лист, SMS, дзвінок) — тобто сценарій, який зачіпає такі операції, коштує грошей, і це пункт погодження прогону, а не деталь.

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

    WAF як чинник спотворення виміру

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

    Синтетичне навантаження мало схоже на людей: однакові заголовки, рівний темп, кілька адрес на тисячі сесій. Периметр — а це зазвичай WAF (web application firewall) — цілком може прочитати це як атаку й почати відсіювати запити, підкидати перевірки або притримувати темп — і далі ваш графік описує реакцію периметра, а не системи. Найгірше, що виглядає це як правдоподібна деградація: час відповіді росте, зʼявляються помилки, у системних метриках тим часом спокій.

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

    Стаби замість зовнішніх залежностей

    ISTQB називає цю практику поіменно: якщо якісь частини системи або даних недоступні для перф-тестів із будь-якої причини, слід реалізувати обхід — наприклад, (stub, у побуті «заглушка»), що замінює й емулює сторонній компонент, відповідальний за обробку кредитних карток. Процес часто називають (service virtualization), для нього є спеціальні інструменти, і їх використання наполегливо рекомендоване, щоб ізолювати систему під тестом. Ключове слово — ізолювати: без цього перф-тест міряє чужий сервіс замість свого.

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

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

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

    І межа, яку називають у звіті: замінивши сервіс, ви перестали міряти систему цілком. Результат стосується системи з фіктивною залежністю — рівно як і будь-яка інша відмінність середовища.

    Тестування на проді: коли виправдано

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

    Канонічна форма присутності перф-тестування на проді інша — і вона не про генерацію навантаження. (scalability testing) — вид, який розбирає глава про види performance-тестів; тут ми беремо з нього один наслідок. Воно визначає масштабованість — ступінь, у якому компонент або систему можна підлаштувати під змінну ємність. Результат цього виду канон описує як експлуатаційний артефакт: щойно межі масштабованості відомі, порогові значення можна встановити й моніторити на проді, щоб отримати попередження про проблеми, які можуть ось-ось виникнути; саме продове середовище при цьому можна підлаштувати відповідною кількістю заліза. Тобто число дає лабораторія, а прод його стереже — що з цим числом робить моніторинг, розбирає глава про APM і спостережуваність.

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

    Типові помилки

    «Час відповіді виріс — система деградує». Виглядає як знахідка, а насправді першим виключають генератор: при 100% зайнятості процесора тест зазнає обмежень тротлінгу, і метрики покажуть значно більший час відповіді, ніж є насправді. Тому перед цією фразою у звіті має стояти графік ресурсів генератора — ISTQB і вимагає моніторити машини генерації нарівні із системою.

    «У звіті too many open files — система не тримає зʼєднань». Виглядає як відмова системи, а насправді це наш бік: генератор досяг межі відкритих дескрипторів, а дескриптори файлів і ліміт задач — повноцінні ресурси з власними помилками. Скинуте зʼєднання (connection reset by peer) — навпаки, вердикт цільової системи.

    «Швидший сервер розвантажує генератор». Виглядає логічно, а насправді навпаки: швидший сервер змушує інструмент працювати більше, бо повертає відповідь швидше. Звідси й сусідня пастка — неправильно підібрана кількість потоків і Coordinated Omission із хибними або неточними результатами. Того самого класу помилка — «подивлюся дерево результатів під час прогону»: більшість елементів Listener тримає копію кожного показаного семпла, і тест починає міряти власний інтерфейс.

    «Ми навантажили кластер із шести вузлів». Виглядає як тест кластера, а насправді — тест одного вузла: за замовчуванням JMeter користується кешем DNS віртуальної машини Java, тож усі запити йдуть на один сервер. Дзеркальна помилка — поставити генератор на машину застосунку: так робити можна, але це додає їй навантаження, і результати будуть дещо зіпсовані.

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

    Підсумок

    1. Цифра без опису середовища — половина цифри. Канон вимагає стенда, максимально близького до проду, а якщо це неможливо — чіткого розуміння відмінностей і того, як результати проєктуватимуться на прод.
    2. Дані стоять першими серед частин середовища: розмір і структура кардинально впливають на результат, а передбачити цей вплив до реального тесту важко.
    3. Множити на коефіцієнт не можна: продуктивність є нелінійною функцією середовища, і 20% зайвого навантаження здатні опустити корисну роботу нижче початкової.
    4. Генератор — теж система: до 80% процесора, памʼять до 90%, мережа не в поличці, своп вимкнено; помилки розводять за походженням, а машини генерації моніторять нарівні із системою.
    5. Усе, що стоїть між генератором і системою, — частина виміру: edge-вузол CDN, балансувальник, обмеження частоти, периметр і кожен стаб.

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

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

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

    «Час відповіді в тесті виріс. Ваші дії?» Перевіряють порядок: спершу ресурси генератора й походження помилок, і лише потім метрики системи. Хто одразу йде до бекенду, пропускає найчастішу причину хибної тривоги.

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

    «Чи можна ганяти навантаження на проді?» Питання не про сміливість, а про ціну й альтернативу. Сильна відповідь: канонічний вихід перф-тесту на прод — це пороги з відомих меж масштабованості під моніторингом, а не генератор; а якщо навантаження на проді неминуче, називають ризик, спосіб відкату даних і готовий до старту моніторинг.

    Джерела

    Достовірність перф-середовища: що мусить збігатися

    Чому не можна множити на коефіцієнт

    Генератор — теж система під навантаженням

    • Grafana k6 — Running large tests — тротлінг генератора й завищений час відповіді, пороги процесора, памʼяті й мережі, оцінка памʼяті на користувача, розведення помилок за походженням, скидання лімітів ОС після перезапуску, ємність одного екземпляра.
    • Apache JMeter — Best Practices — швидший сервер навантажує генератор сильніше, Coordinated Omission, настанови про режим запуску, елементи Listener, асерти й формат результатів.
    • Apache JMeter — Introduction to listeners — більшість елементів Listener тримає копію кожного показаного семпла.
    • ISTQB® CT-PT — Foundation Level Specialist Syllabus, Performance Testing v1.0 (2018) — §4.2.8: вимога моніторити й самі машини генерації навантаження.
    • Brendan Gregg — USE Method: Linux Performance Checklist — дескриптори файлів і ліміт задач як ресурси з власною утилізацією й помилками.

    Що стоїть між генератором і системою

    • MDN Glossary — CDN — CDN як мережа серверів у багатьох локаціях і зниження навантаження запитами на власні сервери організації.
    • MDN — HTTP caching — керовані кеші (reverse proxy, CDN, service worker) і навіщо їх розгортають.
    • RFC 9111 — HTTP Caching — спільний кеш проти приватного й окремий термін свіжості s-maxage для спільних кешів.
    • RFC 6585 — Additional HTTP Status Codes — значення 429 і свідома відмова специфікації визначати, як сервер рахує запити.
    • MDN — 429 Too Many Requests — рахунок за IP або за автентифікованим користувачем, обмеження на сервер або на окремий ресурс.
    • MDN — Retry-After header — два формати заголовка й інші коди, при яких він приходить.
    • OWASP API Security Top 10 — 2023 (перелік ризиків) — перейменування ризику на Unrestricted Resource Consumption і акцент на вичерпанні ресурсів, включно з платними за виклик.

    Стаби замість зовнішніх залежностей

    Тестування на проді: коли виправдано

    Пояснення

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

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

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