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

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

Руководство по развертыванию Global Planner

В этом руководстве объясняется, как развернуть GlobalPlanner и когда его использовать. GlobalPlanner - это централизованный слой выполнения масштабирования для развертываний, где несколько DGD должны делегировать масштабирование одному компоненту, независимо от того, открывают ли эти DGD отдельные endpoints или находятся за одним общим endpoint.

Впервые работаете с Planner? Перед переходом к GlobalPlanner рекомендуем начать с развертывания с одним DGD и масштабированием на основе throughput или load. Для начала см. обзор Planner и руководство по Planner.

Зачем нужен Global Planner?

Без GlobalPlanner локальный planner каждого DGD напрямую масштабирует только свое развертывание. Для изолированных развертываний это нормально, но становится неудобно, когда нужно в одном месте:

  • применять централизованную политику масштабирования для нескольких DGD
  • обеспечивать общие ограничения, например авторизацию или общий бюджет GPU
  • координировать масштабирование для развертывания с одним endpoint и несколькими пулами

GlobalPlanner решает эту задачу, становясь общим endpoint выполнения масштабирования для нескольких локальных planners.

Терминология

  • Planner: компонент dynamo.planner, который вычисляет нужное число реплик для соблюдения latency SLA. См. обзор Planner.
  • Local Planner: локальный для пула экземпляр Planner, работающий внутри одного DGD.
  • Global Planner: централизованный слой выполнения и политики, который получает запросы на масштабирование от локальных planners.
  • Single-endpoint multi-pool deployment: один model endpoint, за которым стоят несколько DGD для одной и той же модели. Этот паттерн использует и GlobalRouter, и GlobalPlanner.

Паттерны развертывания

Используйте GlobalPlanner в одном из двух паттернов:

ПаттернКогда использоватьНужен GlobalRouterФорма публичного endpoint
Несколько model endpoints или независимые DGDОтдельные DGD должны разделять централизованную политику масштабирования, например авторизацию или общий бюджет GPUНетОдин endpoint на DGD или любой другой способ экспонирования каждого DGD
Один model endpoint, несколько DGDОдна модель должна быть доступна через один публичный endpoint, но разные классы запросов должны попадать в разные DGDДаОдин общий endpoint

Паттерн 1: несколько model endpoints или независимые DGD

Используйте этот паттерн, когда у вас есть несколько DGD, часто для разных моделей, и вы хотите, чтобы они разделяли централизованную политику масштабирования без объединения в один endpoint.

Типичные примеры:

  • DGD A: disaggregated deployment qwen-0.6b со своим локальным planner
  • DGD B: disaggregated deployment qwen-32b со своим локальным planner
  • один общий GlobalPlanner, которому делегируют все локальные planners

В этом паттерне:

  • каждый DGD сохраняет свой обычный локальный planner
  • каждый локальный planner настраивается с environment: "global-planner"
  • все эти planners указывают на один и тот же global_planner_namespace
  • каждый DGD сохраняет собственный endpoint или frontend, если он нужен
  • GlobalRouter не нужен

Этот паттерн подходит, когда цель - централизованное управление масштабированием нескольких развертываний или моделей.

Паттерн 2: один model endpoint, несколько DGD

Используйте этот паттерн, когда верны все следующие условия:

  • Вам нужен один публичный endpoint для одной модели.
  • Вам нужны разные приватные пулы для разных классов запросов, например запросов с коротким ISL и длинным ISL или разных целевых значений latency.
  • Нужно, чтобы каждый пул autoscale'ился независимо.
  • Нужно централизовать маршрутизацию и выполнение масштабирования, а не открывать клиентам несколько endpoints.

Типичные примеры:

  • запросы с коротким input дешевле обрабатывать на меньшем prefill pool
  • запросам с длинным input нужен более крупный prefill pool
  • decode capacity должна масштабироваться независимо от prefill capacity

Если для одной модели нужен только один пул, используйте один Local Planner и DGD/DGDR.

Что нужно развернуть

В текущей реализации паттерн с одним endpoint собирается из нескольких ресурсов:

РесурсНазначениеТипичное содержимое
Control DGDПубличная точка входа и централизованная control planeFrontend, GlobalRouter, GlobalPlanner
Prefill pool DGD(s)Приватные пулы prefill capacityLocalRouter, prefill worker(s), Planner
Decode pool DGD(s)Приватные пулы decode capacityLocalRouter, decode worker(s), Planner
Опциональные DGDR(s)Генерация или проверка одной оптимизированной формы пула за разModel, workload, SLA, hardware inputs

