English translation is not available yet. Showing Russian content.

Как вы делаете load shedding при перегрузке LLM сервера?

Краткий тезис

Load shedding — это контролируемый сброс части входящих запросов при превышении допустимой нагрузки на LLM-сервер. Основная цель — сохранить отказоустойчивость и предсказуемое качество ответов для наиболее критичных клиентов. Стратегия строится на приоритизации трафика, пошаговой деградации некритических функций и прозрачном информировании клиентов через HTTP-статусы. Ключевые метрики — процент отброшенных запросов и время восстановления сервиса.


1. Термин: Load Shedding

Load shedding (буквально «сброс нагрузки») — это техника, при которой сервер намеренно отклоняет часть запросов, когда ресурсы (GPU, CPU, память, пропускная способность) находятся на границе исчерпания. В отличие от rate limiting (ограничение частоты запросов от одного клиента), load shedding работает на уровне общего пула запросов и применяется ситуационно — только в моменты пиковой нагрузки.

ХарактеристикаLoad SheddingRate Limiting
ЦельЗащита сервера от коллапсаЗащита от злоупотребления одного клиента
ОснованиеГлобальная загрузка (CPU/GPU/очередь)Ключ клиента (token bucket, leaky bucket)
РеакцияСброс части запросов (с приоритетом)Отклонение запросов, превысивших лимит
ДлительностьПока пик не спадетПостоянно действующий лимит

2. Причины перегрузки LLM-сервера

LLM-инференс ресурсоёмкий: генерация одного токена может занимать миллисекунды, но при batch-обработке и длинных контекстах нагрузка резко растёт. Основные сценарии перегрузки:

  • Всплеск трафика (например, после публикации нового AI-продукта).
  • Тяжёлые запросы с контекстом 32K+ токенов — они занимают GPU надолго и блокируют остальные.
  • Отказ upstream-сервисов (например, базы данных) — запросы начинают зависать и накапливаться в очереди.
  • Проблемы с автоскейлингом — новые инстансы не успевают подняться.

При перегрузке без load shedding сервер может уйти в thrashing (частые переключения контекста, OOM), что приведёт к падению всех запросов и длительному восстановлению.


3. Базовая стратегия: приоритизация запросов

Первый шаг — разделить весь трафик на классы. Типичная схема:

ПриоритетТип запросовПример
1 (высший)Premium / платныеПользователи с подпиской, критичные API
2 (средний)RegularБесплатные пользователи, обычные web-запросы
3 (низший)Batch / async / фоновыеПакетная обработка, аналитика, re-ranking

При превышении порога нагрузки (например, 80% GPU utilization) начинается selective shedding: сначала сбрасываются запросы 3-го приоритета, потом 2-го. Запросы 1-го приоритета не сбрасываются до тех пор, пока не наступит критическая черта (95%+).

Важно: приоритеты должны быть настраиваемыми через конфигурацию или runtime API. В RAG|Agentic RAG также можно ранжировать запросы по «стоимости» (ожидаемое число токенов) и SLA клиента.


4. Отказ от наименее важных (least critical first)

Это частный случай приоритизации — сброс именно тех запросов, которые принесут наименьший бизнес-ущерб. Как определить «наименее важный»:

  • По типу операции — например, re-ranking второстепенных кандидатов можно пропустить, а ответ пользователю — нет.
  • По источнику — внутренние тестовые запросы сбрасываются раньше, чем внешние клиентские.
  • По истории — для недавно зарегистрированных пользователей можно снизить приоритет (но рискованно с точки зрения UX).

В контексте Agentic RAG least critical часто означает «запросы без привязки к сессии пользователя» — например, фоновый мониторинг качества retrieval’а.


5. Возврат HTTP 503 с Retry-After: 5

Когда сервер решает отбросить запрос, он должен вернуть понятный клиенту ответ. HTTP 503 Service Unavailable — стандартный код для временной недоступности. Обязательно добавлять заголовок Retry-After, чтобы клиент знал, когда повторить попытку.

Пример ответа:

HTTP/1.1 503 Service Unavailable
Retry-After: 5
Content-Type: application/json

{
  "error": "server_overloaded",
  "message": "Сервер временно перегружен. Повторите запрос через 5 секунд."
}

Retry-After можно выставлять:

  • Фиксированное значение (например, 5 или 10 секунд) — просто, но не адаптивно.
  • Динамическое — на основе ожидаемого времени освобождения ресурсов (проверяется по длине очереди).

Важно: не все клиенты корректно обрабатывают 503 — для Agentic RAG с собственными AI-агентами нужно предусмотреть логику повторных попыток (exponential backoff).


6. Graceful Degradation (плавная деградация функций)

Вместо полного сброса запроса можно отключить некоторые «тяжёлые» или некритичные компоненты. Это называется graceful degradation. Примеры для LLM-сервера:

  • Отключить semantic caching — кеш экономит время, но его запись/чтение добавляет latency. При перегрузке можно временно пропускать кеш.
  • Отключить re-ranking — если используется двухступенчатый retrieval (sparse + dense + cross-encoder re-ranker), можно выполнять re-ranking только для premium-запросов.
  • Снизить число candidates в retrieval — например, уменьшить top_k с 20 до 5.
  • Уменьшить max_tokens генерации — ограничить длину ответа LLM.
  • Переключиться на меньшую модель — если есть каскад моделей (например, GPT-4GPT-3.5), временно отправлять все запросы на более дешёвую и быструю.

