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

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

Концепции маршрутизации

Эта страница объясняет, как маршрутизатор Dynamo оценивает worker-узлы, выбирает целевой узел и встраивается в путь запроса. О CLI-флагах и параметрах настройки см. Конфигурация и настройка.

Маршрутизация KV cache

Маршрутизация по KV cache оптимизирует инференс больших языковых моделей, направляя запросы на worker-узлы с наиболее релевантными кешированными данными. За счет максимального повторного использования кеша она уменьшает лишние вычисления и улучшает как пропускную способность, так и задержку.

graph TD
T[Tokens] --> R[KV Aware Router]

R -.-> W1["Worker 1<br/>Cached: 2 blocks<br/>Prefill: 8 blks<br/>Decode: 10 blks"]
R ==>|Selected| W2["Worker 2<br/>Cached: 5 blocks<br/>Prefill: 5 blks<br/>Decode: 5 blks"]
R -.-> W3["Worker 3<br/>Cached: 8 blocks<br/>Prefill: 2 blks<br/>Decode: 9 blks"]

style T fill:#fff3e0,stroke:#333,color:#333
style R fill:#2e8b57,stroke:#333,color:#fff
style W1 fill:#f3e5f5,stroke:#333,color:#333
style W2 fill:#c8e6c9,stroke:#333,color:#333
style W3 fill:#f3e5f5,stroke:#333,color:#333

linkStyle 0,1,2,3 stroke:#8b4513,stroke-width:2px

Повторное использование KV-кеша усложняет балансировку нагрузки при обслуживании LLM. Хотя оно может заметно снизить вычислительные затраты, стратегии маршрутизации, которые игнорируют состояние KV у конкретных worker-узлов, могут приводить к:

  • Потере возможностей повторного использования кеша из-за неоптимального выбора worker-узла
  • Снижению пропускной способности системы из-за неравномерного распределения запросов между worker-узлами

Маршрутизатор использует функцию стоимости, которая учитывает и стоимость prefill (зависящую от кешированных блоков), и нагрузку decode, чтобы принимать оптимальные решения о маршрутизации.

Расчёт стоимости

  1. Блоки prefill: Рассчитываются как активная нагрузка на стороне prompt плюс входные токены входящего запроса, деленные на размер блока. Система обновляет активную prompt-нагрузку, когда первый выходной токен сигнализирует о завершении prefill.
  2. Блоки decode: Оцениваются на основе входных токенов запроса и активных последовательностей каждого worker-узла. Значение обновляется, когда запросы завершаются и их блоки освобождаются.
  3. Кредиты перекрытия: Попадания в device-local, host, disk и shared-cache уменьшают prefill-нагрузку на стороне prompt до применения итогового масштаба prefill.
  4. Формула стоимости:
adjusted_prefill_blocks = max(
prefill_blocks
- overlap_score_credit * device_overlap_blocks
- host_cache_hit_weight * host_overlap_blocks
- disk_cache_hit_weight * disk_overlap_blocks
- shared_cache_multiplier * shared_beyond_blocks,
0,
)
cost = prefill_load_scale * adjusted_prefill_blocks + decode_blocks

Меньшая стоимость означает лучший выбор маршрутизации. overlap_score_credit — это множитель кредита за локальное на устройстве перекрытие префикса, от 0.0 до 1.0. Более высокие значения благоприятствуют повторному использованию кеша (улучшая TTFT), тогда как более низкие значения приоритетно выравнивают нагрузку (улучшая ITL). prefill_load_scale управляет весом скорректированной нагрузки на стороне prompt относительно decode blocks.

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

Параметры prefill_blocks и decode_blocks включают прогнозируемую нагрузку для нового запроса плюс активную нагрузку, уже назначенную каждому worker-узлу.

Моделирование нагрузки prefill

Для нагрузки prefill маршрутизатор сначала оценивает некешированную работу prompt для каждого кандидата:

effective_isl = input_tokens - cached_tokens

По умолчанию эта эффективная нагрузка prefill учитывается в полном объеме, пока первый выходной токен не обозначит завершение prefill. При --router-prefill-load-model aic маршрутизатор также запрашивает у AIC ожидаемую длительность prefill, используя effective ISL и длину кешированного префикса. Затем трекер активной нагрузки постепенно уменьшает вклад самого старого активного prefill-запроса на каждом worker-узле на протяжении предсказанной длительности. Это меняет только учет нагрузки на стороне маршрутизатора; выполнение на backend не меняется.

Моделирование нагрузки decode

Для нагрузки decode маршрутизатор отслеживает активные KV-блоки, назначенные каждому worker-узлу. По умолчанию это включает блоки на стороне prompt, уже назначенные активным запросам, и освобождает их по завершении каждого запроса.

