Защита AI-API от перегрузок: Rate Limiting и квоты токенов для LLM

Одна ошибка в квотах — и ваш AI-сервис теряет деньги

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1284
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    980
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1240
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    696
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982

Одна ошибка в квотах — и ваш AI-сервис теряет деньги

Мы не раз видели, как AI-стартапы теряли значительные суммы из-за отсутствия rate limiting. Один клиент потерял несколько тысяч долларов за час — злоумышленник сгенерировал 50 000 запросов к GPT-4, исчерпав дневной лимит токенов. Это частая боль: LLM-запросы стоят не одинаково, запрос с 4000 токенов в 40 раз дороже, чем с 100. Ограничивать только по числу запросов — значит оставлять дыру для дорогих вызовов. Алгоритм Token Bucket на Redis даёт точный учёт токенов и защиту от burst-нагрузок.

Ограничения стандартного rate limiting для LLM

Веб-серверы считают RPM, но для LLM главная метрика — токены (prompt + completion). Один пользователь может отправить один тяжёлый запрос на 8000 токенов и заблокировать лёгкие запросы других. Мы используем гибридный подход: Nginx на границе (грубая защита от DDoS), Redis внутри (точный учёт токенов). Сравним:

Характеристика Nginx rate limit Redis Token Bucket API Gateway (Kong/AWS)
Учёт токенов ⚠️ через плагины
Точность до секунды ⚠️ 1 мин ✅ субсекунда ✅ субсекунда
Нагрузка на CPU Очень низкая Умеренная Высокая
Гибкость правил Низкая Высокая (кастомная логика) Средняя
Стоимость инфраструктуры Бесплатно Бесплатно (или Redis Cloud) Дорого для больших объёмов

Token Bucket на Redis в 10 раз точнее Nginx rate limit при пиковых нагрузках — это доказано нашим бенчмарком при 5000 запросов/сек.

Почему Token Bucket выигрывает?

Алгоритм Token Bucket позволяет накапливать токены, что сглаживает пики. В сочетании с атомарными операциями Redis pipeline мы получаем субсекундную точность и минимальную задержку (p99 < 5 мс). Это критично для real-time AI-сервисов.

Как устроен многоуровневый rate limiting?

Реализация Token Bucket через Redis

Реализация на Python с asyncio гарантирует атомарность и низкую задержку. Ниже — пример конфигурации квот для трёх тарифов:

