Що ламається без rate limiting в AI-сервісах
Генерація відповіді моделлю тримає воркер зайнятим увесь час стрімінгу — від першого токена до останнього.
Коли клієнт запускає пакетну обробку або на сервіс приходить сплеск запитів від веб-клієнта, паралельні виклики вишиковуються в чергу, і кожен наступний чекає на слот довше за попередній.
Першим упирається пул воркерів: він розрахований на середнє навантаження, а не на пікове. Далі зростає час відповіді під навантаженням — спочатку до секунд, потім до таймаутів на боці того, хто викликає.
Черга не нескінченна: при переповненні запити відкидаються, але частина роботи вже виконана й витрачена марно.
Далі починаються каскадні відмови. Отримавши таймаут, клієнт повторює запит, і повторні спроби добивають залишки ємності.
Помилки розповзаються на сусідні сервіси — вхідний шлюз, облік споживання, пошук за індексами, кеш: усі вони отримують шквал однакових повторів одночасно й деградують слідом за основним.
Окрема проблема — відсутність розділення ємності. Один інтегратор з агресивним циклом опитування забирає весь пул і роняє якість роботи для решти, формально нічого не порушуючи: перевантаження сервісу виглядає як загальний збій, а не як поведінка конкретного клієнта. Розбираємо, як це закривається: ліміти на клієнта, квоти на токени й пріоритети черг.
Що дає керування лімітами: зняте навантаження й відмови
Дію лімітів видно не за конфігурацією, а за метриками сервісу. Нижче — що змінюється, коли для кожного ключа задані пороги за запитами й токенами, а черга обмежена за глибиною.
Частка відмов перестає залежати від чужого трафіку
Без порогів сплеск в одного споживача йде в загальний пул і роняє всіх: сервіс відповідає помилками, повторні спроби додають навантаження. Окрема черга на ключ обриває цей ланцюжок — частка відмов тримається в одиницях відсотків і в години піку. Лічильник допуску ведемо в Redis з накопиченням токенів: перевірка не подовжує відповідь моделі.
Пік проходить деградацією, а не відмовою
При десятикратному стрибку частина запитів стає в чергу обмеженої глибини, решта отримує зрозумілу відмову із зазначенням, коли повторити. Замість лавини помилок у всіх — передбачувана затримка для тих, хто пройшов поріг. Стійкість тримається на тому, що надлишковий попит переноситься на клієнта, а не на сервіс.
Затримка відповіді перестає «плавати»
Ліміт на довжину контексту й число одночасних генерацій знімає боротьбу за обчислювальні ресурси. Інтерактивні запити отримують пріоритет над пакетними, тому час відповіді на 95-му процентилі залишається в узгодженому коридорі навіть при повному завантаженні.
Ємність розподіляється рівномірно
Квоти на команду й проєкт плюс окремий пул для фонових завдань: один великий споживач не витісняє решту. Гарантована частка ємності закріплена за кожним клієнтом і не дістається тому, хто просто відправив запит першим.
Режими обмеження: ліміти запитів, квоти токенів, черги
Ліміти запитів, квоти токенів, паралельні сесії, буферизація й пріоритети ключів вирішують одне завдання — не дати одному споживачеві з'їсти ємність моделі.
Гранулярність різна: rate limiting рахує звернення, але не їхню вагу, квота токенів не розрізняє десять дрібних викликів і одне важке звернення з великим контекстом.
Тому режими не вибирають «один із», а вишиковують у порядок: що перевіряється першим, що йде в чергу, кому дістається залишок ємності.
| Варіант | Коли підходить | Чим обмежений |
|---|---|---|
| Ліміт за запитами | Зовнішні інтеграції з передбачуваним розміром виклику | Не відображає вартість: важкий і короткий запит вважаються однаково |
| Квота за токенами | Основний бюджет сценаріїв, де довжина промпту й відповіді плаває | Потрібен точний облік; при потоковій віддачі витрата видно за фактом |
| Паралельні сесії | Інтерактивні інтерфейси та агенти, де важлива чутливість | Обмежує одночасність, а не сумарний обсяг |
| Буферизація запитів | Фонові й пакетні завдання без вимоги негайної відповіді | Відповідь приходить із затримкою, потрібні таймаут і політика відмови |
| Пріоритети ключів | Кілька споживачів різної критичності на спільній ємності | Потрібен реєстр ключів; неприоритетні отримують відмову, а не чекають вічно |
На вході — пріоритети ключів, бюджет тримаємо на квоті токенів, ліміт запитів страхує від шквалу дрібних викликів, паралельні сесії вмикаємо для інтерактиву, буферизацію — для фонових завдань.
Порядок перевірок фіксуємо в конфігурації, щоб правила були відтворювані й не залежали від коду окремого сервісу.
Етапи впровадження: від заміру навантаження до регламенту
Перш ніж виставляти ліміти, ми знімаємо реальний профіль: розподіл запитів за годинами, довжину контексту, частку повторних викликів, поведінку окремих клієнтів.
Пороги «на око» однаково погані в обидва боки — завищений ліміт не захищає від перевантаження, занижений ріже легітимні сценарії й виглядає для користувача як нестабільність сервісу. Тому порядок робіт жорсткий.
- Профіль навантаження. Збираємо статистику за кілька тижнів, включно з хоча б одним піковим періодом. Окремо позначаємо, які звернення критичні для бізнес-процесу, а які можна відкласти в чергу.
- Розрахунок порогів. Визначаємо ліміти пошарово — на ключ, на користувача, на весь сервіс, — із запасом до насичення моделі, щоб обмежувач спрацьовував раніше, ніж почне зростати час відповіді.
- Налаштування обмежувача. Вибираємо алгоритм під характер трафіку (ковзне вікно або поповнюване відро) і вводимо роздільні квоти на число запитів і на обсяг токенів: короткий виклик і довгий контекст витрачають ресурс непорівнянно.
- Обробка відмов. Обмеження має бути передбачуваним: зрозумілий код відповіді, зазначення, коли повторити, пріоритетна черга для критичних операцій.
- Перевірка під піком. Проганяємо профіль, що повторює реальний пік із запасом, і фіксуємо, на яких значеннях з'являються відмови й чи не зачіпають вони сумлінних клієнтів.
- Регламент експлуатації. Передаємо документ: як змінювати квоти, де дивитися метрики, за яких відхилень піднімати ліміт, як видати тимчасове виключення.
Окремо домовляємося про перегляд порогів — при зміні сценаріїв або зростанні числа клієнтів цифри застарівають швидше за конфігурацію.
Що передаємо замовнику: конфігурації, схеми, регламенти
Віддаємо не опис «як треба», а робочий комплект, за яким черговий інженер і розробник працюють без нас: файли, застосовні прямо в контурі, і регламенти під конкретні інциденти.
- Конфігурація обмежувачів — правила за ключем, користувачем і моделлю: вікно, поріг, вага запиту. Зберігаються в репозиторії, застосовуються на ходу, без перезапуску сервісу.
- Схема проходження запиту — шлях від клієнта через шлюз до моделі: де рахується витрата токенів, у якій точці спрацьовує відмова і що повертається стороні, що викликає.
- Матриця квот — таблиця за ключами й групами клієнтів: ліміт у хвилину й за добу, окрема стеля на дорогі моделі, запас для службових завдань.
- Інструкція чергової зміни — як відрізнити сплеск навантаження від зловживання, які пороги зміна піднімає сама, а які лише за погодженням.
- Журнал змін порогів — хто, коли і з якої причини рухав ліміт, з можливістю повернути попереднє значення.
- Метрики й оповіщення — частка відмов, залишок квоти, час очікування в черзі; сигнал приходить раніше, ніж деградацію помітять клієнти.
- Порядок видачі й ротації ключів — кому який рівень доступу належить, як ключ відкликається і що відбувається з уже запущеними запитами.
Комплект оновлюємо разом із сервісом: інакше регламент розходиться з контуром, і на інциденті ніхто не знає, де правда.
Кейс: піковий наплив користувачів без відмов
Пік у сервісу генерації відповідей припадав на вечірні години: 40 запитів за секунду при договірному ліміті провайдера OpenAI в 20. Запити йшли напряму — без черги, без обліку витрати токенів на користувача і без розділення за тарифами. Кожен зайвий запит повертав помилку, клієнт повторював його, і лавина тільки посилювалася.
Свою частку вносили й повторні відправлення при таймауті: користувач натискав кнопку ще раз, застосунок ставив друге завдання до того самого вузького місця.
Підсумок — 7,8% відповідей з помилкою і p95 затримки 12 секунд, а в пікові двадцять хвилин частка відмов сягала 15%: люди йшли, не дочекавшись відповіді.
Що виставили на вході
Обмеження частоти зробили дворівневим: token bucket на користувача з правом на короткий сплеск і ковзне вікно на 60 секунд для згладжування. Зверху — добова квота токенів за кожним тарифом і пріоритетна черга для платних звернень.
Загальний запобіжник на провайдера розмикається при зростанні помилок і не дає добити його повторами.
Повторні спроби перевели на експоненційну затримку з розкидом, а ідентичні промпти протягом хвилини стали віддаватися з кешу — це зняло частину навантаження, яку раніше створювали самі користувачі.
Метрики після
- Відмови: 7,8% → 0,4% від усіх запитів.
- Затримка p95: 12 секунд → 2,6 секунди; сплеск до 60 запитів за секунду проходить без деградації.
- Частка відповідей з кешу в піку: 22%.
- Розбір накопиченої черги після збою провайдера — 90 секунд замість ручного перезаливання.
Квоти більше не роняють запит мовчки: при вичерпанні ліміту система показує розрахунковий час очікування. Витрата токенів стала планованою за тарифами, а навантаження на провайдера — передбачуваним.
Що робити, якщо AI-шлюз уже впирається в стелю?
Першим ділом — замір у реальному часі, а не розбір логів тижневої давності. На працюючому сервісі вмикаємо збір метрик: частка відмов і повторних спроб, розподіл запитів за ключами й моделями, час відповіді на 95-му процентилі, глибина черги.
Обмеження швидкості запитів і квоти за токенами поки не вмикаємо — спочатку потрібно побачити, хто саме створює навантаження і де вузьке місце.
Далі рахуємо тіньові пороги. Правило застосовується до кожного запиту подумки: у журнал іде вердикт, що було б відхилено за такої квоти, але сам запит проходить.
Поріг підбирається за реальним трафіком, і відразу видно ціну помилки — скількох сумлінних клієнтів зачепило б обмеження.
Увімкнення робимо поетапним. Правило спочатку діє на одному ключі або на невеликій частці трафіку, потім частка зростає — у кожного кроку свій критерій переходу. Раніше за інших закриваємо рідкісні, але найдорожчі виклики, і тільки потім загальний потік.
Відкат налаштувань живе в конфігурації, а не в коді: профіль порогів змінюється однією правкою і повертається до попереднього за секунди, без перезапуску й викочування нової версії. Плюс автоматичний відкат — якщо частка відмов виходить вище базової, правило знімається саме.
Сервіс не зупиняється на жодному з кроків. У замовника залишається журнал: який поріг діяв, скільки запитів зачепив, коли його змінювали — на цих даних будується наступна ітерація.
Часті технічні сумніви щодо лімітів і квот
Обмеження частоти запитів і квоти токенів вводять не заради заборон: їхнє завдання — щоб сплеск від одного клієнта або зациклений виклик не з'їдали ємність у решти. Правила описуються декларативно, поруч зі шлюзом, і бізнес-логіка застосунків залишається незмінною.
Нижче — заперечення, які найчастіше підіймають на погодженні схеми: вони про поведінку реальних користувачів і про обсяг правок у коді.
Клієнти помітять, що їх почали обмежувати?
Поріг ставлять вище пікового навантаження застосунку, тому звичайний користувач його не бачить: спрацьовує тільки на аномалії — зацикленому запиті або парсері. У відповіді клієнт отримує час повтору, а не тиху помилку.
Чи можна задати різні правила для команд і продуктів?
Правила вішаються на ключ доступу, а не на сервіс загалом: у внутрішніх команд, партнерських інтеграцій і зовнішнього застосунку пороги різняться. Квота токенів рахується окремо від частоти запитів.
Ліміти легко обійти?
Лічильники живуть на боці сервісу, а не в клієнті, тому правка коду застосунку на них не впливає. Ключі видаються й відкликаються централізовано, аномалії за одним ключем видно в метриках.
Чи доведеться переписувати код застосунку?
Обов'язкового переписування немає: застосунок звертається за тією самою адресою, змінюється лише обробка відповіді про перевищення. За стандартних повторів правка зводиться до кількох рядків, її вносимо в складі робіт.
Обговоримо ваше навантаження — повернемося з оцінкою та планом
Щоб виставити ліміти за розрахунком, а не на око, досить кількох вихідних даних — зазвичай вони вже є в логах і в статистиці провайдера моделі. Зберемо картину й повернемося з цифрами щодо квот, строків і меж робіт.
- Профіль навантаження: запитів за секунду в піку й у середньому, розподіл за маршрутами API і за клієнтами.
- Витрата токенів: медіана й 95-й перцентиль на запит і на відповідь, частка довгих контекстів.
- Ключі й доступи: за чим рахуємо квоту — ключ, акаунт, команда; як вони видаються й відкликаються.
- Поведінка при відмовах: чи є повторні відправлення, пауза між ними, скільки трафіку повертається після коду 429.
- Що вже на вході: шлюз, проксі, балансувальник, де лежать лічильники — у пам'яті окремого вузла чи в спільному сховищі.
- Пріоритети: які сценарії не можна роняти, які допустимо затримати в черзі.
Далі готуємо план: ліміти за запитами й за токенами, розміри вікна й обробку сплесків, окремі пули для інтерактивних і фонових завдань, поведінку при вичерпанні квоти — відмова із зазначенням часу очікування, черга або м'яка деградація.
Повертаємо конфігурації шлюзу, карту лімітів за ключами, порядок викочування зі зворотним відкатом, оцінку строків за етапами й зони відповідальності: що робимо ми, що залишається на вашому боці.
Опишіть завдання і надішліть те, що є за навантаженням, — повернемося з оцінкою та планом.







