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

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

A/B-тестирование KV Router

Это руководство проведет вас через настройку и запуск A/B-бенчмарков, чтобы сравнить Dynamo KV Smart Router со стандартной round-robin маршрутизацией в кластере Kubernetes.

Обзор

KV Smart Router от Dynamo интеллектуально маршрутизирует запросы на основе affinity к KV cache, повышая производительность для нагрузок с общими префиксами prompt. Это руководство поможет вам:

  1. Развернуть две одинаковые конфигурации Dynamo: a. vllm-сервер для Qwen3-32B с 8 worker-узлами (aggregated) БЕЗ включенного KV Smart Router b. vllm-сервер для Qwen3-32B с 8 worker-узлами (aggregated) С включенным KV Smart Router
  2. Запустить управляемые бенчмарки с помощью AIPerf
  3. Сравнить метрики производительности, чтобы оценить эффективность KV router

Предварительные требования: кластер Kubernetes с GPU, kubectl, helm


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

Необходимые инструменты

  • kubectl (настроен и имеет доступ к кластеру)
  • helm (v3+)
  • учетная запись HuggingFace и токен (если загрузка модели ограничена)
  • Кластер Kubernetes со следующими характеристиками:
    • GPU-узлы (H100, H200 или аналогичные)
    • Достаточный объем GPU-ресурсов (для этого примера рекомендуется 8+ GPU)
    • Dynamo platform, установленная на уровне кластера, ИЛИ возможность установки в отдельный namespace

Требуемые знания

  • Базовые понятия Kubernetes (namespaces, pods, services)
  • Знакомство с концепциями LLM inference
  • Уверенная работа в командной строке

Архитектура

В этом руководстве используется один namespace. Мы разворачиваем одну конфигурацию (например, router-ON), запускаем бенчмарк, удаляем ее, затем разворачиваем вторую (router-OFF) и запускаем тот же бенчмарк.

┌──────────────────────────────────────────────┐
│ Namespace: dynamo-bench │
│ (one of A or B active at a time) │
│ │
│ Deployment A: Router OFF │
│ ├─ Frontend (Standard Routing) │
│ └─ 8x Decode Workers (1 GPU each) │
│ │
│ Deployment B: Router ON │
│ ├─ Frontend (KV Smart Router) │
│ └─ 8x Decode Workers (1 GPU each) │
│ │
│ Benchmark Pod (AIPerf + Dataset) │
└──────────────────────────────────────────────┘

Ключевое отличие: Deployment B задает DYN_ROUTER_MODE=kv на frontend, чтобы включить маршрутизацию с учетом KV cache.


Этап 1: Настройка namespace и инфраструктуры

Шаг 1.1: Создайте namespace

kubectl create namespace dynamo-bench

Шаг 1.2: Создайте Secret с токеном HuggingFace (необязательно)

Если модель, которую вы хотите развернуть, требует HF token для загрузки (модели семейства Llama требуют этого), замените YOUR_HF_TOKEN на свой токен HuggingFace:

kubectl create secret generic hf-token-secret \
--from-literal=HF_TOKEN="YOUR_HF_TOKEN" \
-n dynamo-bench

Шаг 1.3: Установите Dynamo Platform

Следуйте Dynamo Kubernetes Installation Guide, чтобы установить платформу в dynamo-bench.

Примечание: Режим с ограничением по namespace (namespaceRestriction.enabled=true) устарел и будет удален в одном из будущих релизов. Для новых развертываний используйте кластерный режим.

Ключевые замечания по конфигурации:

  • Подберите теги версий в соответствии с доступными в вашем кластере версиями Dynamo
  • Если вы столкнетесь с проблемами совместимости operator (например, неподдерживаемыми аргументами MPI), обратитесь к администратору кластера или к документации Dynamo по устранению неполадок

Шаг 1.4: Проверьте инфраструктуру

kubectl get pods -n dynamo-bench

Перед развертыванием graph дождитесь состояния Running у pods operator, etcd и nats.


Этап 2: Развертывание сервинга модели

Шаг 2.1: Создайте YAML-файлы развертывания

Создайте router-off-deployment.yaml (базовый вариант):

