Лимиты запросов: как проектировать нагрузку и не упираться в потолок
Первое столкновение с лимитами обычно выглядит одинаково: всё работало, вы запустили обработку тысячи записей, и половина запросов вернулась с отказом. Разберёмся, как устроены ограничения и как строить систему, которая в них не упирается.
Лимит — это две величины, а не одна
Провайдеры ограничивают одновременно количество запросов в минуту и количество токенов в минуту. Это разные потолки, и упираетесь вы обычно в тот, о котором не думали.
Практический вывод: если вы работаете с длинным контекстом, считать нужно токены. Двадцать запросов по тридцать тысяч токенов исчерпают минутный лимит быстрее, чем тысяча коротких обращений.
Повторы с растущей паузой
Отказ по лимиту — временная ошибка, она лечится ожиданием. Но повторять сразу бессмысленно: вы попадёте в тот же потолок.
Рабочая схема: первая пауза около секунды, каждая следующая вдвое длиннее, к каждой добавляется случайная добавка. Число попыток ограничено четырьмя-пятью — дальше проблема уже не во временном всплеске.
Случайная добавка важнее, чем кажется. Без неё все ваши процессы, получившие отказ одновременно, повторят запрос тоже одновременно и получат отказ снова.
Что повторять нельзя
Разбирать код ответа обязательно. Повтор помогает только при отказе по лимиту и при сбое на стороне провайдера.
| Ситуация | Повторять |
|---|---|
| Превышен лимит | Да, с растущей паузой |
| Сбой провайдера | Да, осторожно |
| Неверный ключ | Нет, чинить конфигурацию |
| Неверный запрос | Нет, чинить код |
| Превышено окно контекста | Нет, сокращать запрос |
Код, который повторяет всё подряд, превращает разовую ошибку конфигурации в пять одинаковых отказов и лишние записи в журнале.
Ограничение параллельности на своей стороне
Самый надёжный способ не упираться в лимит — не отправлять больше, чем разрешено. Для этого перед вызовом ставится ограничитель: сколько запросов одновременно и сколько в минуту.
Такой ограничитель полезнее повторов, потому что работает до отказа, а не после. Значение подбирается по документации провайдера с запасом процентов в двадцать.
Если обработчиков несколько, ограничитель должен быть общим. Три процесса, каждый со своим лимитом, вместе дают тройное превышение.
Когда отказы идут постоянно
Повторы помогают при всплесках. Если отказы приходят ровным потоком, значит, ваша нормальная нагрузка выше разрешённой, и лечится это иначе.
- Снизить параллельность и растянуть обработку во времени.
- Перенести фоновые задачи на ночь, когда нет пользовательской нагрузки.
- Объединить мелкие однотипные запросы в пачки.
- Запросить повышение лимита у поставщика доступа.
- Разнести нагрузку по разным ключам, если это допустимо условиями.
Прежде чем просить повышения лимита, посмотрите, что именно его выбирает. Часто оказывается, что восемьдесят процентов запросов — это ночной пересчёт, который спокойно ждёт до утра.
Разделяйте потоки
Пользовательские запросы и фоновая обработка не должны конкурировать за один и тот же лимит. Иначе ночной отчёт способен положить чат на сайте.
Простейшее разделение — отдельная очередь с низким приоритетом для фоновых задач и жёсткое ограничение её скорости. Пользовательский поток при этом получает то, что осталось, и всегда проходит первым.
Как измерить свой реальный потолок
Значения из документации — верхняя граница, а не гарантия. Полезно знать, где находитесь вы.
Способ простой: возьмите тестовый ключ и постепенно наращивайте нагрузку, фиксируя, при какой скорости появляются первые отказы. Пятнадцати минут достаточно, чтобы получить рабочее число.
Замеряйте отдельно два сценария. Короткие запросы покажут потолок по числу обращений, длинные — по токенам. Числа будут разными, и планировать нужно по тому, которое ближе к вашей реальной нагрузке.
Полученное значение занесите в конфигурацию ограничителя с запасом процентов в двадцать. Запас нужен потому, что лимиты не всегда постоянны: провайдер может менять их, а часть пропускной способности иногда съедают соседние процессы.
Очередь вместо отказа
Когда ограничитель срабатывает, у вас два варианта: вернуть пользователю ошибку или поставить запрос в очередь.
Для фоновых задач ответ очевиден — очередь. Для пользовательских сложнее: ждать дольше нескольких секунд человек не будет.
Рабочий компромисс — короткая очередь с ограничением времени ожидания. Запрос ждёт до трёх секунд, и если за это время место не освободилось, пользователь получает понятное сообщение о загруженности, а не техническую ошибку.
Такая схема заметно мягче: при коротких всплесках пользователь ничего не замечает, а при длительной перегрузке получает честный ответ вместо непонятного отказа.
Что мерить
Заведите три счётчика: отправленные запросы, отказы по лимиту и среднее время ожидания в очереди. Первый показывает нагрузку, второй — насколько близко вы к потолку, третий — что чувствует пользователь.
Рост третьего при стабильных первых двух означает, что ограничитель настроен слишком строго. Рост второго — что пора менять схему, а не увеличивать число повторов.
Настроенные один раз, эти три величины экономят часы разбирательств: по ним сразу видно, в чём дело — в провайдере, в вашей нагрузке или в настройках ограничителя.