Все статьи
· 7 мин чтения

NVIDIA Dynamo: дирижёр для инференса на целый дата-центр 🎻🖥️

Разбираю ai-dynamo/dynamo — открытый оркестратор инференса от NVIDIA. Зачем нужен, как устроен (KV-aware роутинг, disaggregated prefill/decode, KVBM, Planner), как обрабатывается запрос и как запустить. С mermaid-диаграммами и интерактивом.

NVIDIA Dynamo: дирижёр для инференса на целый дата-центр 🎻🖥️

Ну чё, малютки, vLLM и SGLang вы уже щупали — они шикарно гоняют модель на одной-двух видяхах. А теперь вопрос на засыпку: у тебя 64 GPU на восьми нодах, тысячи запросов в секунду, и надо чтобы всё это работало как единый организм, а не как восемь отдельных серверов, дерущихся за память. Кто этим дирижирует?

Вот тут и выходит NVIDIA Dynamo — открытый оркестратор инференса дата-центрового масштаба. Важный момент: он не заменяет vLLM, TensorRT-LLM или SGLang, а превращает их в единую скоординированную систему на много нод.

🔥Суть за 10 секунд

Dynamo — это слой над движками инференса. Сами движки оптимизируют одну ноду, а Dynamo раскидывает запросы по кластеру: маршрутизирует с учётом KV-кэша, разносит фазы prefill и decode по разным пулам GPU, гоняет KV-кэш между GPU/CPU/SSD и авто-масштабирует под SLA. Ядро на Rust, обвязка на Python, лицензия Apache 2.0.

Apache 2.0Лицензия

Полностью открыто, без вендор-лока. Бэкенды — vLLM, TensorRT-LLM, SGLang.

Rust + PythonСтек

Ядро на Rust ради скорости (~52% кода), Python для расширяемости. Немного Go для Kubernetes.

до 7×Throughput

NVIDIA заявляет до 7× пропускной способности на GPU (DeepSeek R1) и 2× быстрее TTFT за счёт KV-aware роутинга.


Зачем он нужен

Движок инференса (vLLM и ко.) живёт в рамках одной ноды. Как только тебе нужен кластер — вылезают проблемы, которые движок в одиночку не решает:

1Куда слать запрос? Если на одной ноде уже посчитан KV-кэш для этого префикса — глупо считать его заново на другой.
2Prefill и decode конфликтуют. Prefill жрёт вычисления, decode — память. На одних и тех же GPU они мешают друг другу.
3Сколько GPU выделить? Нагрузка скачет, а реплики надо поднимать/гасить под SLA, а не на глазок.
4Куда девать KV-кэш, когда он не влезает в HBM? (Привет, моя статья про KV-кэш.)

Dynamo берёт эти задачи на себя. Один движок — это музыкант; Dynamo — дирижёр, который заставляет весь оркестр играть в такт.


Как устроен: архитектура

Dynamo — это набор слабосвязанных компонентов. Вот основной поток:

Запрос проходит через Frontend и Router, дальше — раздельные пулы prefill и decode; KVBM держит KV-кэш через все уровни памяти, Planner масштабирует пулы.

Ключевые детали по компонентам:

1Frontend — HTTP-сервер с OpenAI-совместимым API. То, куда стучится твой клиент.
2Router — маршрутизатор с KV-aware логикой: учитывает загрузку воркеров и пересечение по KV-кэшу.
3Disaggregated Prefill/Decode — фазы разнесены по независимым пулам GPU и масштабируются отдельно.
4KVBM (KV Block Manager) — выгружает KV-кэш по уровням: GPU → CPU → SSD → удалённое хранилище.
5Planner — автоскейлер под SLA: профилирует нагрузку и подбирает размер пулов (NVIDIA заявляет −80% нарушений SLA).
6ModelExpress + NIXL — стриминг весов и передача KV-кэша между нодами по NVLink/сети (до 7× быстрее старт реплики).

Как обрабатывается запрос

Самое интересное — disaggregated serving. В обычном движке одна группа GPU делает и prefill (обработать промпт, набить KV-кэш), и decode (генерить токены). Dynamo разносит это на два пула, а KV-кэш между ними передаёт по NIXL:

Disaggregated serving: prefill считается на одном пуле, KV-кэш переезжает на decode-пул, который стримит токены. Фазы масштабируются независимо.

Зачем так? Потому что prefill compute-bound, а decode memory-bound (подробно — в моей статье про KV-кэш). Когда они на одних GPU, то мешают друг другу. Разнеси их — и каждый пул масштабируется под свою нагрузку. Хочешь больше длинных промптов — добавь prefill-воркеров, не трогая decode.