Когда включен --router-track-output-blocks, маршрутизатор также добавляет заглушки выходных блоков по мере того, как генерация пересекает границы блоков. Если запрос содержит nvext.agent_hints.osl, этим выходным блокам назначается дробный вес в зависимости от прогресса к ожидаемой длине вывода. Такой proxy для ожидаемого OSL позволяет запросам, близким к завершению, вносить меньший вклад в будущую нагрузку decode. Без ожидаемого OSL отслеживаемые выходные блоки учитываются с полным весом до завершения запроса.

О флагах, включающих эти модели, см. Конфигурация и настройка.

Выбор worker-узла

Маршрутизатор выбирает worker-узел с наименьшей стоимостью. Когда router_temperature задан ненулевым значением, маршрутизатор использует softmax-выборку по нормализованным логитам стоимости, чтобы добавить случайность в выбор, что может помочь распределить нагрузку.

Перед оценкой маршрутизатор фильтрует кандидатов по allow-list запроса, точным привязкам, границам DP-rank, обязательным taints и состоянию перегрузки по busy-threshold. Об этих жестких правилах допустимости см. Фильтрация маршрутизатора.

Пример расчета при overlap_score_credit = 1.0:

  • Worker 1: raw prefill 10 blocks, device overlap 2 blocks, decode 10 blocks => cost = 8 + 10 = 18
  • Worker 2: raw prefill 10 blocks, device overlap 5 blocks, decode 5 blocks => cost = 5 + 5 = 10 (selected - lowest cost)
  • Worker 3: raw prefill 10 blocks, device overlap 8 blocks, decode 9 blocks => cost = 2 + 9 = 11

Использование маршрутизатора KV cache

Чтобы включить маршрутизацию с учетом KV cache, запустите frontend-узел так:

python -m dynamo.frontend --router-mode kv

Когда KV-блоки создаются или удаляются, движок уведомляет маршрутизатор Dynamo, который затем определяет worker-узел с наилучшим совпадением блоков и направляет трафик соответствующим образом.

Чтобы оценить пользу KV-aware маршрутизации, сравните производительность своей нагрузки при --router-mode random|round-robin и при KV-aware маршрутизации.

Подробные CLI-аргументы и расширенные параметры конфигурации см. в Конфигурация и настройка.

Базовая маршрутизация

Dynamo поддерживает несколько стратегий маршрутизации при отправке запросов от одного компонента к конечной точке другого компонента.

Сначала создайте клиент, привязанный к конечной точке компонента. Здесь мы получаем клиент, привязанный к конечной точке generate компонента VllmWorker.

client = runtime.endpoint("dynamo.VllmWorker.generate").client()

Затем вы можете использовать стандартные методы маршрутизации, предоставляемые классом клиента, чтобы отправлять запросы компоненту VllmWorker.

  • Случайная маршрутизация: Стратегия по умолчанию, доступна через client.generate() или client.random()
  • Маршрутизация round-robin: Циклически перебирает доступные worker-узлы через client.round_robin()
  • Прямая маршрутизация: Явно нацеливается на конкретный worker через client.direct(input, component_id)
  • Маршрутизация по минимальной нагрузке: Направляет на worker-узел с наименьшим числом активных соединений через --router-mode least-loaded
  • Взвешенная маршрутизация с учетом устройства: Маршрутизирует с учетом бюджета отношения CPU/non-CPU плюс выбор least-loaded внутри выбранной группы устройств через --router-mode device-aware-weighted Маршрутизация KV cache использует прямую маршрутизацию со специальным алгоритмом выбора worker-узла.

Для бенчмаркинга производительности KV-маршрутизатора см. Руководство по A/B-бенчмаркингу KV Router. Для собственной логики маршрутизации и продвинутых шаблонов см. Шаблоны маршрутизации.

Взвешенная маршрутизация с учетом устройства

device-aware-weighted предназначен для гетерогенных флотилий, где CPU- и non-CPU worker-узлы разделяют один и тот же endpoint. Вместо сравнения сырых счетчиков in-flight маршрутизатор сравнивает нормализованную по возможностям нагрузку между группами CPU и non-CPU, а затем выбирает наименее загруженный worker-узел внутри выигравшей группы.

normalized_load = total_inflight(group) / (instance_count(group) x throughput_weight)

Вес пропускной способности равен 1 для CPU worker-узлов и DYN_ENCODER_CUDA_TO_CPU_RATIO для non-CPU worker-узлов. Это позволяет маршрутизатору распределять трафик пропорционально возможностям устройств, а не постоянно игнорировать более медленные устройства.

Когда присутствует только один класс устройств, поведение сводится к стандартной маршрутизации least-loaded.