Чтобы получить чистое 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 plane | Frontend, GlobalRouter, GlobalPlanner |
| Prefill pool DGD(s) | Приватные пулы prefill capacity | LocalRouter, prefill worker(s), Planner |
| Decode pool DGD(s) | Приватные пулы decode capacity | LocalRouter, 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 flow | vllm |
| 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 shape | Tensor parallelism, GPU на worker и memory footprint | TP1 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"для пулов только с prefillmode: "decode"для пулов только с decode
Настройки worker и planner для каждого пула берутся из результата profiling для конкретного пула, который был создан на шаге 1.
В эталонном примере vLLM:
gp-prefill-0использует prefill worker TP1 с 1 GPUgp-prefill-1использует prefill worker TP2 с 2 GPUgp-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: развертывайте в правильном порядке
Для нового кластера обычный порядок такой:
- Установите Dynamo platform и Prometheus.
- Создайте secrets и PVCs, нужные workers.
- Создайте ConfigMap для
GlobalRouter. - Примените control DGD.
- Примените pool DGDs.
- Дождитесь, пока все DGD перейдут в состояние ready.
- Экспонируйте или 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 для новых развертываний
Для большинства команд самый простой способ собрать такое развертывание:
- Спроектируйте классы пулов на основе ожидаемых паттернов трафика.
- Запустите по одному DGDR на каждый класс пула, чтобы сгенерировать или проверить конфигурацию пула.
- Скопируйте выбранные worker shape и настройки planner в итоговые pool DGDs.
- Соберите один control DGD с
Frontend,GlobalRouterиGlobalPlanner. - Направьте весь клиентский трафик через control
Frontend.
Так profiling и выбор пулов остаются простыми, но при этом для модели сохраняется один публичный endpoint.
Текущие ограничения
- Развертывания
GlobalPlannerс одним endpoint сейчас собираются вручную. Один DGDR не выводит полную топологию control DGD плюс pool DGDs. GlobalRouterмаршрутизирует по grids ISL/TTFT и context-length/ITL, а не напрямую по OSL.- В паттерне с одним endpoint ожидается, что все пулы обслуживают одну и ту же модель.
См. также
- Planner README — обзор Planner и quick start
- Руководство по Planner — справочник конфигурации Planner
- Примеры Planner — примеры DGDR для генерации конфигураций по пулам
- Руководство по Profiler — workflow profiling перед развертыванием
- Global Planner README — централизованное выполнение масштабирования
- Global Router README — маршрутизация запросов между пулами
- Пример vLLM global planner — сквозной эталонный manifest