KV-aware роутинг: главная фишка

Router не раскидывает запросы вслепую. Если несколько запросов делят общий префикс (один системный промпт, один документ в RAG), то KV-кэш для него уже посчитан на каком-то воркере. KV-aware роутер шлёт запрос именно туда — и prefill для общей части пропускается.

Покрути — сравни round-robin и KV-aware на одном потоке запросов:

🎯 KV-aware роутинг vs round-robin
Запросы с одинаковым префиксом (буква/цвет — общий системный промпт или документ). Round-robin раскидывает их вслепую, KV-aware шлёт туда, где префикс уже в KV-кэше — попадание = пропускаем prefill = быстрее TTFT.
A
B
A
C
A
B
C
A
🔁 Round-robin
Воркер 1 · пересчёт
A
Воркер 2
Воркер 3
0%попаданий в кэш
✅ KV-aware
Воркер 1 · пересчёт
A
Воркер 2
Воркер 3
0%попаданий в кэш
Запрос 1/8

Видишь разницу в проценте попаданий? Каждое попадание — это пропущенный prefill, то есть меньше задержка до первого токена. Отсюда заявленные 2× быстрее TTFT.


Куда девается KV-кэш: KVBM

KV-кэш на длинном контексте не влезает в дорогую GPU-память (HBM). KVBM делает то же, что ОС с виртуальной памятью — раскладывает кэш по уровням, от быстрого к ёмкому:

KVBM держит горячий кэш в HBM, а холодный вытесняет вниз по иерархии — освобождая GPU-память под активные запросы.

Так на одни и те же GPU влезает больше параллельных запросов и более длинные контексты — кэш не выбрасывается, а откладывается «пониже» и подтягивается обратно при необходимости.


Остальные компоненты

🗓️Planner — следит за SLA и сам решает, сколько prefill/decode воркеров поднять под текущую нагрузку.
🚀ModelExpress — стримит веса модели по NIXL/NVLink, чтобы новая реплика стартовала за секунды, а не минуты.
☸️Grove — Kubernetes-оператор для topology-aware планирования (раскладка с учётом топологии сети/GPU).
🧪AIConfigurator — симулирует 10K+ конфигов развёртывания за секунды, чтобы подобрать оптимальную раскладку.

Как запустить

Минимальный старт — через готовый контейнер с SGLang-бэкендом:

docker run --gpus all --network host --rm -it \
  nvcr.io/nvidia/ai-dynamo/sglang-runtime:1.2.1

# внутри контейнера: фронтенд + воркер
python3 -m dynamo.frontend --http-port 8000 --discovery-backend file &
python3 -m dynamo.sglang --model-path Qwen/Qwen3-0.6B \
  --discovery-backend file &

# проверка
curl -s localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"Qwen/Qwen3-0.6B","messages":[{"role":"user","content":"Hello!"}]}'

Или поставить из PyPI (выбрав бэкенд):

uv pip install --prerelease=allow "ai-dynamo[sglang]"
Когда это вообще надо

Если у тебя одна GPU — Dynamo не нужен, бери чистый vLLM/SGLang. Dynamo начинает окупаться на кластере: когда запросов много, контексты длинные, надо разносить prefill/decode и держать SLA при минимуме железа. Для прода на десятках GPU — мастхэв; для домашней RTX — оверкилл.


Где это в стеке

Чтобы уложить в голове: движок (vLLM/TRT-LLM/SGLang) гоняет модель на ноде, а Dynamo сидит над ними и дирижирует кластером.

Dynamo — слой оркестрации над движками инференса, а те уже крутят модель на конкретных GPU.

Если хочешь понять сами движки — у меня есть большой гайд по движкам инференса, а про KV-кэш, вокруг которого вся эта оркестрация и пляшет, — отдельная статья.


TL;DR

1Что это: открытый (Apache 2.0) оркестратор инференса от NVIDIA, слой над vLLM/TRT-LLM/SGLang
2Зачем: координация инференса на кластере — роутинг, масштабирование, память
3Как: KV-aware роутинг, disaggregated prefill/decode, KVBM (GPU→CPU→SSD), Planner-автоскейлер, ядро на Rust
4Кому: тем, кто крутит LLM на многих GPU/нодах под SLA; для одной видяхи — лишнее

Тренд очевиден: инференс перестаёт быть «запустил модель на сервере» и становится распределённой системой со своим дирижёром. Dynamo — открытый способ этого дирижёра потрогать. 🫡