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

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 routerFrontend должен использовать 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:

ZoneWorker'ы prefillWorker'ы decodeСоотношение
az-130601:2
az-230601: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.domain matches the projected file name.
  • spec.experimental.kvTransferPolicy.labelKey exists on the worker's node.
  • The worker pod has the nvidia.com/topology-label-key annotation.
  • The topology-label controller is running and has node get RBAC.

Обязательная политика приводит к ошибкам запросов

При 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.