Каждая деградация должна быть измерена по влиянию на качество (faithfulness, answer relevance). Для Agentic RAG можно временно отключать инструменты (tools), которые требуют внешних вызовов (например, поиск в интернете).


7. Мониторинг и алертинг (процент отброшенных запросов)

Load shedding — это не «разовое действие», а управляемый процесс. Необходимо отслеживать:

  • Процент отброшенных запросов (% of shedded requests). Целевое значение – менее 1%, иначе страдает пользовательский опыт.
  • Среднюю latency и latency p99 при включённом shedding.
  • GPU utilization и длину очереди (queue depth).
  • Количество деградированных функций (сколько раз отключали re-ranking и т.д.).

При превышении порога (например, > 5% shedded requests или latency p99 > 10s) должен срабатывать алерт. Инструменты: Prometheus + Grafana, Datadog, Sentry.

Полезно вести лог каждого decision — какой запрос сброшен, какой приоритет, какая причина. Это помогает анализировать после инцидента.


8. Архитектурные решения: очереди, circuit breaker, rate limiting

Load shedding не работает в вакууме — его нужно встраивать в общую архитектуру.

Очереди (message queue) — все запросы проходят через буфер (например, Redis Streams, RabbitMQ). Когда очередь переполняется (превышает max queue size), начинается сброс самых старых или низкоприоритетных запросов.

Circuit Breaker — паттерн, который предотвращает каскадные отказы. Если сервис ретривалов (векторная БД) начал отвечать с ошибками, circuit breaker может быстро завершать запросы без обращения к LLM, экономя ресурсы.

Rate Limiting — дополняет load shedding: ограничивает одного клиента, но не защищает от общего пика. Желательно использовать вместе.

Пример архитектуры (псевдокод на Python с asyncio):

import asyncio
from enum import Enum

class Priority(Enum):
    PREMIUM = 1
    REGULAR = 2
    BATCH = 3

async def process_request(request, priority, server_state):
    # Проверка состояния
    if server_state.should_shed(priority):
        raise HTTPException(503, {"Retry-After": 5})
    # Graceful degradation: отключаем re-ranking если нагрузка > 90%
    if server_state.gpu_util > 90 and priority != Priority.PREMIUM:
        request.rerank = False
    # Обработка
    result = await llm_generate(request)
    return result

9. Сравнение стратегий load shedding

СтратегияПлюсыМинусы
ПриоритизацияСохраняет качество для важных клиентовНужна классификация, административные затраты
Least critical firstЭффективно при массовых запросахСложно определить «критичность» для каждого запроса
503 + Retry-AfterПростой, стандартный, обрабатывается клиентамиКлиент может уйти; нет гарантии, что повторит
Graceful degradationСохраняет сервис, жертвуя качествомСложная логика отключения, нужно следить за качеством
Очередь с автоматическим sheddingГибкий, можно настраивать правилаДополнительные компоненты, latency из-за очереди

10. Пет-проект для закрепления

Задача: Реализовать middleware для FastAPI, который добавляет load shedding с приоритизацией и graceful degradation.

Инструменты: FastAPI, Redis, httpx (для ретраев), prometheus_client.

Шаги:

  1. Создать FastAPI endpoint /v1/generate, который принимает запрос с полем priority (premium/regular/batch).
  2. Завести глобальный счётчик загрузки GPU (симулировать через random, или измерять реальный utilization через nvidia-smi).
  3. Реализовать проверки:
    • Если GPU utilization > 85% → для batch возвращать 503 с Retry-After: 5.
    • Если GPU > 90% → отключать rerank для всех запросов (установить флаг rerank=False).
    • Если GPU > 95% → сбрасывать regular, кроме premium.
  4. Добавить middleware, который логирует каждый факт shedding (причина, приоритет) в Redis-список.
  5. Экспортировать метрики через prometheus_client: shedding_total и degradations_total.
  6. Написать тест с синтетической нагрузкой (locust или aiohttp).

Ожидаемый результат:

  • При низкой нагрузке все запросы обслуживаются.
  • При повышении GPU utilization до 85% batch-запросы получают 503 и должны повторно приходить через 5 секунд.
  • При 90%+ regular-запросы также начинают сбрасываться, но premium остаются.
  • Метрики в Prometheus показывают корректное число сбросов.

11. Связь с другими вопросами

ВопросТема
408Как вы измеряете latency и throughput RAG-системы?
410Как вы реализуете rate limiting для AI-агентов?
413Как вы проектируете отказоустойчивость Agentic RAG?
415Как вы масштабируете LLM-сервер для Agentic RAG?
417Как вы реализуете graceful degradation в Agentic RAG?
420Как вы тестируете систему на устойчивость к пиковым нагрузкам?

Навигация