Перейти к основному содержимому

Чтобы получить чистое Markdown-содержимое этой страницы, добавьте .md к этому URL. Полный индекс документации см. на https://docs.nvidia.com/dynamo/llms.txt. Полный контент, включая справочник API и примеры SDK, см. на https://docs.nvidia.com/dynamo/llms-full.txt.

Отклонение запросов

В этом документе описано, как в Dynamo реализовано отклонение запросов, чтобы предотвращать перегрузку системы и сохранять стабильность сервиса при высокой нагрузке.

Обзор

Отклонение запросов (также известное как load shedding) — это механизм отказоустойчивости, который заранее отклоняет новые запросы, когда воркеры перегружены. Это предотвращает:

  • Каскадные сбои из-за исчерпания ресурсов
  • Ухудшение задержки для всех запросов
  • Ситуации нехватки памяти на GPU-воркерах

Когда все воркеры превышают настроенные пороги занятости, новые запросы получают ответ HTTP 503 (Service Unavailable), который сообщает клиентам, что нужно повторить попытку позже.

Архитектура

┌─────────────────┐
│ Worker Monitor │
│ (Background) │
└────────┬────────┘
│ Updates busy list

┌──────────┐ ┌──────────┐ ┌─────────────────────┐ ┌──────────┐
│ Client │───▶│ Frontend │───▶│ Push Router │───▶│ Worker │
└──────────┘ └──────────┘ │ (checks busy list) │ └──────────┘
└─────────────────────┘

│ If all workers busy

┌─────────────────────┐
│ HTTP 503 Error │
│ "All workers busy" │
└─────────────────────┘

Конфигурация

Аргументы frontend

Настройте пороги занятости при запуске frontend. Для активации порогов требуется --admission-control token-capacity; значение по умолчанию (none) оставляет их отключенными.

python -m dynamo.frontend \
--admission-control token-capacity \
--active-decode-blocks-threshold 0.85 \
--active-prefill-tokens-threshold 10000
АргументТипОписание
--active-decode-blocks-thresholdfloat (0.0-1.0)Порог утилизации блоков KV cache
--active-prefill-tokens-thresholdintПорог количества prefill tokens
--active-prefill-tokens-threshold-fracfloatПорог prefill tokens как доля от max_num_batched_tokens
--admission-controltoken-capacity | noneРежим admission control. token-capacity применяет указанные выше пороги занятости; none (значение по умолчанию) очищает их, при этом очередь router остается под управлением --router-queue-threshold. Чтобы включить admission для занятых воркеров, нужно передать --admission-control token-capacity

Динамическая настройка через API

Пороги можно менять во время выполнения через endpoint /busy_threshold:

Задать пороги

curl -X POST http://localhost:8000/busy_threshold \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-0.6B",
"active_decode_blocks_threshold": 0.85,
"active_prefill_tokens_threshold": 10000
}'

Получить текущие пороги

curl http://localhost:8000/busy_threshold

Ответ:

{
"thresholds": [
{
"model": "Qwen/Qwen3-0.6B",
"active_decode_blocks_threshold": 0.85,
"active_prefill_tokens_threshold": 10000
}
]
}

Логика определения занятости

Воркеры помечаются как "busy" на основе системы из двух порогов. Воркер считается занятым, когда превышен любой из порогов.

Порог блоков KV Cache

Отслеживает процент используемых блоков KV cache:

busy = active_decode_blocks / kv_total_blocks > threshold

Пример: при active_decode_blocks_threshold=0.85 воркер, использующий 87% блоков KV cache, помечается как занятый.

Порог prefill tokens

Отслеживает количество tokens, которые сейчас находятся в prefill:

busy = active_prefill_tokens > threshold

Пример: при active_prefill_tokens_threshold=10000 воркер, выполняющий prefill для 12 000 tokens, помечается как занятый.

Агрегация data-parallel ranks

Для воркеров с несколькими data-parallel ranks (tensor parallelism) воркер помечается как занятый только если заняты ВСЕ ranks:

def is_busy(worker):
return all(rank.is_busy() for rank in worker.dp_ranks)

Это предотвращает ложные срабатывания, когда временно загружены только некоторые ranks.

Мониторинг нагрузки воркера

KvWorkerMonitor работает как фоновая задача, которая:

  1. Подписывается на события метрик KV cache от воркеров
  2. Поддерживает состояние нагрузки для каждого экземпляра воркера
  3. Пересчитывает занятые экземпляры при изменении метрик
  4. Обновляет router текущим списком занятых экземпляров