Текущий workflow

Сейчас один DGDR не генерирует полную multi-pool топологию с одним endpoint. Вместо этого запустите отдельный DGDR или profiling job для каждого запланированного пула, а затем вручную соберите итоговый control DGD и pool DGDs.

Архитектура

flowchart LR
client["Client"]
prometheus["Prometheus<br/>per-pool router metrics"]
operator["Kubernetes operator<br/>DGD replica updates"]

subgraph control["Control DGD"]
frontend["Frontend<br/>single public endpoint"]
global_router["GlobalRouter<br/>selects a pool"]
global_planner["GlobalPlanner<br/>policy, budget, scale execution"]
end

subgraph prefill0["Prefill pool DGD: short prompts"]
prefill_router0["LocalRouter"] --> prefill_workers0["Prefill workers"]
prefill_planner0["Pool Planner"]
end

subgraph prefill1["Prefill pool DGD: long prompts"]
prefill_router1["LocalRouter"] --> prefill_workers1["Prefill workers"]
prefill_planner1["Pool Planner"]
end

subgraph decode0["Decode pool DGD"]
decode_router0["LocalRouter"] --> decode_workers0["Decode workers"]
decode_planner0["Pool Planner"]
end

prometheus -.-> prefill_planner0
prometheus -.-> prefill_planner1
prometheus -.-> decode_planner0

client --> frontend
frontend --> global_router
global_router --> prefill_router0
global_router --> prefill_router1
global_router --> decode_router0

prefill_planner0 -- scale request --> global_planner
prefill_planner1 -- scale request --> global_planner
decode_planner0 -- scale request --> global_planner

global_planner --> operator
operator --> prefill_workers0
operator --> prefill_workers1
operator --> decode_workers0

Читайте диаграмму слева направо для потока запросов: клиенты обращаются к control Frontend, GlobalRouter выбирает приватный пул, а LocalRouter каждого пула отправляет запрос workers. Пунктирные и нижние пути показывают масштабирование: локальный для каждого пула Planner читает router metrics этого пула, отправляет scale request в GlobalPlanner, а GlobalPlanner централизованно применяет изменения реплик Kubernetes.

Предварительные требования

  • Установленная Dynamo Kubernetes Platform. См. Kubernetes Quickstart.
  • Развернутый Prometheus, который собирает router metrics. Примеры global planner предполагают, что в кластере доступен Prometheus.
  • Backend images для выбранного framework (vllm, sglang или trtllm).
  • Secrets для доступа к модели, например secret с токеном Hugging Face.
  • Стратегия хранения model weights, если workers должны разделять PVC для model cache.

Для масштабирования на основе throughput также нужны profiling data для каждого пула. См. руководство по Profiler.

Входные данные, которые нужно определить заранее

Перед написанием manifests определите следующее:

Входные данныеПочему это важноПример
Model nameВсе пулы в одной иерархии обслуживают одну и ту же модельmeta-llama/Llama-3.3-70B-Instruct
BackendОт него зависят worker args и profiling flowvllm
Pool inventoryЧисло специализированных prefill- и decode-пулов2 prefill pools, 1 decode pool
Workload classesОпределяют, сколько pool profiles нужно сгенерироватьshort ISL, long ISL, long context decode
SLA targetsНаправляют profiling и решения маршрутизацииttft: 200 ms, itl: 20 ms
Worker shapeTensor parallelism, GPU на worker и memory footprintTP1 prefill vs. TP2 prefill
Routing policyСопоставляет запросы с пулами во время выполненияlow-ISL requests -> pool 0
Optional global budgetОграничивает общее число GPU во всех managed pools--max-total-gpus 16

Шаг 1: независимо профилируйте каждый запланированный пул

Сначала решите, на чем должен специализироваться каждый пул. Распространенные примеры:

  • Prefill pool 0: более дешевый пул для коротких prompts.
  • Prefill pool 1: более крупный пул для длинных prompts.
  • Decode pool 0: стандартный decode pool для большинства запросов.

Для каждого запланированного пула запустите отдельный DGDR или profiling job с workload и SLA, которые представляют этот пул.

Пример каркаса DGDR:

apiVersion: nvidia.com/v1beta1
kind: DynamoGraphDeploymentRequest
metadata:
name: llama-prefill-short
spec:
model: meta-llama/Llama-3.3-70B-Instruct
backend: vllm
image: nvcr.io/nvidia/ai-dynamo/dynamo-planner:1.2.0 # dynamo-frontend for Dynamo < 1.1.0
workload:
isl: 2048
osl: 256
sla:
ttft: 200.0
itl: 20.0
searchStrategy: rapid
autoApply: false