apiVersion: nvidia.com/v1alpha1
kind: DynamoGraphDeployment
metadata:
name: vllm-agg-no-router
spec:
services:
Frontend:
componentType: frontend
replicas: 1
extraPodSpec:
mainContainer:
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
env:
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
VllmDecodeWorker:
envFromSecret: hf-token-secret
componentType: worker
replicas: 8
resources:
limits:
gpu: "1"
extraPodSpec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node.kubernetes.io/instance-type
operator: In
values:
- gpu-h100-sxm # Adjust to your GPU node type
mainContainer:
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
workingDir: /workspace
command:
- /bin/sh
- -c
args:
- >-
python3 -m dynamo.vllm
--model Qwen/Qwen3-32B
--quantization fp8
--kv-cache-dtype fp8
--max-model-len 131072
--hf-overrides '{"rope_scaling":{"rope_type":"yarn","factor":4.0,"original_max_position_embeddings":32768},"max_position_embeddings":131072}'
--gpu-memory-utilization 0.90
--block-size 64
--async-scheduling
--no-enable-log-requests
env:
- name: DYN_HEALTH_CHECK_ENABLED
value: "false"
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 120
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 60
livenessProbe:
httpGet:
path: /live
port: 9090
initialDelaySeconds: 300
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 10
readinessProbe:
httpGet:
path: /live
port: 9090
initialDelaySeconds: 300
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 10
subComponentType: decode

Создайте router-on-deployment.yaml (KV router включен):

apiVersion: nvidia.com/v1alpha1
kind: DynamoGraphDeployment
metadata:
name: vllm-agg-router
spec:
services:
Frontend:
componentType: frontend
replicas: 1
extraPodSpec:
mainContainer:
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
env:
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
envs:
- name: DYN_ROUTER_MODE
value: kv # KEY DIFFERENCE: Enable KV Smart Router
VllmDecodeWorker:
envFromSecret: hf-token-secret
componentType: worker
replicas: 8
resources:
limits:
gpu: "1"
extraPodSpec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node.kubernetes.io/instance-type
operator: In
values:
- gpu-h100-sxm # Adjust to your GPU node type
mainContainer:
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
workingDir: /workspace
command:
- /bin/sh
- -c
args:
- >-
python3 -m dynamo.vllm
--model Qwen/Qwen3-32B
--quantization fp8
--kv-cache-dtype fp8
--max-model-len 131072
--hf-overrides '{"rope_scaling":{"rope_type":"yarn","factor":4.0,"original_max_position_embeddings":32768},"max_position_embeddings":131072}'
--gpu-memory-utilization 0.90
--block-size 64
--async-scheduling
--no-enable-log-requests
env:
- name: DYN_HEALTH_CHECK_ENABLED
value: "false"
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 120
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 60
livenessProbe:
httpGet:
path: /live
port: 9090
initialDelaySeconds: 300
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 10
readinessProbe:
httpGet:
path: /live
port: 9090
initialDelaySeconds: 300
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 10
subComponentType: decode

Шаг 2.2: Сначала разверните Router-ON

kubectl apply -f router-on-deployment.yaml -n dynamo-bench

💡 Совет по оптимизации: Каждый worker будет скачивать модель независимо (примерно 20 минут на pod). Чтобы ускорить инициализацию, добавьте общий PVC с режимом доступа ReadWriteMany для кеширования модели.

Сначала создайте PVC в том же namespace, что и развертывание (например, dynamo-bench). Используйте storage class, поддерживающий ReadWriteMany:

kubectl get storageclass # choose one with ReadWriteMany (e.g. azurefile-csi-premium, nfs, efs)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-cache
namespace: dynamo-bench
spec:
accessModes:
- ReadWriteMany
storageClassName: "azurefile-csi-premium" # Adjust to your cluster
resources:
requests:
storage: 100Gi

Примените его: kubectl apply -f pvc-model-cache.yaml

Затем сослитесь на существующий PVC в вашем DynamoGraphDeployment, добавив следующее в spec (а в VllmDecodeWorker добавьте volumeMounts):

spec:
pvcs:
- create: false
name: model-cache
size: "0"
services:
VllmDecodeWorker:
volumeMounts:
- mountPoint: /root/.cache/huggingface
name: model-cache
useAsCompilationCache: false