Собираемые метрики

Воркеры публикуют следующие метрики для мониторинга:

МетрикаОписание
active_decode_blocksКоличество блоков KV cache, используемых сейчас
kv_total_blocksОбщее количество доступных блоков KV cache
active_prefill_tokensКоличество tokens, которые сейчас находятся в prefill

Поведение при отклонении

Поток обработки запроса

  1. Запрос поступает во frontend
  2. Push router проверяет, настроен ли порог занятости
  3. Если порог настроен, router получает список свободных (не занятых) экземпляров
  4. Если свободных экземпляров нет (но экземпляры зарегистрированы):
    • Запрос отклоняется с PipelineError::ServiceOverloaded
    • Клиенту возвращается ответ HTTP 503

Ответ с ошибкой

Когда запросы отклоняются, клиенты получают:

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

{
"message": "Service temporarily unavailable: All workers are busy, please retry later",
"type": "service_unavailable",
"code": 503
}

Стратегия повторных попыток на клиенте

Клиенты должны реализовать экспоненциальную задержку при получении ответов 503:

import time
import random

def send_with_retry(request, max_retries=5):
for attempt in range(max_retries):
response = send_request(request)
if response.status_code != 503:
return response

# Exponential backoff with jitter
wait_time = min(60, (2 ** attempt) + random.uniform(0, 1))
time.sleep(wait_time)

raise Exception("Max retries exceeded")

Мониторинг

Метрики Prometheus

Отслеживайте поведение отклонения запросов с помощью следующих метрик:

  • dynamo_frontend_model_rejection_total: счетчик, отслеживающий общее количество запросов, отклоненных из-за исчерпания ресурсов
    • Метки:
      • model: имя обслуживаемой модели
      • endpoint: endpoint API, который получил запрос (например, chat_completions, completions, embeddings)
    • Эта метрика увеличивается, когда router возвращает ошибку ResourceExhausted, потому что все воркеры заняты. Отклоненный запрос передается клиенту как ответ HTTP 503.

Пример вывода метрик:

dynamo_frontend_model_rejection_total{endpoint="chat_completions",model="Qwen/Qwen3-0.6B"} 32
dynamo_frontend_model_rejection_total{endpoint="completions",model="Qwen/Qwen3-0.6B"} 5

Endpoint: доступен в HTTP-сервисе frontend по адресу /metrics.

Настройка порогов

Консервативные настройки (ориентация на задержку)

Для приложений, где приоритетом является низкая задержка:

--active-decode-blocks-threshold 0.70
--active-prefill-tokens-threshold 5000
  • Отклоняют раньше, до полной загрузки воркеров
  • Поддерживают меньшую глубину очередей
  • Улучшают хвостовые задержки

Агрессивные настройки (ориентация на пропускную способность)

Для приложений, где приоритетом является пропускная способность:

--active-decode-blocks-threshold 0.95
--active-prefill-tokens-threshold 20000
  • Позволяют повысить утилизацию воркеров
  • Могут увеличить вариативность задержки
  • Улучшают общую пропускную способность

Отключено (без отклонения)

Чтобы полностью отключить отклонение запросов:

# Simply don't set the threshold arguments
python -m dynamo.frontend

Если пороги не настроены, принимаются все запросы независимо от нагрузки воркеров.

Рекомендации

1. Начните с консервативных значений, затем настраивайте

Начните с консервативных порогов и увеличивайте их на основе наблюдаемого поведения:

# Start here
--active-decode-blocks-threshold 0.75

# Increase if rejection rate is too high
--active-decode-blocks-threshold 0.85

2. Проведите мониторинг перед включением

Понаблюдайте за паттернами нагрузки воркера перед настройкой порогов:

# Watch KV cache utilization
watch -n 1 'curl -s localhost:8000/metrics | grep kv_blocks'

3. Используйте оба порога для disaggregated serving

В disaggregated deployments:

  • Используйте active_prefill_tokens_threshold для prefill-воркеров
  • Используйте active_decode_blocks_threshold для decode-воркеров

4. Согласуйте с автомасштабированием

Если используется Kubernetes HPA, убедитесь, что пороги отклонения срабатывают до автомасштабирования:

# HPA triggers at 70% utilization
# Rejection at 85% provides buffer
--active-decode-blocks-threshold 0.85

Связанная документация