Чтобы получить чистую 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. Это руководство поможет вам:
- Развернуть две одинаковые конфигурации Dynamo: a. vllm-сервер для Qwen3-32B с 8 worker-узлами (aggregated) БЕЗ включенного KV Smart Router b. vllm-сервер для Qwen3-32B с 8 worker-узлами (aggregated) С включенным KV Smart Router
- Запустить управляемые бенчмарки с помощью AIPerf
- Сравнить метрики производительности, чтобы оценить эффективность 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 512for the Mooncake/toolagent trace itself - keep engine
block_sizein--extra-engine-argsaligned with the runtime you want to mimic (for the published vLLM deployment, that is typically64)
Ключевые свойства набора данных:
- ✅ 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 avg | 63,652 ms | 2,586 ms | 96% faster | 24.6x ✅ |
| TTFT p99 | 332,974 ms | 17,871 ms | 95% faster | 18.6x ✅ |
| E2E Latency avg | 92,856 ms | 19,112 ms | 79% faster | 4.9x ✅ |
| E2E Latency p99 | 411,252 ms | 88,274 ms | 79% faster | 4.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 на вашу модель в:
- секции
argsYAML-развертывания - параметрах 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
Лучшие практики
- Equal Conditions: Убедитесь, что перед бенчмарком обе конфигурации имеют одинаковое число worker-узлов и одинаковое состояние здоровья
- Warm-Up: Запустите небольшой тест (100 запросов) перед полным бенчмарком, чтобы прогреть кеши
- Multiple Runs: Запустите бенчмарк 3+ раза и усредните результаты для статистической значимости
- Monitor Workers: Следите за перезапусками pod-ов и любыми проблемами во время бенчмарк-прогонов
- Document Conditions: Зафиксируйте состояние кластера, здоровье worker-узлов и любые аномалии
- 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 routerbenchmark-job.yaml: benchmark pod AIPerf- Каталоги артефактов AIPerf: summary JSON и
profile_export.jsonlдля каждого прогона
Репозиторий: https://github.com/ai-dynamo/dynamo