При такой конфигурации первый запуск заставит одного worker скачать модель, а остальные загрузят ее из кеша. Главное преимущество проявляется при повторном развертывании: модель остается на PVC, поэтому новые pod-ы загружают ее из кеша и поднимаются примерно за 5-10 минут вместо повторного скачивания.

Шаг 2.3: Следите за прогрессом развертывания

kubectl get pods -n dynamo-bench -w

Дождитесь, пока все pods перейдут в состояние Running и пройдут readiness probes.

Ожидаемые сроки:

  • С общим PVC (ReadWriteMany): около 5-10 минут всего (первый worker скачивает модель, остальные используют кеш)
  • Без общего PVC: 20-30 минут на каждый worker (worker-узлы скачивают модель независимо)
    • Для 8 worker-узлов закладывайте 1-2 часа на полное развертывание (worker-узлы стартуют параллельно, но ограничены планированием по узлам)

Startup probe развертывания (initialDelaySeconds: 120, periodSeconds: 30, failureThreshold: 60) дает до 32 минут на каждый pod для скачивания и инициализации модели.

Шаг 2.4: Проверьте, что worker-узлы здоровы

⚠️ CRITICAL CHECKPOINT: Before running benchmarks, you MUST verify equal worker health. Unequal worker counts will invalidate your comparison results.

# Quick health check - should show "8/8"
echo "Workers: $(kubectl get pods -n dynamo-bench -l nvidia.com/dynamo-component-type=worker --field-selector=status.phase=Running -o json | jq '[.items[] | select(.status.conditions[] | select(.type=="Ready" and .status=="True"))] | length')/8 ready"

# Detailed view
kubectl get pods -n dynamo-bench -l nvidia.com/dynamo-component-type=worker

Все 8 должны показывать 1/1 Running и состояние Ready. Не продолжайте, пока это не подтверждено. Повторите проверку после удаления router-ON и развертывания router-OFF (Этап 5).


Этап 3: Подготовьте набор данных для бенчмарка

Что представляет собой Mooncake Toolagent Trace

Для этого A/B-сравнения мы используем Mooncake FAST'25 Toolagent Trace, опубликованный Mooncake AI (лучший доклад USENIX FAST'25). Это защищенный с точки зрения приватности набор данных реального LLM-инференс-трафика из production tool-agent workloads — AI-агентов, которые итеративно вызывают инструменты и API, сохраняя растущий контекст беседы. Трасса содержит 23,608 запросов примерно за 59 минут реального времени.

Почему именно toolagent trace? Tool-agent workloads отлично подходят для оценки маршрутизации по KV cache, потому что каждая сессия агента включает повторяющиеся вызовы LLM с длинным растущим префиксом (system prompt + история разговора + результаты инструментов), что создает высокое естественное перекрытие префиксов между запросами. Mooncake toolagent trace отражает эти реалистичные паттерны и позволяет показать практический выигрыш router.

Что есть в наборе данных? Каждая запись трассы содержит:

  • Timestamp: Время поступления запроса (для реалистичного тайминга)
  • Input/output lengths: Число токенов в prompt и ответах
  • Block hash IDs: Криптографические хэши, представляющие KV cache blocks (без пользовательского текста; пояснение ниже)

Примеры записей трассы (показывают повторное использование префикса):

{"timestamp": 0, "input_length": 9013, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]}
{"timestamp": 0, "input_length": 6506, "output_length": 3, "hash_ids": [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 64]}

Эти два запроса используют общие блоки 46–57 (12 блоков × 512 токенов = примерно 6,144 токенов общего префикса) — tool-agent продолжает ту же сессию с накопленным контекстом. Каждый hash ID представляет 512-токенный блок, а хэш включает и текущий блок, и все предыдущие блоки, сохраняя паттерн повторного использования префикса и защищая приватность пользователя. KV Smart Router направляет запросы с совпадающими hash ID на одного и того же worker-узла, максимизируя cache hit.