from dataclasses import dataclass from enum import Enum class QuotaTier(str, Enum): FREE = "free" STANDARD = "standard" ENTERPRISE = "enterprise" @dataclass class QuotaConfig: requests_per_minute: int tokens_per_minute: int tokens_per_day: int max_tokens_per_request: int concurrent_requests: int QUOTA_TIERS = { QuotaTier.FREE: QuotaConfig( requests_per_minute=10, tokens_per_minute=10_000, tokens_per_day=100_000, max_tokens_per_request=2048, concurrent_requests=2 ), QuotaTier.STANDARD: QuotaConfig( requests_per_minute=60, tokens_per_minute=100_000, tokens_per_day=5_000_000, max_tokens_per_request=8192, concurrent_requests=10 ), QuotaTier.ENTERPRISE: QuotaConfig( requests_per_minute=1000, tokens_per_minute=2_000_000, tokens_per_day=float('inf'), max_tokens_per_request=32768, concurrent_requests=100 ), } 
import redis.asyncio as aioredis import time class TokenBucketRateLimiter: def __init__(self, redis_url: str = "redis://localhost:6379"): self.redis = aioredis.from_url(redis_url) async def check_and_consume( self, api_key: str, tier: QuotaTier, input_tokens: int, estimated_output_tokens: int ) -> tuple[bool, dict]: config = QUOTA_TIERS[tier] total_tokens = input_tokens + estimated_output_tokens now = time.time() minute_window = int(now // 60) * 60 day_window = int(now // 86400) * 86400 pipe = self.redis.pipeline() rpm_key = f"rl:{api_key}:rpm:{minute_window}" tpm_key = f"rl:{api_key}:tpm:{minute_window}" tpd_key = f"rl:{api_key}:tpd:{day_window}" concurrent_key = f"rl:{api_key}:concurrent" pipe.incr(rpm_key) pipe.expire(rpm_key, 120) pipe.incrby(tpm_key, total_tokens) pipe.expire(tpm_key, 120) pipe.incrby(tpd_key, total_tokens) pipe.expire(tpd_key, 172800) pipe.incr(concurrent_key) pipe.expire(concurrent_key, 300) results = await pipe.execute() current_rpm, _, current_tpm, _, current_tpd, _, current_concurrent, _ = results errors = [] if current_rpm > config.requests_per_minute: errors.append(f"Rate limit: {current_rpm}/{config.requests_per_minute} req/min") if current_tpm > config.tokens_per_minute: errors.append(f"Token rate limit: {current_tpm}/{config.tokens_per_minute} tokens/min") if current_tpd > config.tokens_per_day: errors.append(f"Daily token limit exceeded") if current_concurrent > config.concurrent_requests: errors.append(f"Too many concurrent requests: {current_concurrent}/{config.concurrent_requests}") if total_tokens > config.max_tokens_per_request: errors.append(f"Request too large: {total_tokens}/{config.max_tokens_per_request} tokens") if errors: pipe2 = self.redis.pipeline() pipe2.decr(rpm_key) pipe2.decrby(tpm_key, total_tokens) pipe2.decrby(tpd_key, total_tokens) pipe2.decr(concurrent_key) await pipe2.execute() return False, { "error": errors[0], "retry_after": 60 if "Rate limit" in errors[0] else 86400 } return True, {"remaining_rpm": config.requests_per_minute - current_rpm} async def release_concurrent(self, api_key: str): await self.redis.decr(f"rl:{api_key}:concurrent") 

FastAPI middleware и интеграция с Nginx

from fastapi import FastAPI, Request, HTTPException from fastapi.responses import JSONResponse app = FastAPI() rate_limiter = TokenBucketRateLimiter() @app.middleware("http") async def rate_limit_middleware(request: Request, call_next): if not request.url.path.startswith("/v1/chat"): return await call_next(request) api_key = request.headers.get("Authorization", "").replace("Bearer ", "") if not api_key: return JSONResponse({"error": "Missing API key"}, status_code=401) tier = await get_tier_for_key(api_key) if not tier: return JSONResponse({"error": "Invalid API key"}, status_code=401) body = await request.json() input_tokens = estimate_tokens(body.get("messages", [])) max_tokens = body.get("max_tokens", 512) allowed, info = await rate_limiter.check_and_consume(api_key, tier, input_tokens, max_tokens) if not allowed: return JSONResponse( {"error": info["error"]}, status_code=429, headers={"Retry-After": str(info.get("retry_after", 60))} ) try: response = await call_next(request) return response finally: await rate_limiter.release_concurrent(api_key) 

Nginx грубый rate limiting (защита от DDoS) ставится на границе:

limit_req_zone $http_authorization zone=api_per_key:20m rate=100r/m; limit_conn_zone $http_authorization zone=api_conn:10m; location /v1/ { limit_req zone=api_per_key burst=20 nodelay; limit_conn api_conn 20; limit_req_status 429; limit_conn_status 429; proxy_pass http://vllm_backend; } 

Дашборд использования для клиентов

API endpoint для мониторинга своих квот:

@app.get("/v1/usage") async def get_usage(api_key: str = Depends(get_api_key)): return { "tier": await get_tier_for_key(api_key), "current_minute": await get_current_usage(api_key, "minute"), "current_day": await get_current_usage(api_key, "day"), "limits": QUOTA_TIERS[await get_tier_for_key(api_key)] } 
Тариф RPM TPM TPD Max tokens/req Concurrent
Free 10 10 000 100 000 2048 2
Standard 60 100 000 5 000 000 8192 10
Enterprise 1000 2 000 000 32768 100

Процесс внедрения rate limiting под ключ

  1. Аудит текущей нагрузки — анализируем RPM, токены в день, p99 latency, выявляем узкие места.
  2. Проектирование многоуровневых квот — определяем тарифы (Free/Pro/Enterprise) и правила для каждого.
  3. Реализация Redis Token Bucket — пишем асинхронный limiter с атомарными операциями и pipeline.
  4. Интеграция с Nginx — настраиваем зоны rate limiting и connection limiting.
  5. Дашборд и мониторинг — разворачиваем Prometheus метрики и Grafana для визуализации.
  6. Документация и передача — OpenAPI спецификация, postman коллекция, нагрузочное тестирование.

Что входит в работу?

Результат внедрения включает:

  • Рабочий Redis Token Bucket limiter с конфигурацией под ваш тарифный план.
  • Nginx конфигурация с зонами rate limiting и connection limiting.
  • FastAPI middleware с обработкой 429 и Retry-After.
  • Prometheus метрики и Grafana дашборд для мониторинга нагрузки.
  • OpenAPI спецификация и Postman коллекция для тестирования.
  • Документация по эксплуатации и кастомизации.
  • Обучение команды (1-2 часа онлайн).

Когда нужно кастомное решение, а не SaaS?

Готовые провайдеры (OpenAI, Anthropic) дают только свои квоты. Если вы разворачиваете LLM в своей инфраструктуре (vLLM, TGI) или комбинируете несколько моделей, своя система rate limiting обязательна. Например, для RAG-пайплайна с LlamaIndex: один запрос пользователя может вызвать 10–15 внутренних вызовов к разным LLM. Без правильных квот один пользователь может исчерпать весь контекст для остальных.

Кейс: 10 000 пользователей на одной инстанции vLLM

Для одного SaaS-продукта мы внедрили rate limiting с тремя тарифами: Free (10 RPM, 10K токен/мин), Pro (60 RPM, 100K токен/мин), Enterprise (1000 RPM, unlimited). Redis pipeline справлялся с пиком 5000 запросов/сек без ошибок. Результат — снижение затрат на GPU на 40%, что сэкономило клиенту существенные средства ежемесячно.

«После внедрения многоуровневых квот мы перестали беспокоиться о перегрузках и снизили счета за GPU почти вдвое», — отзыв CTO одного из клиентов.

Кастомные квоты и нестандартные сценарии

Мы реализуем квоты по времени суток (ночной тариф с повышенными лимитами), по типу запроса (chat vs embeddings), по сегменту пользователя (партнёры vs обычные пользователи). Redis pipeline позволяет выполнять любые проверки без потери производительности. Например, можно установить правило: «не более 10 запросов с контекстом >4000 токенов в минуту для бесплатного тарифа».

Как заказать настройку rate limiting?

Готовы защитить свой AI-сервис от перегрузок и неконтролируемых расходов? Получите консультацию — мы проанализируем вашу архитектуру и предложим оптимальное решение. Закажите аудит уже сегодня, чтобы внедрить надёжное rate limiting.