Повторите это один раз для каждого запланированного пула, меняя входные workload и SLA для каждого класса запросов.

Что сохранить из каждого результата profiling:

  • Worker shape (tensor-parallel-size, GPU на worker, настройки memory/caching).
  • Planner profile data directory или сгенерированные ConfigMaps.
  • Настройки Planner, например prefill_engine_num_gpu или decode_engine_num_gpu.
  • Любые backend-specific flags, которые различаются между пулами.

Подробности о DGDR см. в примерах Planner и руководстве по Profiler.

Шаг 2: создайте Control DGD

Разверните один control DGD, который содержит:

  • Frontend: единый публичный model endpoint.
  • GlobalRouter: выбирает, какой пул получает каждый запрос.
  • GlobalPlanner: получает scale requests от pool planners и применяет изменения реплик.

Пример топологии vLLM находится в examples/global_planner/global-planner-vllm-test.yaml.

Секция GlobalPlanner минимальна:

GlobalPlanner:
componentType: default
replicas: 1
extraPodSpec:
mainContainer:
image: ${DYNAMO_IMAGE}
command:
- python3
- -m
- dynamo.global_planner
args:
- --managed-namespaces
- ${K8S_NAMESPACE}-gp-prefill-0
- ${K8S_NAMESPACE}-gp-prefill-1
- ${K8S_NAMESPACE}-gp-decode-0

Значения, передаваемые в --managed-namespaces, - это Dynamo namespaces (caller_namespace) pool planners, а не обычные Kubernetes namespaces. Во многих примерах у них общий строковый префикс, но логически это разные идентификаторы.

Режимы управления: когда задан --managed-namespaces (явный режим), только перечисленные Dynamo namespaces имеют право отправлять scale requests, и только соответствующие им DGD учитываются в GPU budget. Имена DGD выводятся из Dynamo namespace по соглашению operator DYN_NAMESPACE = {k8s_namespace}-{dgd_name}. Если параметр опущен (неявный режим), принимается любой caller, а все DGD в Kubernetes namespace учитываются в GPU budget.

Если нужно, чтобы центральный executor отклонял scale requests, превышающие общий GPU budget, добавьте --max-total-gpus. См. examples/global_planner/global-planner-gpu-budget.yaml.

Шаг 3: создайте по одному DGD на пул

Каждый приватный пул получает собственный DGD. Pool DGD обычно содержит:

  • LocalRouter
  • один тип worker (prefill или decode)
  • один Planner

Planner внутри каждого пула должен быть настроен на режим global-planner, чтобы делегировать масштабирование control stack:

{
"environment": "global-planner",
"global_planner_namespace": "${K8S_NAMESPACE}-gp-ctrl",
"backend": "vllm",
"mode": "prefill",
"enable_load_scaling": false,
"enable_throughput_scaling": true,
"throughput_metrics_source": "router",
"ttft": 2000,
"prefill_engine_num_gpu": 2,
"model_name": "${MODEL_NAME}",
"profile_results_dir": "/workspace/components/src/dynamo/planner/tests/data/profiling_results/H200_TP1P_TP1D"
}

global_planner_namespace должен указывать на Dynamo namespace control stack. В эталонных manifests это строка namespace, передаваемая в control Frontend и GlobalRouter.

throughput_metrics_source: "router" обязателен для pool-local Planner в развертываниях GlobalPlanner. Pool Planner должен прогнозировать спрос по собственным Prometheus-метрикам LocalRouter dynamo_component_router_*, а не по общему публичному Frontend. Точные источники frontend- и router-метрик см. в обзоре Planner.

Используйте:

  • mode: "prefill" для пулов только с prefill
  • mode: "decode" для пулов только с decode

Настройки worker и planner для каждого пула берутся из результата profiling для конкретного пула, который был создан на шаге 1.

В эталонном примере vLLM:

  • gp-prefill-0 использует prefill worker TP1 с 1 GPU
  • gp-prefill-1 использует prefill worker TP2 с 2 GPU
  • gp-decode-0 использует decode worker TP1 с 1 GPU

См. global-planner-vllm-test.yaml.

Шаг 4: настройте GlobalRouter для выбора пулов

GlobalRouter читает JSON-конфигурацию, где перечислены pool namespaces и routing grid для каждого типа запросов.

Пример:

