For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.nvidia.com/dynamo/llms.txt. For full content including API reference and SDK examples, see https://docs.nvidia.com/dynamo/llms-full.txt.
Топологически осведомлённая передача KV
Топологически осведомлённая передача KV
Топологически осведомлённая передача KV позволяет disaggregated deployment Dynamo направлять decode-запросы к worker'ам, которые находятся в той же топологической области, что и выбранный prefill worker, например в той же зоне или на том же rack. Это снижает медленные междоменные передачи KV-кэша, когда worker'ы prefill и decode обмениваются KV-данными через NIXL.
Используйте эту возможность, когда:
- Ваш deployment использует отдельные worker'ы prefill и decode.
- В кластере доступны полезные метки node, например
topology.kubernetes.io/zoneили метка rack/block. - Передача KV в пределах одного домена нужна для корректности или сильно предпочтительна с точки зрения задержки и пропускной способности.
На этой странице описан путь через Kubernetes operator. Поведение router и runtime см. в Router Topology-Aware KV Transfer. Настройку транспорта RDMA/NIXL см. в Disagg Communication.
Как это работает
flowchart LR
DGD["DGD spec.experimental.kvTransferPolicy"] --> Operator["Operator injects worker env + Downward API volume"]
Node["Node label"] --> Controller["Topology label controller"]
Controller --> Pod["Worker pod label"]
Pod --> Volume["/etc/dynamo/topology/<domain>"]
Volume --> Runtime["Worker publishes ModelRuntimeConfig topology metadata"]
Runtime --> Prefill["Prefill router derives decode constraints"]
Prefill --> Decode["Decode router selects same or preferred topology"]
Operator настраивает worker pods из spec.experimental.kvTransferPolicy:
- Добавляет к worker pods аннотацию
nvidia.com/topology-label-key. - Запускает topology-label controller, который копирует настроенную метку node на worker pod после scheduling.
- Проецирует эту метку pod в
/etc/dynamo/topology/<domain>через том Downward API. - Добавляет переменные среды worker'а, которые сообщают backend runtime, какой топологический домен и политику принуждения публиковать.
Frontend не читает эту политику из собственной среды. Worker'ы публикуют топологические метаданные в ModelRuntimeConfig, а router читает их из runtime discovery.
Предварительные требования
| Требование | Подробности |
|---|---|
| Disaggregated serving | Отдельные службы worker'ов prefill и decode. |
| KV router | Frontend должен использовать DYN_ROUTER_MODE=kv. |
| Метки топологии node | Каждая node, на которой может размещаться worker, должна содержать настроенный labelKey. |
| Dynamo operator | В operator должны быть topology-label controller и RBAC на чтение node. |
| Транспорт передачи KV | Для production disaggregated deployment уже должен быть настроен RDMA, EFA или другой совместимый с NIXL транспорт. |
Убедитесь, что метка, которую вы планируете использовать, присутствует на worker nodes:
kubectl get nodes -L topology.kubernetes.io/zone
Обязательная маршрутизация в пределах одного домена
enforcement: required ограничивает выбор decode worker'а теми worker'ами, чьё значение топологии совпадает с выбранным prefill worker для настроенного домена. Если ни один decode worker не удовлетворяет сформированному ограничению, router завершает запрос с ошибкой вместо того, чтобы незаметно перейти в другой домен.
apiVersion: nvidia.com/v1beta1
kind: DynamoGraphDeployment
metadata:
name: qwen3-disagg-zone
spec:
experimental:
kvTransferPolicy:
labelKey: topology.kubernetes.io/zone
domain: zone
enforcement: required
components:
- name: Frontend
type: frontend
replicas: 1
podTemplate:
spec:
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
env:
- name: DYN_ROUTER_MODE
value: kv
- name: VllmPrefillWorker
type: worker
replicas: 2
podTemplate:
spec:
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
command: ["python3", "-m", "dynamo.vllm"]
args: ["--model", "Qwen/Qwen3-0.6B", "--disaggregation-mode", "prefill"]
envFrom:
- secretRef:
name: hf-token-secret
resources:
limits:
nvidia.com/gpu: "1"
- name: VllmDecodeWorker
type: worker
replicas: 2
podTemplate:
spec:
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
command: ["python3", "-m", "dynamo.vllm"]
args: ["--model", "Qwen/Qwen3-0.6B", "--disaggregation-mode", "decode"]
envFrom:
- secretRef:
name: hf-token-secret
resources:
limits:
nvidia.com/gpu: "1"
Если enforcement не указан, по умолчанию используется required.
required - это ограничение маршрутизации decode, а не планировщик capacity. Автор DynamoGraphDeployment или администратор кластера должен обеспечить, чтобы у каждого топологического домена, куда могут попасть prefill worker'ы, была достаточная same-domain capacity для decode. Если в домене есть prefill worker'ы, но нет подходящих decode worker'ов или decode capacity слишком мала, router не сможет переключиться в другой домен, не нарушив политику.
Планирование capacity по доменам
Спланируйте capacity prefill и decode по каждому топологическому домену до включения enforcement: required. Например, допустим:
- Две зоны доступности:
az-1иaz-2. - Целевой парк - 60 worker'ов prefill и 120 worker'ов decode.
- Парк должен быть поровну распределён между двумя зонами.
- Целевое соотношение prefill к decode в каждой зоне - 1:2.
Это означает, что в каждой зоне должно работать по 30 worker'ов prefill и 60 worker'ов decode:
| Zone | Worker'ы prefill | Worker'ы decode | Соотношение |
|---|---|---|---|
az-1 | 30 | 60 | 1:2 |
az-2 | 30 | 60 | 1:2 |
В DynamoGraphDeployment задайте это как отдельные компоненты prefill и decode для каждой зоны. Привяжите каждый компонент к своей зоне и установите kvTransferPolicy.enforcement в required, чтобы router отклонял выбор decode из другой зоны. Автор DGD или администратор кластера должен обеспечить, чтобы в каждой зоне хватало capacity для размещения закреплённых replicas. Команда и args worker'а здесь опущены; настройте каждый worker в режиме prefill или decode так же, как в базовом manifest disaggregated serving:
apiVersion: nvidia.com/v1beta1
kind: DynamoGraphDeployment
metadata:
name: qwen3-disagg-zone-capacity
spec:
experimental:
kvTransferPolicy:
labelKey: topology.kubernetes.io/zone
domain: zone
enforcement: required
components:
- name: Frontend
type: frontend
replicas: 1
podTemplate:
spec:
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
env:
- name: DYN_ROUTER_MODE
value: kv
- name: VllmPrefillWorkerAz1
type: worker
replicas: 30
podTemplate:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["az-1"]
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
envFrom:
- secretRef:
name: hf-token-secret
- name: VllmDecodeWorkerAz1
type: worker
replicas: 60
podTemplate:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["az-1"]
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
envFrom:
- secretRef:
name: hf-token-secret
- name: VllmPrefillWorkerAz2
type: worker
replicas: 30
podTemplate:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["az-2"]
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
envFrom:
- secretRef:
name: hf-token-secret
- name: VllmDecodeWorkerAz2
type: worker
replicas: 60
podTemplate:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values: ["az-2"]
containers:
- name: main
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
envFrom:
- secretRef:
name: hf-token-secret
Предпочтительная маршрутизация в пределах одного домена
enforcement: preferred оставляет доступными все decode worker'ы, но смещает выбор worker'а в сторону того же топологического домена.
spec:
experimental:
kvTransferPolicy:
labelKey: topology.kubernetes.io/zone
domain: zone
enforcement: preferred
preferredWeight: 0.85
preferredWeight обязателен при enforcement: preferred. Он должен быть в диапазоне от 0 до 1. Более высокое значение сильнее предпочтёт same-domain выбор, но это не вероятность и не гарантия выбора внутри того же домена.
Справочник по полям
| Поле | Обязательно | Описание |
|---|---|---|
labelKey | Да | Ключ метки Kubernetes node, который нужно скопировать на worker pods, например topology.kubernetes.io/zone. |
domain | Да | Логическое имя топологического домена, публикуемое worker'ами, например zone или rack. Должно соответствовать ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. |
enforcement | Нет | required или preferred. По умолчанию required. |
preferredWeight | Только с preferred | Вес смещения от 0 до 1; допустим только при enforcement: preferred. |
Runtime использует domain, а не ключ метки Kubernetes, при создании routing constraints. Например, labelKey: topology.kubernetes.io/zone и domain: zone дают метаданные топологии worker'а вида:
{
"topology_domains": {
"zone": "us-east-1a"
},
"kv_transfer_domain": "zone",
"kv_transfer_enforcement": "required"
}
Проверка deployment
После того как DGD создаст worker pods, проверьте pipeline operator'а от метки node до файла топологии runtime.
export NAMESPACE=<namespace>
export POD=<worker-pod>
kubectl get pod "$POD" -n "$NAMESPACE" \
-o jsonpath='{.metadata.annotations.nvidia\.com/topology-label-key}{"\n"}'
kubectl get pod "$POD" -n "$NAMESPACE" \
-o jsonpath='{.metadata.labels.topology\.kubernetes\.io/zone}{"\n"}'
kubectl exec "$POD" -n "$NAMESPACE" -- \
sh -c 'find /etc/dynamo/topology -maxdepth 1 -type f -print -exec cat {} \;'
Ожидаемый результат:
- Значение аннотации равно настроенному
labelKey. - У worker pod присутствует скопированная метка топологии.
/etc/dynamo/topology/<domain>существует и содержит значение топологии.
В журналах worker'а при запуске должна присутствовать конфигурация топологии:
kubectl logs "$POD" -n "$NAMESPACE" | grep -i "Topology config"
Устранение неполадок
У pod нет скопированной метки топологии
Проверьте, есть ли на node настроенная метка:
NODE=$(kubectl get pod "$POD" -n "$NAMESPACE" -o jsonpath='{.spec.nodeName}')
kubectl get node "$NODE" -o jsonpath='{.metadata.labels.topology\.kubernetes\.io/zone}{"\n"}'
Если метка отсутствует, topology-label controller создаёт warning event с причиной TopologyLabelMissing и оставляет топологические метаданные недоступными для этого worker'а.
kubectl get events -n "$NAMESPACE" \
--field-selector involvedObject.name="$POD",reason=TopologyLabelMissing
Worker завершается в ожидании топологии
Когда топология включена, worker ждёт появления файла transfer-domain и наличия в нём данных. Если он остаётся пустым, проверьте:
spec.experimental.kvTransferPolicy.domainmatches the projected file name.spec.experimental.kvTransferPolicy.labelKeyexists on the worker's node.- The worker pod has the
nvidia.com/topology-label-keyannotation. - The topology-label controller is running and has node
getRBAC.
Обязательная политика приводит к ошибкам запросов
При enforcement: required маршрутизация decode завершается с ошибкой, если ни у одного decode worker нет того же сгенерированного topology taint, что и у выбранного prefill worker. Убедитесь, что и prefill, и decode worker'ы публикуют один и тот же domain, и что в каждом домене, где могут быть выбраны prefill worker'ы, достаточно подходящих decode worker'ов для ожидаемого p/d ratio.
Используйте preferred во время проверки heterogenous rollout, если при частичной capacity допустима маршрутизация между доменами.
Связь с Topology Aware Scheduling
Topology Aware Scheduling управляет тем, куда Kubernetes размещает pods. Топологически осведомлённая передача KV управляет тем, как Dynamo маршрутизирует трафик между уже работающими worker'ами prefill и decode.
По возможности используйте их вместе:
- Topology Aware Scheduling размещает worker'ов внутри полезных топологических границ.
- Топологически осведомлённая передача KV не позволяет router'у выбрать decode worker вне домена передачи выбранного prefill worker.