Если вы воспроизводите этот бенчмарк с python -m dynamo.replay, держите этот факт о наборе данных отдельно от конфигурации replay engine:

  • use --trace-block-size 512 for the Mooncake/toolagent trace itself
  • keep engine block_size in --extra-engine-args aligned with the runtime you want to mimic (for the published vLLM deployment, that is typically 64)

Ключевые свойства набора данных:

  • Realistic timing: Паттерны поступления запросов из production tool-agent workloads
  • High prefix overlap: 59% cache ratio (Mooncake FAST'25 paper); итеративные вызовы инструментов внутри сессий создают естественное повторное использование префикса
  • Privacy-preserving: Нет реального текста — только идентификаторы cache block на основе хэшей
  • Reproducible: Публичный набор данных позволяет честно сравнивать разные системы

Скачайте и подготовьте набор данных

# Download the Mooncake FAST'25 toolagent trace
curl -sL https://raw.githubusercontent.com/kvcache-ai/Mooncake/refs/heads/main/FAST25-release/traces/toolagent_trace.jsonl -o toolagent_trace.jsonl

# Slow down timestamps to 0.80× replay speed (~5.3 req/s instead of ~6.7 req/s)
python3 - <<'PY'
import json

with open("toolagent_trace.jsonl") as src, open("toolagent_trace_080x.jsonl", "w") as dst:
for line in src:
rec = json.loads(line)
rec["timestamp"] = int(rec["timestamp"] / 0.80)
dst.write(json.dumps(rec) + "\n")
PY

echo "Dataset ready: toolagent_trace_080x.jsonl (23,608 requests, 0.80x speed)"

Этап 4: Настройка среды бенчмарка

Шаг 4.1: Разверните benchmark pod

Создайте benchmark-job.yaml:

apiVersion: batch/v1
kind: Job
metadata:
name: aiperf-benchmark
spec:
backoffLimit: 1
template:
spec:
restartPolicy: Never
containers:
- name: benchmark
image: nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0
securityContext:
runAsUser: 0 # Required: apt-get and pip install need root in ephemeral benchmark pod
command:
- /bin/bash
- -lc
- |
apt-get update -qq && apt-get install -y -qq tmux > /dev/null 2>&1
pip install -q aiperf==0.8.0
echo "Benchmark pod ready (tmux + aiperf installed)."
sleep infinity
imagePullPolicy: IfNotPresent
resources:
limits:
nvidia.com/gpu: 0

Этот pod устанавливает tmux и aiperf при запуске, чтобы бенчмарки можно было выполнять внутри tmux-сессии, которая переживает разрывы kubectl exec.

Разверните:

kubectl apply -f benchmark-job.yaml -n dynamo-bench

Дождитесь готовности pod (инициализация занимает примерно 1-2 минуты на установку пакетов):

kubectl get pods -n dynamo-bench -l job-name=aiperf-benchmark -w

Шаг 4.2: Скопируйте набор данных в benchmark pod

POD_NAME=$(kubectl get pods -n dynamo-bench -l job-name=aiperf-benchmark -o jsonpath='{.items[0].metadata.name}')
kubectl -n dynamo-bench cp toolagent_trace_080x.jsonl ${POD_NAME}:/tmp/toolagent_trace_080x.jsonl

Этап 5: Запустите бенчмарки

Шаг 5.1: Протестируйте Router-ON

Убедитесь, что frontend service доступен (operator создает service с именем {deployment-name}-frontend):

kubectl get svc -n dynamo-bench | grep frontend

Запустите бенчмарк внутри tmux-сессии, чтобы он переживал разрывы kubectl exec:

kubectl -n dynamo-bench exec ${POD_NAME} -- bash -c '
tmux new-session -d -s benchmark ". /opt/dynamo/venv/bin/activate && \
AIPERF_HTTP_CONNECTION_LIMIT=200 aiperf profile \
-m Qwen/Qwen3-32B \
--tokenizer Qwen/Qwen3-32B \
--input-file /tmp/toolagent_trace_080x.jsonl \
--custom-dataset-type mooncake_trace \
--fixed-schedule \
--url http://vllm-agg-router-frontend.dynamo-bench.svc.cluster.local:8000 \
--streaming \
--random-seed 42 \
--workers-max 200 \
--request-timeout-seconds 1000 \
--profile-export-level records \
--record-processors 8 \
--artifact-dir /tmp/aiperf_router_on \
--goodput \"time_to_first_token:5000 inter_token_latency:100\""
'

Подключитесь к активному TUI (отсоединение с помощью Ctrl+B, затем D):

kubectl -n dynamo-bench exec -it ${POD_NAME} -- tmux a -t benchmark

Шаг 5.2: Переключитесь на Router-OFF и запустите бенчмарк

Удалите router-ON и разверните базовый вариант:

kubectl delete dynamographdeployment vllm-agg-router -n dynamo-bench
kubectl apply -f router-off-deployment.yaml -n dynamo-bench

Дождитесь, пока 8/8 worker-узлов снова станут Ready (повторно выполните проверку из Шага 2.4), затем очистите предыдущую tmux-сессию и запустите базовый бенчмарк:

kubectl -n dynamo-bench exec ${POD_NAME} -- tmux kill-session -t benchmark 2>/dev/null

kubectl -n dynamo-bench exec ${POD_NAME} -- bash -c '
tmux new-session -d -s benchmark ". /opt/dynamo/venv/bin/activate && \
AIPERF_HTTP_CONNECTION_LIMIT=200 aiperf profile \
-m Qwen/Qwen3-32B \
--tokenizer Qwen/Qwen3-32B \
--input-file /tmp/toolagent_trace_080x.jsonl \
--custom-dataset-type mooncake_trace \
--fixed-schedule \
--url http://vllm-agg-no-router-frontend.dynamo-bench.svc.cluster.local:8000 \
--streaming \
--random-seed 42 \
--workers-max 200 \
--request-timeout-seconds 1000 \
--profile-export-level records \
--record-processors 8 \
--artifact-dir /tmp/aiperf_router_off \
--goodput \"time_to_first_token:5000 inter_token_latency:100\""
'

Шаг 5.3: Соберите результаты

Скопируйте каталоги с артефактами (или файлы summary/export внутри них) на локальную машину:

kubectl -n dynamo-bench cp ${POD_NAME}:/tmp/aiperf_router_on ./aiperf_router_on
kubectl -n dynamo-bench cp ${POD_NAME}:/tmp/aiperf_router_off ./aiperf_router_off

Каждый каталог с артефактами содержит:

  • profile_export_aiperf.json — сводка с агрегированными метриками (TTFT, перцентили задержки, throughput)
  • profile_export.jsonl — записи по каждому запросу (один JSON-объект на завершенный запрос)

Шаг 5.4: Быстрое сравнение

Извлеките и сравните ключевые метрики из двух summary-файлов:

python3 -c "
import json, pathlib

def load(d):
return json.loads(pathlib.Path(d, 'profile_export_aiperf.json').read_text())

on, off = load('aiperf_router_on'), load('aiperf_router_off')

metrics = [
('TTFT avg (ms)', 'time_to_first_token', 'avg'),
('TTFT p99 (ms)', 'time_to_first_token', 'p99'),
('E2E Latency avg (ms)', 'request_latency', 'avg'),
('E2E Latency p99 (ms)', 'request_latency', 'p99'),
('Output Throughput (tok/s)', 'output_token_throughput', 'avg'),
]

print(f\"{'Metric':<28} {'Router-OFF':>12} {'Router-ON':>12} {'Speedup':>10}\")
print('-' * 66)
for label, key, stat in metrics:
v_off = off.get(key, {}).get(stat, 0)
v_on = on.get(key, {}).get(stat, 0)
if 'throughput' in key.lower():
speedup = v_on / v_off if v_off else 0
else:
speedup = v_off / v_on if v_on else 0
print(f'{label:<28} {v_off:>12.1f} {v_on:>12.1f} {speedup:>9.1f}x')
"

Этап 6: Анализ результатов

Ключевые метрики для сравнения

МетрикаОписаниеНа что смотреть
Time to First Token (TTFT)Задержка до появления первого токенаМеньше лучше; KV router может снизить ее при повторном использовании префикса
Inter Token Latency (ITL)Среднее время между токенамиМеньше лучше; показывает скорость генерации
Request LatencyПолная end-to-end задержкаМеньше лучше; отражает общий пользовательский опыт
Output Token ThroughputКоличество токенов, генерируемых в секунду (по всей системе)Больше лучше; эффективность системы
Request ThroughputЧисло запросов, завершаемых в секундуБольше лучше; пропускная способность

Как интерпретировать результаты

Ваши результаты могут отличаться: выигрыш от KV Smart Router сильно зависит от характеристик workload:

Факторы, увеличивающие пользу KV router:

  • Высокое перекрытие префиксов (общие system prompts, шаблоны, контексты документов)
  • Длинные prompt-ы (>2000 токенов), где кеширование экономит заметные вычисления
  • Многоходовые разговоры с накоплением контекста
  • Batch-workload-ы с похожими запросами

Факторы, уменьшающие пользу KV router:

  • Уникальные prompt-ы без повторного использования префикса
  • Короткие prompt-ы (меньше 1000 токенов), где накладные расходы маршрутизации могут перевешивать выгоду
  • Равномерно распределенная нагрузка, где round-robin уже близок к оптимуму
  • Низкая скорость поступления запросов, где вытеснение кеша сводит пользу на нет

KV Smart Router полезен, когда:

  • Улучшение TTFT превышает 20%
  • Нет заметной деградации по другим метрикам
  • Workload демонстрирует измеримое повторное использование префикса

Стандартная маршрутизация лучше, когда:

  • KV router дает меньше 10% улучшения
  • Наблюдается рост вариативности задержек
  • Важнее равномерное распределение нагрузки между worker-узлами, чем affinity к кешу

Пример сравнения

На нашем бенчмарке Dynamo Operator с полным toolagent trace и скоростью replay 0.80×:

МетрикаRouter-OFF (Baseline)Router-ON (KV Router)УлучшениеSpeedup
TTFT avg63,652 ms2,586 ms96% faster24.6x ✅
TTFT p99332,974 ms17,871 ms95% faster18.6x ✅
E2E Latency avg92,856 ms19,112 ms79% faster4.9x ✅
E2E Latency p99411,252 ms88,274 ms79% faster4.7x ✅

В этом примере при здоровых всех 8 worker-узлах KV router заметно опередил baseline:

  • TTFT на 96% быстрее — пользователи видят первый токен примерно через 2.6 секунды вместо ~64 секунд
  • E2E latency на 79% ниже — запросы завершаются примерно за 19 секунд вместо ~93 секунд
  • TTFT p99 на 95% быстрее — хвостовая задержка падает примерно с ~333 секунд до ~18 секунд

Toolagent trace содержит сильное перекрытие префиксов из tool-agent сессий с повторяющимся контекстом. Без KV router запросы с совпадающими префиксами распределяются по разным worker-узлам, что приводит к избыточному пересчету и неконтролируемому росту очередей при высокой загрузке. С KV router запросы с совпадающими префиксами отправляются на один и тот же worker, максимизируя cache hit и стабилизируя задержки под нагрузкой.


Этап 7: Очистка

kubectl delete dynamographdeployment --all -n dynamo-bench
kubectl delete job aiperf-benchmark -n dynamo-bench
kubectl delete namespace dynamo-bench

Устранение неполадок

Проблема: Pods застряли в Pending

Причина: Недостаточно GPU-ресурсов

Решение:

# Check GPU availability
kubectl describe nodes | grep -A 10 "Allocated resources"

# Reduce worker replicas if needed
kubectl edit dynamographdeployment -n dynamo-bench

Проблема: Ошибки ImagePullBackOff

Причина: Несовпадение версии или отсутствующие учетные данные

Решение:

# Check available versions
kubectl get pods -n dynamo-bench -o yaml | grep image:

# Update deployment YAML to match cluster version

Проблема: Operator не обрабатывает развертывание

Причина: Ограничения namespace

Решение:

  • Убедитесь, что Dynamo platform установлена через Helm в нужном namespace
  • Проверьте, что у operator есть аргумент --restrictedNamespace=dynamo-bench
  • Посмотрите логи operator: kubectl logs -n dynamo-bench deployment/dynamo-platform-dynamo-operator-controller-manager

Проблема: Worker-узлы не становятся Ready

Причина: Сбои загрузки модели или конфигурации probe

Решение:

# Check worker logs
kubectl logs -n dynamo-bench <worker-pod-name>

# Common issues:
# - Invalid HuggingFace token
# - Network connectivity
# - Insufficient disk space for model

Проблема: Worker-узлы перезапускаются в CrashLoopBackOff

Причина: Timeout startup probe — worker-узлы убиваются до завершения инициализации

Симптомы:

  • Pods показывают "Container main failed startup probe, will be restarted"
  • В логах видно, что модель все еще скачивается или загружается в момент убийства pod

Решение: В YAML-файлах развертывания в этом руководстве задано failureThreshold: 60, что дает до 32 минут (120s + 60×30s). Если вы уменьшили это значение или используете более крупную модель, которой нужно больше времени, увеличьте его:

kubectl patch dynamographdeployment <deployment-name> -n dynamo-bench --type='json' \
-p='[{"op": "replace", "path": "/spec/services/VllmDecodeWorker/extraPodSpec/mainContainer/startupProbe/failureThreshold", "value": 80}]'

Соответствующие поля startup probe:

startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 120
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 60 # 32 minutes total (120s + 60*30s); increase for larger models

Примерное время загрузки модели:

  • Qwen3-32B: ~20-25 minutes (first download)
  • With cached model on node: ~2-5 minutes

Проблема: Неравномерное состояние worker-узлов

Причина: Ограничения ресурсов, проблемы с image pull или ошибки конфигурации

Решение:

# Check all worker status
kubectl get pods -n dynamo-bench -l nvidia.com/dynamo-component-type=worker

# Describe problematic pods
kubectl describe pod <pod-name> -n dynamo-bench

# Fix issues before benchmarking or results will be skewed

Дополнительная настройка

Тестирование других моделей

Замените Qwen/Qwen3-32B на вашу модель в:

  • секции args YAML-развертывания
  • параметрах AIPerf --model и --tokenizer

Изменение числа worker-узлов

Измените replicas: 8 в YAML-файлах развертывания. Для честного сравнения убедитесь, что в обеих конфигурациях используется одинаковое число worker-узлов.

Использование пользовательских наборов данных

Замените Mooncake trace своим JSONL-файлом:

  • Формат: одна запись запроса на строку с полем timestamp
  • AIPerf поддерживает разные форматы через --custom-dataset-type

Disaggregated Prefill/Decode

Для продвинутого тестирования добавьте отдельные prefill worker-узлы:

VllmPrefillWorker:
componentType: worker
replicas: 2
# ... configuration

Лучшие практики

  1. Equal Conditions: Убедитесь, что перед бенчмарком обе конфигурации имеют одинаковое число worker-узлов и одинаковое состояние здоровья
  2. Warm-Up: Запустите небольшой тест (100 запросов) перед полным бенчмарком, чтобы прогреть кеши
  3. Multiple Runs: Запустите бенчмарк 3+ раза и усредните результаты для статистической значимости
  4. Monitor Workers: Следите за перезапусками pod-ов и любыми проблемами во время бенчмарк-прогонов
  5. Document Conditions: Зафиксируйте состояние кластера, здоровье worker-узлов и любые аномалии
  6. Consistent Configuration: Используйте один и тот же файл trace и одинаковые опции AIPerf для обоих запусков

Заключение

Это руководство дает полную методику A/B-тестирования KV Smart Router в Dynamo. Эффективность KV router сильно зависит от характеристик workload: на наборах данных с высоким перекрытием префиксов выигрыш будет максимальным. Дополнительные сведения о настройке KV router см. в Tuning Guidelines.

Если у вас есть вопросы или проблемы, обратитесь к документации Dynamo или откройте issue на GitHub.


Приложение: Справочник файлов

  • router-off-deployment.yaml: Развертывание со стандартной маршрутизацией
  • router-on-deployment.yaml: Развертывание с включенным KV router
  • benchmark-job.yaml: benchmark pod AIPerf
  • Каталоги артефактов AIPerf: summary JSON и profile_export.jsonl для каждого прогона

Репозиторий: https://github.com/ai-dynamo/dynamo