{
"enable_priority_retry": true,
"num_prefill_pools": 2,
"num_decode_pools": 1,
"prefill_pool_dynamo_namespaces": [
"${K8S_NAMESPACE}-gp-prefill-0",
"${K8S_NAMESPACE}-gp-prefill-1"
],
"decode_pool_dynamo_namespaces": [
"${K8S_NAMESPACE}-gp-decode-0"
],
"prefill_pool_priorities": [0, 1],
"decode_pool_priorities": [0],
"prefill_pool_selection_strategy": {
"ttft_min": 10,
"ttft_max": 3000,
"ttft_resolution": 2,
"isl_min": 0,
"isl_max": 32000,
"isl_resolution": 2,
"prefill_pool_mapping": [[0, 1], [0, 1]]
},
"decode_pool_selection_strategy": {
"itl_min": 10,
"itl_max": 500,
"itl_resolution": 2,
"context_length_min": 0,
"context_length_max": 32000,
"context_length_resolution": 2,
"decode_pool_mapping": [[0, 0], [0, 0]]
}
}

Записи prefill_pool_dynamo_namespaces и decode_pool_dynamo_namespaces - это Dynamo namespaces, под которыми регистрируются pool-local routers.

Важное поведение во время выполнения:

  • Выбор prefill pool использует ISL + TTFT target
  • Выбор decode pool использует context length + ITL target
  • OSL полезен для проектирования и profiling пулов, но в текущем GlobalRouter он не является прямым routing key
  • Опциональный priority retry включается через enable_priority_retry; меньшие значения в *_pool_priorities обозначают более быстрые пулы, а если priority lists опущены, по умолчанию используется порядок пулов (0, 1, ...)

Клиенты могут передавать целевые значения запроса через extra_args:

{
"extra_args": {
"ttft_target": 200,
"itl_target": 20
}
}

Подробнее см. Global Router README.

Шаг 5: развертывайте в правильном порядке

Для нового кластера обычный порядок такой:

  1. Установите Dynamo platform и Prometheus.
  2. Создайте secrets и PVCs, нужные workers.
  3. Создайте ConfigMap для GlobalRouter.
  4. Примените control DGD.
  5. Примените pool DGDs.
  6. Дождитесь, пока все DGD перейдут в состояние ready.
  7. Экспонируйте или port-forward control Frontend.

Пример:

export K8S_NAMESPACE=my-llama
export MODEL_NAME=meta-llama/Llama-3.3-70B-Instruct
export DYNAMO_IMAGE=<dynamo-image>
export DYNAMO_VLLM_IMAGE=<vllm-image>
export STORAGE_CLASS_NAME=<rwx-storage-class>

kubectl create secret generic hf-token-secret \
--from-literal=HF_TOKEN=${HF_TOKEN} \
-n ${K8S_NAMESPACE}

envsubst < examples/global_planner/global-planner-vllm-test.yaml | \
kubectl apply -n ${K8S_NAMESPACE} -f -

Единственный пользовательский endpoint - это Frontend в control DGD, а не pool DGDs.

Шаг 6: проверьте stack

Проверяйте развертывание снаружи внутрь:

  • Убедитесь, что control Frontend исправен и обслуживает model endpoint.
  • Убедитесь, что логи GlobalRouter показывают назначение запросов ожидаемым pool namespaces.
  • Убедитесь, что pool-local planners создают scale requests.
  • Убедитесь, что логи GlobalPlanner показывают принятые операции масштабирования.
  • Убедитесь, что число реплик целевых DGD меняется ожидаемым образом.

Если вы используете Prometheus и Grafana, также проверьте:

  • TTFT и ITL во времени
  • число workers по пулам
  • состав запросов по пулам
  • общее использование GPU

Рекомендуемый workflow для новых развертываний

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

  1. Спроектируйте классы пулов на основе ожидаемых паттернов трафика.
  2. Запустите по одному DGDR на каждый класс пула, чтобы сгенерировать или проверить конфигурацию пула.
  3. Скопируйте выбранные worker shape и настройки planner в итоговые pool DGDs.
  4. Соберите один control DGD с Frontend, GlobalRouter и GlobalPlanner.
  5. Направьте весь клиентский трафик через control Frontend.

Так profiling и выбор пулов остаются простыми, но при этом для модели сохраняется один публичный endpoint.

Текущие ограничения

  • Развертывания GlobalPlanner с одним endpoint сейчас собираются вручную. Один DGDR не выводит полную топологию control DGD плюс pool DGDs.
  • GlobalRouter маршрутизирует по grids ISL/TTFT и context-length/ITL, а не напрямую по OSL.
  • В паттерне с одним endpoint ожидается, что все пулы обслуживают одну и ту же модель.

См. также