FinCodeCow

Масштабирование разделённых фаз prefill и decode для инференса

От интерференции и KV-кэша до гетерогенных кластеров и адаптивной маршрутизации на масштабе сотен тысяч GPU
Об источнике

Настоящий материал представляет собой обзор семнадцатой главы книги Chris Fregly, «AI Systems Performance Engineering: Optimizing Model Training and Inference Workloads with GPUs, CUDA, and PyTorch», O'Reilly Media, 2026 (Copyright © 2026 Flux Capacitor, LLC).

Прямые цитаты из книги выделены отдельными блоками с пометкой «Цитата из книги». Остальной текст — систематизированное изложение содержания главы, сопоставление с актуальными данными, проверка прогнозов, а также технические детали, выходящие за пределы исходного текста и основанные на официальной документации и открытых источниках. Цитаты приводятся в ограниченном объёме в целях обзора и критического анализа.

Процесс вывода большой языковой модели естественным образом распадается на две принципиально разные фазы: prefill и decode. Разделив их физически, можно одновременно оптимизировать время до первого токена (TTFT) и время на один выходной токен (TPOT) — то, что в монолитной архитектуре недостижимо. Эта глава — систематический разбор того, как проектировать, эксплуатировать и масштабировать разделённый prefill/decode инференс на масштабе ультрабольших кластеров.

• • •

IВведение и исторический контекст

Цитата из книги · Глава 17

«В конце 2024 года китайский стартап DeepSeek.AI поразил AI-сообщество, обучив фронтирную большую языковую модель без доступа к самым современным GPU NVIDIA. Из-за экспортных ограничений инженеры DeepSeek не могли получить топовые ускорители Blackwell или Hopper, поэтому использовали локально доступные альтернативы, включая NVIDIA H800. Они применили собственные ядра и продвинутые методы оптимизации, чтобы выжать максимум из менее производительного железа».

Процесс вывода LLM распадается на два этапа. Prefill принимает входной запрос целиком и формирует KV-кэш для всей последовательности. Decode порождает выходные токены по одному (или небольшими группами при спекулятивном декодировании), опираясь на уже сформированный KV-кэш.

Эти фазы обладают диаметрально противоположными профилями производительности. Prefill — вычислительно тяжёлая операция с интенсивной работой тензорных ядер; она ограничена FLOPS. Decode — ограничен пропускной способностью памяти: для каждого нового токена приходится перечитывать огромный KV-кэш и дописывать в него новые значения. Проще говоря, prefill — высокопараллельная задача с упором на пропускную способность, тогда как decode — последовательный процесс, критичный к задержкам.

Первые системы обслуживания LLM обрабатывали обе фазы в едином конвейере на одном оборудовании. Такой подход отдавал приоритет prefill, поскольку позволял максимизировать пропускную способность за счёт батчинга. Однако с ростом популярности интерактивных приложений на первый план вышли TTFT и TPOT. Обеспечить одновременную оптимизацию обоих в едином движке на одном GPU крайне затруднительно.

Понимание того, что prefill и decode имеют разные ресурсные профили, возникло не одномоментно. Уже в 2023 году практика непрерывного батчирования, популяризированная системой Orca и затем vLLM, показала: совмещение фаз на одном GPU создаёт «пузыри» — decode-последовательности простаивают, пока GPU обрабатывает тяжёлый prefill. Первые экспериментальные системы — Splitwise (Microsoft Research, 2024) и DistServe (2024) — независимо показали, что физическое разделение фаз на разные пулы GPU даёт двукратное и более улучшение goodput при тех же SLO. К 2025 году практически все крупные фреймворки — vLLM, SGLang, TensorRT-LLM, NVIDIA Dynamo — встроили поддержку disaggregated prefill/decode как первоклассную возможность. К 2026 году подход стал стандартом де-факто для инференса в масштабе сотен тысяч GPU.

Разделение фаз означает закрепление каждой фазы за специализированными ресурсами, оптимизированными под её нужды. DistServe показала потенциал обслуживания в 7,4 раза большего числа запросов в рамках строгих SLO по задержке по сравнению с монолитным решением. С тех пор промышленные фреймворки начали массово внедрять отдельные серверы для prefill и decode.

Открытая библиотека vLLM внедрила поддержку раздельного режима совместно с LMCache. NVIDIA Dynamo реализует disaggregated prefill и decode с динамической маршрутизацией и автомасштабированием. По сообщениям, масштабные сервисные системы OpenAI, Meta и xAI используют этот подход для соблюдения жёстких SLO по задержке. В ультрамасштабных развёртываниях речь может идти о сотнях тысяч или даже миллионах GPU, обслуживающих миллиарды запросов. В таких условиях выгода от разделения становится колоссальной.

IIЗачем разделять prefill и decode

Современные интерактивные сервисы на базе LLM зачастую ставят целью обеспечить задержку TTFT < 200–300 мс на уровне p99. Без разделения prefill-вычислений гарантировать это практически невозможно.

Рассмотрим сценарий: один пользователь отправляет запрос с чрезвычайно длинным промптом в несколько тысяч токенов, другой — с очень коротким. Без разделения, если эти запросы приходят одновременно, вычисление prefill для длинного промпта надолго займёт GPU. Второму запросу придётся ждать неоправданно долго, прежде чем начнётся его декодирование. Это явление называется интерференцией: работа по prefill одного запроса задерживает декодирование другого.

Рисунок 1. Интерференция prefill и decode

Prefill (compute-bound) и decode (memory-bound) борются за один GPU → decode задерживается

Один GPU — колокация фаз PREFILL — long prompt (compute) DECODE — token stream (memory) Таймлайн декодера ← stall из-за чужого prefill ← stall из-за чужого prefill head-of-line blocking → p99 TTFT/TPOT деградирует
Prefill-нагрузка блокирует decode-поток на одном GPU

При простой стратегии FIFO длинные промпты усиливают хвостовую задержку для всех. Тяжёлые prefill-задачи в начале очереди блокируют более лёгкие запросы позади — это блокировка начала очереди (head-of-line blocking), ведущая к низкой утилизации, выбросам задержки и недовольству пользователей.

В разделённой архитектуре можно направить prefill большого промпта в выделенный пул вычислительно-оптимизированных prefill-воркеров, а prefill лёгкого промпта — напрямую декодерам. Такая гибкость не даёт коротким запросам страдать от head-of-line blocking.

IIIКоличественная оценка интерференции

В монолитной системе, обслуживающей модель Llama-3.1-70B на одном H100 SXM5, типичное время prefill для промпта из 2048 токенов — около 150–250 мс. За это время все decode-потоки на этом GPU замораживаются. Если одновременно в батче 32 активные decode-последовательности с целевым TPOT 20 мс, каждая получает «паузу» до 250 мс — задержку в 12,5 раз больше целевой. В p99 это всплеск с 20 мс до 250+ мс, что нарушает SLO для подавляющего большинства активных запросов.

В разделённой системе тот же prefill выполняется на выделенном GPU, не затрагивая decode-пул. TPOT активных последовательностей остаётся стабильным — единственная добавка — время передачи KV-кэша от prefill-воркера к decode-воркеру.

Рисунок 2. Colocated vs Disaggregated

Goodput в пределах SLO: P90 TTFT ≤ 0,4 с, P90 TPOT ≤ 0,04 с

RPS config SLO Colocated (1× GPU) TTFT 3 TPOT 1.6 Disaggregated 2P1D (3× GPU) Prefill 5.6 Decode 10 3.3 RPS/GPU ↑ goodput ×2 при том же latency-SLO
Goodput в пределах SLO: колокация vs разделение

Здесь SLO установлен на уровне 0,4 с для P90 TTFT и 0,04 с для P90 TPOT. Совмещённая система способна поддерживать лишь около 3 RPS полезной пропускной способности в границах TTFT и только 1,6 RPS в границах TPOT. Goodput совмещённой конфигурации — 1,6 RPS. После разделения (2 prefill + 1 decode) prefill-воркеры дают ~5,6 RPS, decode — ~10 RPS. Goodput конфигурации 2P1D — 3,3 RPS на GPU — двукратный рост.

Устранение интерференции не только улучшает средние задержки, но и сжимает хвосты. Эмпирически разделённые системы демонстрируют более плотное распределение задержек и избегают длинных хвостов, характерных для монолитных систем.

IVПулы prefill- и decode-воркеров

В разделённом развёртывании поддерживаются два (или более) пула воркеров: один набор GPU выделен под обработку промптов (prefill), другой — под генерацию токенов (decode). Эти воркеры могут располагаться на отдельных узлах или стойках — или даже в разных дата-центрах, если пропускная способность межсоединений достаточна.

Пулы общаются по сети для передачи KV-кэша, сформированного prefill-воркером, тому GPU, который будет выполнять декодирование. Этой коммуникацией управляет планировщик, или маршрутизатор.

Обычно эти две группы воркеров взаимодействуют через высокоскоростные межсоединения (NVLink/NVSwitch и InfiniBand) и zero-copy передачи GPU-to-GPU с использованием RDMA. На практике такие передачи задействуют GPUDirect RDMA или UCX. Для NVL-фабрик на базе суперчипов (Grace-Blackwell, Vera-Rubin) используют NVIDIA Multi-Node NVLink (MNNVL), держат NVLink-first коллективы включёнными для TP-декодирования и включают SHARP для коллективов AllGather и ReduceScatter.

Когда система получает новый запрос, обычно он принимается на decode-воркере. Это decode-центричный дизайн. Он предпочтителен, поскольку prefill-воркеры уже загружены вычислениями KV. Перекладывая на decode-воркеры клиентский ввод-вывод, маршрутизацию и управление состоянием сессии, система избегает перегрузки prefill-воркеров.

Альтернативный дизайн

Другой подход — выделенный централизованный API-роутер, направляющий запрос либо prefill-, либо decode-воркеру. Третий — реализованный в llm-d — использует шлюз kgateway на базе Envoy AI Gateway, который перехватывает запросы и направляет их в пулы prefill и decode через Kubernetes-оператор.

Ниже приведён фрагмент упрощённой конфигурации кластера NVIDIA Dynamo, определяющей две роли, использующие NVIDIA Inference Xfer Library (NIXL) для передачи KV-кэша через GPUDirect RDMA:

roles:
  - name: prefill_worker
    model_path: models/llm-70b
    instance_count: 4
    gpu_type: B200
  - name: decode_worker
    model_path: models/llm-70b
    instance_count: 8
    gpu_type: B300

NVIDIA Rubin CPX (CP = context processing) специально спроектирован под вычислительно-тяжёлые задачи — такие как prefill. Он знаменует отход NVIDIA от универсальных ускорителей к специализированным чипам, оптимизированным под конкретную фазу AI-нагрузки.

Внутри, когда система работает, каждый decode-воркер регистрирует область GPU-памяти, чтобы prefill-воркеры могли писать в неё напрямую через RDMA. Метаданные регистрации обмениваются при старте или первом контакте — так, для каждой удалённой prefill-задачи достаточно передать лишь небольшой идентификатор.

Dynamo использует etcd для обнаружения воркеров и аренды. Воркеры регистрируют дескрипторы памяти в роутере, чтобы пиры могли получить их при необходимости. Так prefill-запрос может содержать лишь ID целевого KV-буфера.

VПередача KV-кэша

Критический вопрос: сколько фактически времени занимает передача KV-кэша между prefill- и decode-воркерами? Без этих чисел невозможно осознанно выбрать порог PREFILL_LENGTH_THRESHOLD, при котором передача становится выгодной.

Размер KV-кэша для одного запроса вычисляется по формуле:

KV_размер = 2 × n_layers × n_kv_heads × head_dim
           × bytes_per_element × n_tokens
МодельТочность1024 токена4096 токенов8192 токена
Llama-3.1-8B (GQA, 8 KV heads)FP16128 МБ512 МБ1024 МБ
Llama-3.1-70B (GQA, 8 KV heads)FP16320 МБ1280 МБ2560 МБ
Llama-3.1-70B (GQA, 8 KV heads)FP8160 МБ640 МБ1280 МБ
DeepSeek-R1 671B (MLA, FP8)FP870 МБ280 МБ560 МБ

Для DeepSeek-R1 с MLA размер KV-кэша определяется латентным представлением: 61 слой × (512 латент + 64 RoPE) × 1 байт ≈ 35 КБ/токен. Даже в FP16 это ~68,6 КБ/токен — примерно в 40 раз меньше, чем у Llama-70B с GQA.

Время передачи зависит от доступной пропускной способности сети:

ТранспортПропускная способностьЗадержкаGPUDirect
InfiniBand RDMA20–50 ГБ/с~1 мксДа
RoCE RDMA10–25 ГБ/с~2 мксДа
AWS EFA + libfabric~9,6 ГБ/с~5 мксДа
TCP (fallback)~1 ГБ/с~50 мксНет

Для Llama-3.1-70B в FP8 и промпта из 1024 токенов (KV ~160 МБ) передача через InfiniBand RDMA занимает 3–6 мс. Через TCP — около 170 мс. Эмпирические данные из продакшена подтверждают: на AWS p5.48xlarge для Llama-3.1-8B при длине входа 8000 токенов накладные расходы на передачу KV — всего ~37 мс, при том что disaggregated режим дал 41% ускорение на токен и 22% рост пропускной способности.

Рисунок 3. Передача KV-кэша через NIXL

PagedAttention блоки коалесцируются в ~128-токеновые страницы → RDMA / NVLink

PREFILL WORKER Compute KV attention block 16-token pages → coalesce NIXL · GPUDirect RDMA / NVLink zero-copy · non-blocking DECODE WORKER KV Blocks allocated in HBM decode stream → tokens ✓ handle-обмен на старте · ✓ collated payload · ✓ overlap с compute
KV-кэш передаётся напрямую через NIXL без участия CPU
Практическое правило

Передача оправдана, когда время удалённого prefill плюс время передачи KV-кэша меньше времени локального prefill на decode-воркере. Для моделей 70B+ с длинными промптами (>256 токенов после учёта prefix-кэша) и InfiniBand/RDMA-сетью передача почти всегда выгодна. Для моделей 4B и меньше либо при отсутствии RDMA — почти никогда.

Сравнение движков передачи KV-кэша

Бенчмарки на AMD MI300X (400 Гбит/с NIC) показали следующие результаты для передачи 1 ГБ данных:

ДвижокВремя (1 ГБ)Пропускная способностьРасход GPU SM
UCCL P2P~205 мс~4,9 ГБ/сНет
NIXL~216 мс~4,6 ГБ/сНет
NCCL/RCCL~300 мс~3,3 ГБ/сДа
Mooncake TE~298 мс~3,5 ГБ/сНет

NIXL и UCCL P2P достигают наилучших результатов для типичных размеров KV-кэша (256 КБ – 1 МБ), поскольку не расходуют GPU SM на передачу — данные идут напрямую через GPUDirect RDMA.

VIПроектирование prefill-воркеров

Prefill-воркеры — вычислительные узлы, предназначенные для выполнения начальной фазы. Поскольку prefill-нагрузка вычислительно интенсивна, prefill-узлы должны использовать GPU с высокой вычислительной мощностью и быть оптимизированы под крупные матричные умножения.

Рисунок 4. Конвейер prefill-воркера

read prefix-cache → compute prefill → write KV blocks обратно декодеру

Queue prefill tasks Prefix Cache reuse PREFILL compute-bound GEMM · attention KV → Decode via NIXL Non-blocking: prefill не держит KV в своей HBM — сразу передаёт его декодеру
Prefill-воркер читает prefix-cache, вычисляет KV и сразу отправляет его декодеру

Управление памятью

Prefill заполняет память GPU параметрами модели и рабочими активациями прямого прохода с входными токенами промпта. Как только KV-кэш создан, он немедленно отправляется decode-воркерам. KV-кэш не задерживается надолго в памяти prefill-узла. Некоторые фреймворки предварительно резервируют большой блок GPU-памяти под prefill как рабочее пространство — это снижает фрагментацию и время на выделение буферов.

Оптимизация под задержку или пропускную способность

При настройке разделённого prefill-кластера возникает фундаментальный компромисс между минимизацией TTFT для каждого отдельного промпта и максимизацией общего RPS.

Подход «сначала задержка». Чтобы сократить TTFT, prefill-узлы обрабатывают промпты сразу по мере поступления — с минимальным батчированием или без него. Недостаток — более низкая утилизация GPU. Можно либо избыточно зарезервировать ёмкость, либо использовать размер батча, равный 1.

Подход «сначала пропускная способность». Объединение промптов в крупные батчи (8–32) повышает арифметическую интенсивность и загружает вычислительные блоки. Недостаток — каждый запрос несёт задержку батчирования, равную времени сбора батча.

Многие inference-движки отдают предпочтение задержке для prefill-воркеров: быстрый первый токен значительно улучшает UX. Обычно для prefill-кластера резервируют больше ёмкости, чем нужно для средней нагрузки — так он поглощает всплески промптов без скачков задержки.

Планирование и батчирование с учётом задержек

Разделённые системы применяют политики планирования с учётом задержек: гарантируют выполнение одиночного запроса, пока нагрузка не станет достаточно высокой, применяют адаптивные окна батчирования (при низкой нагрузке — батч 1, при высокой — микробатчи 2–10 мс), используют очереди приоритетов для коротких промптов. NVIDIA Dynamo поддерживает классы задержки в планировании.

VIIПроектирование decode-воркеров

Decode-воркеры предназначены для авторегрессионной фазы декодирования. Как только KV-кэш промпта готов, он передаётся decode-воркеру, который использует его для генерации оставшихся выходных токенов как можно быстрее, чтобы поддерживать низкую задержку TPOT.

Если запрос изначально направляется decode-воркеру, он решает, выполнять prefill локально или удалённо. Prefill-воркер непрерывно забирает задачи из очереди prefill, читает KV-блоки из prefix-кэша и выполняет prefill. Затем записывает KV-блоки обратно decode-воркеру.

Непрерывное батчирование

Decode-серверы активно полагаются на непрерывное батчирование. В отличие от prefill-фазы, выполняющей крупные матрично-матричные вычисления, фаза декодирования выполняет множество малых вычислений. Чтобы избежать низкой утилизации GPU, decode-воркеры объединяют несколько входных последовательностей, формируя более крупные матрично-матричные вычисления на каждой итерации.

Например, если 32 различных запроса готовы сгенерировать следующий токен, планировщик непрерывного батчирования выполнит один прямой проход, генерирующий 32 токена параллельно. Так матричные умножения получают эффективный размер батча 32.

Непрерывное батчирование гарантирует, что decode-GPU-воркеры не простаивают. Они всегда работают над доступными запросами. При высокой нагрузке оно эффективно, при низкой — отзывчиво. Это хороший баланс между высокой пропускной способностью и низкой задержкой.

Группировка последовательностей переменной длины

Обработка последовательностей переменной длины требует тщательного планирования. Смешивание коротких и длинных промптов в одном батче ведёт к накладным расходам на padding — иногда до 50% от числа токенов. Решение — группировать запросы в корзины по длине последовательности. Более продвинутый подход — Flash Attention с интерфейсом переменной длины (varlen), упаковывающий все последовательности в один непрерывный тензор с метаданными кумулятивных длин. Это полностью устраняет padding (экономия до 63%) и сокращает число запусков ядер с N до 1 на каждый слой внимания.

NVIDIA Programmatic Dependent Launch (PDL) и device-initiated CUDA Graph Launch используются для снижения накладных расходов на запуск на каждом токене, перекрытия работы и устранения пузырей между итерациями декодирования.

Управление памятью под KV-кэш

Поскольку декодирование включает внимание ко всей последовательности, память под KV-кэш — критичный ресурс для decode-воркеров. Для больших моделей и длинных последовательностей память KV растёт линейно с числом токенов.

Практическая оценка: байт_на_токен = 2 × n_layers × n_kv_heads × head_dim × байт_на_элемент.

Для модели класса Llama 13B с 40 слоями, 40 головами внимания и FP16 при контексте 4096 токенов со стандартным MHA размер KV составляет ~0,819 МБ/токен или ~3,36 ГБ всего. При KV в FP8 — ~1,68 ГБ. При GQA с 8 группами запросов — ~0,671 ГБ в FP16 и ~0,336 ГБ в FP8. Для MQA с 1 KV-головой — ~0,084 ГБ в FP16.

Paged GPU memory allocator. Механизм PagedAttention в vLLM разбивает KV-кэш на страницы фиксированного размера и может выгружать неактивные страницы в память CPU. Менеджеры paged KV-памяти реализованы в SGLang, TensorRT-LLM, NVIDIA Dynamo.

Выгрузка KV-кэша. Когда GPU-память заполняется, decode-воркеры могут выгружать более старые KV-блоки в CPU DRAM или NVMe. NVIDIA Dynamo реализует многоуровневое управление через KV Block Manager (KVBM). В сценарии с 20 многоходовыми диалогами и 15 пользователями KVBM с выгрузкой в CPU-память дал улучшение TTFT в 2,2–12 раз.

Иерархия памяти в разделённой архитектуре

GPU-память decode-кластера полностью посвящена хранению весов модели и KV-кэша. Она не пытается обрабатывать крупные вычисления prefill промптов. Разделение не устраняет проблемы памяти KV, но позволяет выбирать типы decode-узлов, оптимизированные под ёмкость памяти и пропускную способность.

VIIIМаршрутизация и планирование

Не каждый запрос нужно передавать prefill-воркеру. Разделённая система использует политику маршрутизации, чтобы условно использовать удалённый путь prefill только тогда, когда это вероятно поможет.

Стратегия маршрутизацииОписание
Round robinНаправляет по одному узлу по очереди
Least requestsНаправляет воркеру с наименьшим числом активных запросов
Prefix awareИспользует префикс запроса для выбора воркера
KV awareНаправляет воркеру, чей KV-кэш лучше всего соответствует запросу

Факторы маршрутизации

ФакторОписаниеВлияние
Длина промптаЧисло токенов после prefix-кэшированияДлинные → передавать; короткие → локально
Попадание в prefix-кэшСтепень, в которой промпт уже в KV-кэшеБольшое → локально; нет → передача выгодна
Длина очереди prefillЧисло ожидающих задачДлинная → избегать передачи
Нагрузка decodeТекущая нагрузка на локальный воркерЗанятый → передача помогает
Срочность по SLOПриоритет или жёсткость требованияСрочное → немедленно передать

Рисунок 5. KV-aware маршрутизация запросов

Роутер получает KV-cache events и направляет запрос туда, где префикс уже в памяти

request KV Router prefix-cache events queue · load · SLO Worker 1 HIT (90%) Worker 2 cache miss Remote prefill dispatch Логика: длинный эффективный префикс → локально; miss + long prompt → offload
KV-aware маршрутизация учитывает попадание в prefix-кэш

Пример политики динамической маршрутизации

На практике политика маршрутизации реализуется как условная проверка. Ниже — упрощённая версия логики маршрутизации:

def should_offload_prefill(prompt_length: int,
                           prefix_cached_length: int,
                           prefill_queue_size: int,
                           decode_active_reqs: int,
                           ttft_slo_ms: int = 500) -> bool:
    eff_len = max(0, prompt_length - prefix_cached_length)

    PREFILL_LENGTH_THRESHOLD = 256
    PREFILL_QUEUE_MAX = 10
    DECODE_LOAD_THRESHOLD = 8

    long_prefill = (eff_len >= PREFILL_LENGTH_THRESHOLD)
    prefill_available = (prefill_queue_size < PREFILL_QUEUE_MAX)

    if long_prefill and prefill_available:
        return True

    if decode_active_reqs >= DECODE_LOAD_THRESHOLD and eff_len >= 64:
        return True

    return False

Пример конфигурации Dynamo Planner

В производственном развёртывании политику маршрутизации следует настраивать через файл. NVIDIA Dynamo позволяет задавать сложные правила маршрутизации и автомасштабирования в JSON или YAML:

model: ...
split_policy:
  prompt_length_threshold: 256
  prefix_cache_weight: 10.0
  queue_length_weight: 1.5
  decode_load_weight: 0.5
  enable_hotspot_prevention: true
cache:
  reuse_prefix: true
  min_cache_hit_ratio: 0.75
autoscale:
  prefill:
    min_replicas: 4
    max_replicas: 12
    scale_up:   { queue_length: 8,  gpu_utilization: 80 }
    scale_down: { queue_length: 2,  gpu_utilization: 40 }
  decode:
    min_replicas: 8
    max_replicas: 24
    scale_up:   { queue_length: 16, kv_cache_usage: 75 }
    scale_down: { queue_length: 4,  kv_cache_usage: 30 }
qos:
  enable_early_rejection: true
  low_priority_threshold_ms: 500
  reject_on_slo_violation: true

Маршрутизация с учётом ёмкости и задержек

Dynamo Planner использует метрики вроде TTFT, TPOT и оценённой стоимости передачи KV-кэша для решения об изменении маршрутизации — или даже о перераспределении GPU для конкретной фазы. При наплыве задач суммаризации Planner перераспределит больше GPU в фазу prefill. При наплыве reasoning-задач — в фазу decode.

Рисунок 6. Dynamo GPU Planner

По метрикам (TTFT/TPOT, GPU util, queue depth) планировщик перераспределяет GPU между prefill и decode

Dynamo Planner observe · predict · reallocate Metrics TTFT · TPOT · util queue · KV usage PREFILL POOL DECODE POOL Influx scenario → summarization → больше prefill Reasoning scenario → big output → больше decode
Dynamo Planner перераспределяет GPU между фазами по метрикам

KV-aware маршрутизация: результаты из продакшена

NVIDIA Dynamo сообщает 3-кратное улучшение TTFT и 2-кратное снижение средней задержки запроса при маршрутизации 100 000 реальных запросов к DeepSeek-R1 Distilled Llama 70B (FP8, 2 узла H100) с учётом KV-кэша по сравнению со случайной маршрутизацией. Проект llm-d на B200 сообщает о 3-кратном росте выходной пропускной способности и 2-кратном ускорении TTFT с prefix-cache-aware маршрутизацией.

IXМногопутевое спекулятивное декодирование

Спекулятивное декодирование может быть наложено поверх процесса принятия решений роутером. Система может обнаружить неопределённую ветвь спекулятивного декодирования и отправить несколько спекулятивных запросов разным decode-воркерам параллельно. Это обменивает дополнительные вычисления на более низкую задержку для генераций с непредсказуемыми ветвями.

Адаптивное спекулятивное декодирование. Система StreamServe (2026) объединила disaggregated prefill/decode с адаптивным спекулятивным декодированием, глубина которого настраивается онлайн на основе runtime-метрик. На бенчмарках StreamShow показал снижение задержки на 11–18% относительно tensor-parallel vLLM и прирост пропускной способности до 6,8% при стабильном TPOT. Взаимодействие между disaggregation, metric-aware routing и adaptive speculation даёт сверхаддитивный эффект.

В практическом плане спекулятивное декодирование через EAGLE-3 может давать до 6× ускорения на плотных моделях. Однако при constrained decoding (JSON mode, tool calls с грамматиками) acceptance rate часто резко падает, поскольку constraint mask инвалидирует спекулятивные токены. Это важно учитывать при планировании нагрузки в разделённом кластере.

XQoS и политики раннего отклонения

Политики QoS приоритизируют или ограничивают определённые запросы для соблюдения целей по задержке. Раннее отклонение, также называемое контролем допуска, может отказать в низкоприоритетных запросах, когда система насыщена. Так сохраняются ресурсы и SLO для других запросов.

Современные системы делают это на основе порога времени в очереди. Если запрос пробыл в очереди > X мс, возможно, лучше отклонить его, чем допустить серьёзное нарушение SLO. Такой QoS-барьер становится всё более распространённым для критически важных систем инференса.

В ультрамасштабных системах механизмы QoS необходимы для поддержания гарантий хвостовой задержки под тяжёлой нагрузкой. Вместо того чтобы позволить нарушение SLO для всех запросов, хорошо спроектированная система предпочтёт изящно сбросить нагрузку: отклонив или отложив низкоприоритетные запросы, когда ясно, что их обслуживание нарушит гарантии для других.

Контроль допуска

class QoSController:
    def __init__(self, ttft_slo_ms: int = 500):
        self.ttft_slo_ms = ttft_slo_ms

    def admit_request(self, priority: str) -> bool:
        est_ttft = (get_current_prefill_queue_length()
                    * get_avg_prefill_time_per_req()
                    + get_current_decode_queue_length()
                    * get_avg_decode_time_per_req())

        if est_ttft > self.ttft_slo_ms and priority == "low":
            return False
        return True

Адаптивные лимиты генерации. Если фаза decode угрожает затянуться слишком долго и вызвать нарушение SLO по TPOT, система может досрочно прервать генерацию. Если пользователь запросил 1000 токенов, но система под давлением, она может разрешить только 200 токенов, оставляя ресурсы для других запросов.

Изящная деградация. Одна из интересных форм — временное отключение удалённого prefill для низкоприоритетных запросов, когда система под нагрузкой. Низкоприоритетные запросы выполняют локальный prefill, освобождая prefill-воркеры для высокоприоритетных.

Отказоустойчивость и хвостовая задержка

По мере масштабирования систем до тысяч и миллионов GPU-узлов становится труднее контролировать хвостовую задержку. Изоляция prefill-задач на одном узле, а decode-задач на другом означает, что медленный узел с одной стороны не окажет резкого влияния на задачи с другой стороны. Кэширование больших частей контекста означает, что одна медленная операция не замедлит всю генерацию так сильно.

XIГетерогенные кластеры

Одно из самых мощных следствий disaggregation — возможность использовать разные типы GPU для prefill и decode, подбирая оборудование под ресурсный профиль каждой фазы.

Экономическое обоснование

Prefill — compute-bound: нужен максимум FP8/FP4 TFLOPS, ёмкость HBM не критична. Decode — memory-bound: нужна максимальная пропускная способность HBM, вычислительная мощность почти не используется. Это создаёт неэффективность: использовать H100 (стоимость ~$2,57/час за GPU) для decode — значит платить примерно в 3,6 раза больше за пропускную способность памяти, которая вам не нужна. L40S (стоимость ~$0,72/час) имеет достаточную пропускную способность HBM для decode моделей 70B и стоит в 3,5 раза дешевле.

КонфигурацияGPUСтоимость/часПропускная способностьСтоимость 1M токенов
Однородная4× H100 SXM5$10,283200 tok/s$0,89
Гетерогенная 11× H100 + 2× L40S$4,012400 tok/s$0,46
Гетерогенная 22× H100 + 4× A100$9,304800 tok/s$0,54

Гетерогенная конфигурация 1 (H100 для prefill + L40S для decode) экономит 61% на почасовой стоимости и снижает цену за 1M токенов на 48% — при снижении пропускной способности на 25%. Для моделей до 70B это наиболее рентабельная пара. Для моделей 70B–405B лучше подходит связка B200 + A100 80G.

Когда гетерогенность оправдана

  1. Модель крупная (32B+). Для моделей меньше 10B накладные расходы на передачу KV-кэша перевешивают выгоды.
  2. Нагрузка несбалансированная. Преобладание длинных промптов или длинных ответов.
  3. Доступны разные типы GPU. В облаке — разные инстанс-типы; в on-premise — смешанный парк.
  4. RDMA-инфраструктура доступна. Без RDMA гетерогенность теряет смысл.

Архитектурные паттерны

«Вычислительный prefill + бюджетный decode» — prefill на H100/B200, decode на L40S/A100. Роутер Dynamo направляет prefill на вычислительный пул, KV-кэш передаётся через NIXL/RDMA на decode-пул.

«Перекрёстное перемешивание» (work stealing) — реализован в HeteroServe. Когда consumer-GPU простаивают, они временно забирают decode-задачи у других воркеров, восстанавливая простаивающую ёмкость.

«Спотовые GPU с on-demand fallback» — ShuntServe. Decode на дешёвых spot-инстансах, при отзыве — переключение на on-demand. DP-оптимизатор на основе roofline-модели находит оптимальное размещение слоёв. Достигается 1,42× более высокая пропускная способность на Llama-3.1-70B.

«GPU Combo» — Cauchy. Концептуальная «GPU-комбинация» выбирается для каждого типа нагрузки на основе cost-efficiency.

Перспективы: специализированные чипы

Работа DUET (2026) предлагает аппаратное разделение на уровне чипов: «Prefill Chips» с увеличенными систолическими массивами и GDDR7 вместо HBM, и «Decode Chips» с сохранением высокой пропускной способности, но сокращённой вычислительной мощности. Отчёты показывают: 8% выше prefill-производительность при 52% меньшей стоимости для Prefill Chips, и 97% decode-производительности при 28% меньшем TDP для Decode Chips — относительно смоделированных H100.

XIIРеальные бенчмарки

DistServe (прототип, 2024)

Базовый эксперимент показал: goodput совмещённой конфигурации — 1,6 RPS на GPU; разделённой 2P1D — 3,3 RPS на GPU (2,1× улучшение) при строгих SLO.

SGLang + DeepSeek-R1 (96× H100, 2025)

PD-дезагрегация с экспертным параллелизмом: 52,3k входных токенов/с на узел prefill (24 GPU), 22,3k выходных токенов/с на узел decode (72 GPU). На GB200 NVL72 — до 3,8× для prefill и 4,8× для decode по сравнению с H100-конфигурацией.

NVIDIA Dynamo (H100, 2025–2026)

  • Одноузловой тест (Llama 70B, FP8, vLLM): 30% рост пропускной способности на GPU.
  • Двухузловой тест: более 2× прирост.
  • KV-aware маршрутизация (100k запросов, DeepSeek-R1 Distilled 70B): 3× TTFT, 2× средняя задержка.
  • GTC 2026 (Dynamo 1.0 на GB200 NVL72 + wide EP): 7× пропускная способность.

llm-d (B200, 2025–2026)

  • 3× выходная пропускная способность и 2× быстрее TTFT с prefix-cache-aware routing.
  • До 70% больше токенов/с с P/D disaggregation vs стандартный vLLM.
  • ~3,1k tok/s на B200 decode GPU (wide-EP).
  • До 50k выходных tok/s на топологии 16×16 B200.
  • 40% снижение задержки на выходной токен для DeepSeek V3.1 на H200.

AWS EFA + libfabric (H100, 2025)

Измеренные накладные расходы на передачу KV-кэша для Llama-3.1-8B (ISL=8000, OSL=50): всего 37 мс (TTFT: aggregated 173 мс vs disaggregated 210 мс). При этом disaggregated режим даёт 41% ускорение на токен и 22% рост пропускной способности.

XIIIПрактические рекомендации

  • Оптимизируйте каждую фазу независимо. Prefill ограничен вычислениями и выигрывает от максимального параллелизма и высокой вычислительной мощности. Decode ограничен памятью и выигрывает от GPU с высокой пропускной способностью памяти и непрерывного батчирования.
  • Используйте KV-кэш. Умный роутер решает, должен ли новый запрос быть передан prefill-воркеру или обработан локально. Политика должна учитывать длину промпта, попадания в кэш и загрузку кластера.
  • Маршрутизируйте разумно. vLLM, SGLang и NVIDIA Dynamo используют многофакторный алгоритм оценки. Отслеживайте TTFT (p50/p95/p99) и ITL/TPOT (p50/p95/p99) отдельно для prefill- и decode-узлов.
  • Используйте QoS для поддержания SLA при масштабе. Применяйте контроль допуска и приоритизацию под тяжёлой нагрузкой.
  • Начинайте с агрегированного baseline. Прежде чем внедрять disaggregation, измерьте производительность монолитной конфигурации.
  • Проверяйте RDMA. Без RDMA disaggregation практически неприменима. Перед запуском в продакшен валидируйте NIXL-бенчмарком.
  • Рассмотрите гетерогенность для снижения затрат. Для моделей 32B+ с несбалансированной нагрузкой связка H100/B200 для prefill и L40S/A100 для decode может дать 30–60% экономии.

XIVБудущие направления

Дезагрегированная квантизация. Использование разных форматов квантизации для prefill (аппаратно-нативный NVFP4) и decode (weight-only 2–3 бита) с совместной оптимизацией весов. QADD показал прирост точности на decode-задачах при сохранении скорости prefill — до 1,49× ускорения над BF16 на Qwen3-8B и Gemma3-12B.

Адаптивное спекулятивное декодирование. Объединение disaggregation с онлайн-настройкой глубины спекуляции на основе runtime-метрик. StreamServe показал сверхаддитивный эффект от этого сочетания.

Специализированные чипы для фаз. Проекты вроде DUET предлагают чипы, спроектированные исключительно под prefill или decode, с разной архитектурой памяти и вычислительных блоков.

Дезагрегация для диффузионных LLM. Prefilling-dLLM расширяет disaggregation на диффузионные языковые модели, кэшируя chunked prefix KV один раз и переиспользуя его между шагами денойзинга. На LongBench и Infinitebench — ускорение 9,1–28,0× при контекстах 8K–32K.

Мультимодальная дезагрегация. Расширение на трёхфазную архитектуру: encode (визионный энкодер) → prefill (языковой prefill) → decode. NVIDIA Dynamo уже поддерживает disaggregated encode/prefill/decode с кэшем эмбеддингов — 30% быстрее TTFT на image-нагрузках.

XVЗаключение

Разделение prefill и decode стало обычной практикой в современном высокомасштабном LLM-инференсе. Практически все крупные AI-провайдеры — Meta, Amazon, NVIDIA, Google и OpenAI — в той или иной форме внедрили разделённую архитектуру в своих крупномасштабных развёртываниях LLM.

Хотя большинство этих компаний не публикуют свою полную производственную архитектуру, существует множество открытых реализаций — vLLM, SGLang, NVIDIA Dynamo, llm-d, LMCache, Mooncake — которые демонстрируют этот подход и его преимущества. Разделённый prefill-decode даёт более высокий goodput — полезную пропускную способность в рамках ограничений по задержке — и лучшую экономическую эффективность, чем монолитные дизайны.

Спустя 18 месяцев после выхода DistServe концепция эволюционировала от небольшого прототипа до фундаментальной техники, питающей практически каждый современный inference-движок.

Итог

Разделение фаз prefill и decode — не конечная точка, а платформа для дальнейших оптимизаций: дезагрегированной квантизации, адаптивного спекулятивного декодирования, специализированных чипов, мультимодальной дезагрегации. Каждый уровень даёт свой прирост, и правильный порядок шагов — профилирование, KV-кэш, маршрутизация, QoS, гетерогенность — важнее отдельной «серебряной пули».

FinCodeCow

Scaling Disaggregated Prefill and Decode for Inference

From interference and KV cache to heterogeneous clusters and adaptive routing at the scale of hundreds of thousands of GPUs
About the source

This material is a review of Chapter 17 of Chris Fregly, «AI Systems Performance Engineering: Optimizing Model Training and Inference Workloads with GPUs, CUDA, and PyTorch», O'Reilly Media, 2026 (Copyright © 2026 Flux Capacitor, LLC).

Direct quotes from the book are marked with separate blocks labeled «Quote from the book». The rest of the text is a systematized exposition of the chapter's content, a comparison with current data, forecast verification, and technical details beyond the original text based on official documentation and open sources. Quotes are provided in limited volume for review and critical analysis purposes.

LLM inference naturally splits into two fundamentally different phases: prefill and decode. Separating them physically allows you to optimize both Time To First Token (TTFT) and Time Per Output Token (TPOT) simultaneously — something monolithic architectures cannot achieve. This chapter is a systematic examination of how to design, operate, and scale disaggregated prefill/decode inference at the scale of ultra-large clusters.

• • •

IIntroduction and Historical Context

Quote from the book · Chapter 17

«In late 2024, the Chinese startup DeepSeek.AI stunned the AI community by training a frontier large language model without access to NVIDIA's most advanced GPUs. Due to export restrictions, DeepSeek's engineers could not obtain top-tier Blackwell or Hopper accelerators, so they used locally available alternatives, including the NVIDIA H800. They applied custom kernels and advanced optimization techniques to squeeze maximum performance out of less capable hardware».

LLM inference splits into two stages. Prefill accepts the input request in full and forms the KV cache for the entire sequence. Decode generates output tokens one at a time (or in small groups with speculative decoding), relying on the already formed KV cache.

These phases have diametrically opposite performance profiles. Prefill is a compute-heavy operation with intensive Tensor Core work; it is FLOPS-bound. Decode is memory-bandwidth-bound: for every new token, the huge KV cache must be re-read and new values appended. In short, prefill is a highly parallel throughput-oriented task, while decode is a sequential latency-critical process.

The first LLM serving systems processed both phases in a single pipeline on the same hardware. That approach prioritized prefill, as it maximized throughput through request batching. However, with the rise of interactive applications, TTFT and TPOT moved to the foreground. Simultaneously optimizing both in a single engine on one GPU is extremely challenging.

The realization that prefill and decode have different resource profiles emerged gradually. As early as 2023, continuous batching — popularized by Orca and then vLLM — showed that co-locating phases on one GPU creates "bubbles": decode sequences idle while the GPU processes a heavy prefill. The first experimental systems — Splitwise (Microsoft Research, 2024) and DistServe (2024) — independently showed that physically separating phases into different GPU pools yields 2× or more goodput improvement at the same SLO. By 2025, virtually every major framework — vLLM, SGLang, TensorRT-LLM, NVIDIA Dynamo — had built disaggregated prefill/decode support as a first-class feature. By 2026, the approach became the de-facto standard for inference at the scale of hundreds of thousands of GPUs.

Disaggregation means assigning each phase to specialized resources optimized for its needs. DistServe demonstrated the potential to serve 7.4× more requests within strict latency SLOs compared to the monolithic solution of its time. Since then, production frameworks have mass-adopted separate servers for prefill and decode.

The open-source vLLM library added split-mode support together with LMCache. NVIDIA Dynamo implements disaggregated prefill and decode with dynamic routing and autoscaling. Large-scale serving systems at OpenAI, Meta, and xAI are reported to use this approach to meet strict latency SLOs. At ultra-scale deployments, this can mean hundreds of thousands or even millions of GPUs serving billions of requests. Under those conditions, the benefit of disaggregation becomes enormous.

IIWhy Disaggregate Prefill and Decode

Modern interactive LLM services often target p99 TTFT < 200–300 ms. Without prefill disaggregation, guaranteeing this is practically impossible.

Consider a scenario: one user sends a request with an extremely long prompt of several thousand tokens, another with a very short one. Without disaggregation, if these arrive at the same time, computing the prefill for the long prompt occupies the GPU for a long time. The second request must wait unjustifiably long before its decode begins. This phenomenon is called interference: prefill work for one request delays decoding for another.

Figure 1. Prefill/Decode Interference

Prefill (compute-bound) and decode (memory-bound) fight over one GPU → decode is delayed

One GPU — Colocated Phases PREFILL — long prompt (compute) DECODE — token stream (memory) Decoder Timeline ← stall from foreign prefill ← stall from foreign prefill head-of-line blocking → p99 TTFT/TPOT degrades
Prefill load blocks the decode stream on one GPU

With a simple FIFO strategy, long prompts exacerbate tail latency for everyone. Heavy prefill tasks at the head of the queue block lighter requests behind them — head-of-line blocking, leading to low utilization, latency spikes, and user frustration.

In a disaggregated architecture, you can route the prefill of a large prompt to a dedicated pool of compute-optimized prefill workers, and the prefill of a light prompt directly to decoders. This flexibility prevents short requests from suffering head-of-line blocking.

IIIQuantifying Interference

In a monolithic system serving Llama-3.1-70B on one H100 SXM5, typical prefill time for a 2048-token prompt is 150–250 ms. During this time, all decode streams on that GPU freeze. With 32 active decode sequences targeting 20 ms TPOT, each gets a "pause" of up to 250 ms — a delay 12.5× the target. At p99, this is a spike from 20 ms to 250+ ms, violating SLOs for the vast majority of active requests.

In a disaggregated system, the same prefill runs on a dedicated GPU without touching the decode pool. TPOT of active sequences remains stable — the only addition is KV cache transfer time from the prefill worker to the decode worker.

Figure 2. Colocated vs Disaggregated

Goodput within SLO: P90 TTFT ≤ 0.4 s, P90 TPOT ≤ 0.04 s

RPS config SLO Colocated (1× GPU) TTFT 3 TPOT 1.6 Disaggregated 2P1D (3× GPU) Prefill 5.6 Decode 10 3.3 RPS/GPU ↑ 2× goodput at the same latency SLO
Goodput within SLO: colocation vs disaggregation

Here SLO is 0.4 s for P90 TTFT and 0.04 s for P90 TPOT. The colocated system sustains only ~3 RPS of useful throughput within the TTFT bound and only 1.6 RPS within the TPOT bound. Goodput of the colocated configuration is 1.6 RPS. After disaggregation (2 prefill + 1 decode), prefill workers give ~5.6 RPS, decode ~10 RPS. Goodput of the 2P1D configuration is 3.3 RPS per GPU — a 2× improvement.

Eliminating interference not only improves average latencies but also tightens tails. Empirically, disaggregated systems show tighter latency distributions and avoid the long tails characteristic of monolithic systems.

IVPrefill and Decode Worker Pools

In a disaggregated deployment, two (or more) worker pools are maintained: one set of GPUs is dedicated to prompt processing (prefill), another to token generation (decode). These workers may sit on separate nodes or racks — or even in different data centers if interconnect bandwidth is sufficient.

The pools communicate over the network to transfer the KV cache formed by the prefill worker to the GPU that will perform decoding. This communication is managed by a scheduler or router.

Typically, the two worker groups interact over high-speed interconnects (NVLink/NVSwitch and InfiniBand) and zero-copy GPU-to-GPU transfers using RDMA. In practice, these transfers leverage GPUDirect RDMA or UCX. For NVL-fabrics based on superchips (Grace-Blackwell, Vera-Rubin), use NVIDIA Multi-Node NVLink (MNNVL), keep NVLink-first collectives enabled for TP-decode, and enable SHARP for AllGather and ReduceScatter collectives.

When the system receives a new request, it is usually admitted on a decode worker. This is the decode-centric design. It is preferable because prefill workers are already busy computing KV. By pushing client I/O, routing, and session state management onto decode workers, the system avoids overloading prefill workers.

Alternative design

Another approach is a dedicated centralized API router that directs the request either to a prefill or a decode worker. A third — implemented in llm-d — uses the kgateway Envoy AI Gateway, which intercepts requests and routes them to prefill and decode pools via a Kubernetes operator.

Below is an excerpt of a simplified NVIDIA Dynamo cluster configuration defining two roles that use NVIDIA Inference Xfer Library (NIXL) for KV cache transfer over GPUDirect RDMA:

roles:
  - name: prefill_worker
    model_path: models/llm-70b
    instance_count: 4
    gpu_type: B200
  - name: decode_worker
    model_path: models/llm-70b
    instance_count: 8
    gpu_type: B300

NVIDIA Rubin CPX (CP = context processing) is specifically designed for compute-heavy tasks like prefill. It marks NVIDIA's shift from universal compute accelerators to specialized chips optimized for a specific AI phase.

Inside a running system, each decode worker registers a region of GPU memory so prefill workers can write to it directly via RDMA. Registration metadata is exchanged at startup or first contact — so for each remote prefill task, only a small ID needs to be sent.

Dynamo uses etcd for worker discovery and leases. Workers register memory descriptors in the router so peers can fetch them as needed. A prefill request can thus carry only the target KV buffer ID.

VKV Cache Transfer

A critical question: how much time does KV cache transfer actually take between prefill and decode workers? Without these numbers, you cannot consciously choose PREFILL_LENGTH_THRESHOLD at which transfer becomes worthwhile.

KV cache size per request is computed as:

KV_size = 2 × n_layers × n_kv_heads × head_dim
        × bytes_per_element × n_tokens
ModelPrecision1024 tokens4096 tokens8192 tokens
Llama-3.1-8B (GQA, 8 KV heads)FP16128 MB512 MB1024 MB
Llama-3.1-70B (GQA, 8 KV heads)FP16320 MB1280 MB2560 MB
Llama-3.1-70B (GQA, 8 KV heads)FP8160 MB640 MB1280 MB
DeepSeek-R1 671B (MLA, FP8)FP870 MB280 MB560 MB

For DeepSeek-R1 with MLA, KV cache size is determined by the latent representation: 61 layers × (512 latent + 64 RoPE) × 1 byte ≈ 35 KB/token. Even in FP16 it is ~68.6 KB/token — roughly 40× smaller than Llama-70B with GQA.

Transfer time depends on available network bandwidth:

TransportBandwidthLatencyGPUDirect
InfiniBand RDMA20–50 GB/s~1 µsYes
RoCE RDMA10–25 GB/s~2 µsYes
AWS EFA + libfabric~9.6 GB/s~5 µsYes
TCP (fallback)~1 GB/s~50 µsNo

For Llama-3.1-70B in FP8 with a 1024-token prompt (KV ~160 MB), transfer over InfiniBand RDMA takes 3–6 ms. Over TCP — about 170 ms. Production data confirms this: on AWS p5.48xlarge for Llama-3.1-8B with an 8000-token input length, KV transfer overhead was only ~37 ms, while the disaggregated regime gave 41% per-token speedup and 22% throughput increase.

Figure 3. KV Cache Transfer via NIXL

PagedAttention blocks coalesce into ~128-token pages → RDMA / NVLink

PREFILL WORKER Compute KV attention block 16-token pages → coalesce NIXL · GPUDirect RDMA / NVLink zero-copy · non-blocking DECODE WORKER KV Blocks allocated in HBM decode stream → tokens ✓ handle exchange at startup · ✓ collated payload · ✓ overlapped with compute
KV cache transferred directly via NIXL without CPU involvement
Rule of thumb

Transfer is justified when remote prefill time plus KV transfer time is less than local prefill on the decode worker. For models 70B+ with long prompts (>256 tokens after prefix caching) and InfiniBand/RDMA network, transfer is almost always beneficial. For models 4B and under or without RDMA — almost never.

Comparison of KV transfer engines

Benchmarks on AMD MI300X (400 Gbit/s NIC) produced the following results for transferring 1 GB of data:

EngineTime (1 GB)BandwidthGPU SM usage
UCCL P2P~205 ms~4.9 GB/sNo
NIXL~216 ms~4.6 GB/sNo
NCCL/RCCL~300 ms~3.3 GB/sYes
Mooncake TE~298 ms~3.5 GB/sNo

NIXL and UCCL P2P achieve the best results for typical KV cache sizes (256 KB – 1 MB) because they do not consume GPU SMs for transfer — data flows directly through GPUDirect RDMA.

VIDesigning Prefill Workers

Prefill workers are compute nodes designed for the initial phase. Since prefill load is compute-intensive, prefill nodes should use GPUs with high compute power and be optimized for large matrix multiplications.

Figure 4. Prefill Worker Pipeline

read prefix-cache → compute prefill → write KV blocks back to decoder

Queue prefill tasks Prefix Cache reuse PREFILL compute-bound GEMM · attention KV → Decode via NIXL Non-blocking: prefill does not hold KV in its HBM — passes it to the decoder immediately
Prefill worker reads prefix-cache, computes KV, and forwards it to the decoder

Memory management

Prefill fills GPU memory with model parameters and forward-pass activations. Once the KV cache is created, it is immediately sent to decode workers. The KV cache does not linger in prefill node memory. Some frameworks pre-reserve a large GPU memory block as a workspace — reducing fragmentation and buffer allocation time.

Latency-first vs throughput-first

Configuring a disaggregated prefill cluster involves a fundamental trade-off between minimizing TTFT for each prompt and maximizing overall RPS.

Latency-first approach. To cut TTFT, prefill nodes process prompts immediately as they arrive — with minimal or no batching. The downside is lower GPU utilization. You can either overprovision capacity or use batch size 1.

Throughput-first approach. Combining prompts into larger batches (8–32) increases arithmetic intensity and loads compute units. The downside is that each request incurs a batching delay equal to the time to collect the batch.

Many inference engines favor latency for prefill workers: a fast first token significantly improves UX. Prefill clusters are usually overprovisioned relative to average load — so they absorb prompt bursts without latency spikes.

Latency-aware scheduling and batching

Disaggregated systems apply latency-aware scheduling policies: they guarantee single-request execution until load is high enough, use adaptive batching windows (batch 1 at low load, microbatch 2–10 ms at high load), and use priority queues for short prompts. NVIDIA Dynamo supports latency classes in scheduling.

VIIDesigning Decode Workers

Decode workers are designed for the autoregressive decoding phase. Once the prompt's KV cache is ready, it is passed to a decode worker, which uses it to generate remaining output tokens as quickly as possible to keep TPOT low.

If a request is initially routed to a decode worker, it decides whether to run prefill locally or remotely. The prefill worker continuously pulls tasks from the prefill queue, reads KV blocks from the prefix cache, and performs prefill. It then writes KV blocks back to the decode worker.

Continuous batching

Decode servers rely heavily on continuous batching. Unlike prefill, which performs large matrix-matrix computations, the decode phase performs many small computations. To avoid low GPU utilization, decode workers combine several input sequences into larger matrix-matrix computations on each iteration.

For example, if 32 different requests are ready to generate the next token, the continuous batching scheduler performs a single forward pass generating 32 tokens in parallel. This gives matmuls an effective batch size of 32.

Continuous batching keeps decode GPU workers busy. At high load it is efficient; at low load it is responsive. That is a good balance between high throughput and low latency.

Batching variable-length sequences

Handling variable-length sequences requires careful planning. Mixing short and long prompts in one batch leads to padding overhead — sometimes up to 50% of tokens. The solution is to bucket requests by sequence length. A more advanced approach is Flash Attention with a variable-length (varlen) interface, packing all sequences into one contiguous tensor with cumulative-length metadata. This eliminates padding entirely (up to 63% savings) and reduces the number of kernel launches from N to 1 per attention layer.

NVIDIA Programmatic Dependent Launch (PDL) and device-initiated CUDA Graph Launch reduce per-token launch overhead, overlap work, and eliminate bubbles between decode iterations.

KV cache memory management

Because decoding involves attention over the entire sequence, KV cache memory is a critical resource for decode workers. For large models and long sequences, KV memory grows linearly with the number of tokens.

Practical estimate: bytes_per_token = 2 × n_layers × n_kv_heads × head_dim × bytes_per_element.

For a Llama 13B-class model with 40 layers, 40 attention heads, FP16, at 4096-token context with standard MHA, KV size is ~0.819 MB/token or ~3.36 GB total. With FP8 KV — ~1.68 GB. With GQA of 8 query groups — ~0.671 GB in FP16 and ~0.336 GB in FP8. For MQA with 1 KV head — ~0.084 GB in FP16.

Paged GPU memory allocator. vLLM's PagedAttention splits the KV cache into fixed-size pages and can offload inactive pages to CPU memory. Paged KV memory managers are implemented in SGLang, TensorRT-LLM, and NVIDIA Dynamo.

KV cache offloading. When GPU memory fills up, decode workers can offload older KV blocks to CPU DRAM or NVMe. NVIDIA Dynamo implements multi-tier management via KV Block Manager (KVBM). In a scenario with 20 multi-turn conversations and 15 users, KVBM with CPU offload gave 2.2–12× TTFT improvement.

Memory hierarchy in disaggregated architecture

The decode cluster's GPU memory is entirely dedicated to holding model weights and KV cache. It is not trying to handle large prefill prompt computations. Disaggregation does not eliminate KV memory issues, but it allows choosing decode node types optimized for memory capacity and bandwidth.

VIIIRouting and Scheduling

Not every request must be passed to a prefill worker. A disaggregated system uses a routing policy to conditionally use the remote prefill path only when it is likely to help.

Routing strategyDescription
Round robinDirects to one node in turn
Least requestsDirects to the worker with the fewest active requests
Prefix awareUses request prefix to select a worker
KV awareDirects to the worker whose KV cache best matches the request

Routing factors

FactorDescriptionEffect
Prompt lengthToken count after prefix cachingLong → offload; short → local
Prefix cache hitDegree to which prompt is already in KV cacheLarge → local; none → offload helps
Prefill queue lengthNumber of pending tasksLong → avoid offload
Decode loadCurrent load on the local workerBusy → offload helps
SLO urgencyPriority or strictness of the requirementUrgent → dispatch immediately

Figure 5. KV-Aware Request Routing

The router receives KV cache events and routes the request where the prefix is already in memory

request KV Router prefix-cache events queue · load · SLO Worker 1 HIT (90%) Worker 2 cache miss Remote prefill dispatch Logic: long effective prefix → local; miss + long prompt → offload
KV-aware routing accounts for prefix cache hits

Dynamic routing policy example

In practice, the routing policy is implemented as a conditional check. Below is a simplified version of the routing logic:

def should_offload_prefill(prompt_length: int,
                           prefix_cached_length: int,
                           prefill_queue_size: int,
                           decode_active_reqs: int,
                           ttft_slo_ms: int = 500) -> bool:
    eff_len = max(0, prompt_length - prefix_cached_length)

    PREFILL_LENGTH_THRESHOLD = 256
    PREFILL_QUEUE_MAX = 10
    DECODE_LOAD_THRESHOLD = 8

    long_prefill = (eff_len >= PREFILL_LENGTH_THRESHOLD)
    prefill_available = (prefill_queue_size < PREFILL_QUEUE_MAX)

    if long_prefill and prefill_available:
        return True

    if decode_active_reqs >= DECODE_LOAD_THRESHOLD and eff_len >= 64:
        return True

    return False

Dynamo Planner configuration example

In a production deployment, the routing policy should be configured through a file. NVIDIA Dynamo allows complex routing and autoscaling rules in JSON or YAML:

model: ...
split_policy:
  prompt_length_threshold: 256
  prefix_cache_weight: 10.0
  queue_length_weight: 1.5
  decode_load_weight: 0.5
  enable_hotspot_prevention: true
cache:
  reuse_prefix: true
  min_cache_hit_ratio: 0.75
autoscale:
  prefill:
    min_replicas: 4
    max_replicas: 12
    scale_up:   { queue_length: 8,  gpu_utilization: 80 }
    scale_down: { queue_length: 2,  gpu_utilization: 40 }
  decode:
    min_replicas: 8
    max_replicas: 24
    scale_up:   { queue_length: 16, kv_cache_usage: 75 }
    scale_down: { queue_length: 4,  kv_cache_usage: 30 }
qos:
  enable_early_rejection: true
  low_priority_threshold_ms: 500
  reject_on_slo_violation: true

Capacity-aware and latency-aware routing

Dynamo Planner uses metrics such as TTFT, TPOT, and estimated KV transfer cost to decide whether to change routing — or even reassign GPUs for a specific phase. When summarization tasks surge, Planner reassigns more GPUs to prefill. When reasoning tasks surge, it moves them to decode.

Figure 6. Dynamo GPU Planner

Based on metrics (TTFT/TPOT, GPU util, queue depth), the planner reallocates GPUs between prefill and decode

Dynamo Planner observe · predict · reallocate Metrics TTFT · TPOT · util queue · KV usage PREFILL POOL DECODE POOL Influx scenario → summarization → more prefill Reasoning scenario → big output → more decode
Dynamo Planner reallocates GPUs between phases based on metrics

KV-aware routing: production results

NVIDIA Dynamo reports 3× TTFT improvement and 2× reduction in average request latency when routing 100,000 real requests to DeepSeek-R1 Distilled Llama 70B (FP8, 2× H100 nodes) with KV cache awareness compared to random routing. The llm-d project on B200 reports 3× output throughput and 2× TTFT speedup with prefix-cache-aware routing.

IXMulti-Path Speculative Decoding

Speculative decoding can be layered on top of the router's decision process. The system might detect an uncertain branch and send several speculative requests to different decode workers in parallel, trading extra compute for lower latency on unpredictable generation branches.

Adaptive speculative decoding. StreamServe (2026) combined disaggregated prefill/decode with adaptive speculative decoding whose depth is tuned online based on runtime metrics. On StreamShow benchmarks it showed 11–18% latency reduction vs tensor-parallel vLLM and up to 6.8% throughput improvement while keeping TPOT stable. The interaction between disaggregation, metric-aware routing, and adaptive speculation is super-additive.

In practice, speculative decoding via EAGLE-3 can yield up to 6× speedup on dense models. However, with constrained decoding (JSON mode, tool calls with grammars), acceptance rate often drops sharply because the constraint mask invalidates speculative tokens. This must be factored in when planning load in a disaggregated cluster.

XQoS and Early Rejection

QoS policies prioritize or restrict certain requests to meet latency goals. Early rejection — also called admission control — can refuse low-priority requests when the system is saturated. This preserves resources and SLOs for other requests.

Modern systems do this based on a queue time threshold. If a request has waited > X ms, it may be better to reject it than to allow a serious SLO violation. Such a QoS barrier is becoming increasingly common for critical inference systems.

At ultra-scale, QoS mechanisms are necessary to maintain tail latency guarantees under heavy load. Instead of allowing SLO violation for all requests, a well-designed system prefers graceful load shedding: rejecting or deferring low-priority requests when it is clear that serving them would violate guarantees for others.

Admission control

class QoSController:
    def __init__(self, ttft_slo_ms: int = 500):
        self.ttft_slo_ms = ttft_slo_ms

    def admit_request(self, priority: str) -> bool:
        est_ttft = (get_current_prefill_queue_length()
                    * get_avg_prefill_time_per_req()
                    + get_current_decode_queue_length()
                    * get_avg_decode_time_per_req())

        if est_ttft > self.ttft_slo_ms and priority == "low":
            return False
        return True

Adaptive generation limits. If the decode phase threatens to take too long and violate the TPOT SLO, the system can terminate generation early. If the user requested 1000 tokens but the system is under pressure, it may allow only 200 tokens, preserving resources for other requests.

Graceful degradation. One interesting form is temporarily disabling remote prefill for low-priority requests when the system is under load. Low-priority requests do local prefill, freeing prefill workers for high-priority ones.

Fault tolerance and tail latency

As systems scale to thousands and millions of GPU nodes, controlling tail latency becomes harder. Isolating prefill tasks on one node and decode tasks on another means a slow node on one side does not sharply affect tasks on the other side. Caching large parts of the context means one slow operation does not slow the whole generation as much.

XIHeterogeneous Clusters

One of the most powerful consequences of disaggregation is the ability to use different GPU types for prefill and decode, matching hardware to each phase's resource profile.

Economic rationale

Prefill is compute-bound: it needs maximum FP8/FP4 TFLOPS; HBM capacity is not critical. Decode is memory-bound: it needs maximum HBM bandwidth; compute power is barely used. This creates inefficiency: using an H100 (~$2.57/hour per GPU) for decode means paying roughly 3.6× more for memory bandwidth you do not need. The L40S (~$0.72/hour) has sufficient HBM bandwidth for decode of 70B models and is 3.5× cheaper.

ConfigurationGPUCost/hourThroughputCost per 1M tokens
Homogeneous4× H100 SXM5$10.283200 tok/s$0.89
Heterogeneous 11× H100 + 2× L40S$4.012400 tok/s$0.46
Heterogeneous 22× H100 + 4× A100$9.304800 tok/s$0.54

Heterogeneous configuration 1 (H100 for prefill + L40S for decode) saves 61% on hourly cost and reduces cost per 1M tokens by 48% — while reducing throughput by 25%. For models up to 70B this is the most cost-effective pairing. For 70B–405B models, B200 + A100 80G works better.

When heterogeneity is justified

  1. Large model (32B+). For models under 10B, KV transfer overhead outweighs the benefits.
  2. Unbalanced workload. Predominance of long prompts or long responses.
  3. Different GPU types available. In cloud — different instance types; on-prem — a mixed fleet.
  4. RDMA infrastructure available. Without RDMA, heterogeneity loses meaning.

Architectural patterns

"Compute prefill + budget decode" — prefill on H100/B200, decode on L40S/A100. Dynamo router sends prefill to the compute pool, KV cache transfers via NIXL/RDMA to the decode pool.

"Work stealing" — implemented in HeteroServe. When consumer GPUs idle, they temporarily take decode tasks from other workers, restoring idle capacity.

"Spot GPUs with on-demand fallback" — ShuntServe. Decode on cheap spot instances; on revocation, fall back to on-demand. A DP-optimizer based on a roofline model finds optimal layer placement. Achieves 1.42× higher throughput on Llama-3.1-70B.

"GPU Combo" — Cauchy. A conceptual "GPU combination" is chosen for each workload class based on cost-efficiency.

Future: phase-specialized chips

The DUET (2026) work proposes chip-level hardware partitioning: "Prefill Chips" with enlarged systolic arrays and GDDR7 instead of HBM, and "Decode Chips" retaining high bandwidth but reduced compute power. Reports show 8% higher prefill performance at 52% lower cost for Prefill Chips, and 97% decode performance at 28% lower TDP for Decode Chips — relative to modeled H100s.

XIIProduction Benchmarks

DistServe (prototype, 2024)

The baseline experiment showed: goodput of the colocated configuration — 1.6 RPS per GPU; disaggregated 2P1D — 3.3 RPS per GPU (2.1× improvement) under strict SLOs.

SGLang + DeepSeek-R1 (96× H100, 2025)

PD disaggregation with expert parallelism: 52.3k input tokens/s per prefill node (24 GPUs), 22.3k output tokens/s per decode node (72 GPUs). On GB200 NVL72 — up to 3.8× for prefill and 4.8× for decode vs an H100 configuration.

NVIDIA Dynamo (H100, 2025–2026)

  • Single-node test (Llama 70B, FP8, vLLM): 30% per-GPU throughput gain.
  • Two-node test: over 2× improvement.
  • KV-aware routing (100k requests, DeepSeek-R1 Distilled 70B): 3× TTFT, 2× average latency.
  • GTC 2026 (Dynamo 1.0 on GB200 NVL72 + wide EP): 7× throughput.

llm-d (B200, 2025–2026)

  • 3× output throughput and 2× faster TTFT with prefix-cache-aware routing.
  • Up to 70% more tokens/s with P/D disaggregation vs standard vLLM.
  • ~3.1k tok/s per B200 decode GPU (wide-EP).
  • Up to 50k output tok/s on a 16×16 B200 topology.
  • 40% reduction in per-output-token latency for DeepSeek V3.1 on H200.

AWS EFA + libfabric (H100, 2025)

Measured KV transfer overhead for Llama-3.1-8B (ISL=8000, OSL=50): only 37 ms (TTFT: aggregated 173 ms vs disaggregated 210 ms). The disaggregated regime gives 41% per-token speedup and 22% throughput increase.

XIIIPractical Recommendations

  • Optimize each phase independently. Prefill is compute-bound and benefits from maximum parallelism and high compute power. Decode is memory-bound and benefits from GPUs with high memory bandwidth and continuous batching.
  • Leverage KV cache. A smart router decides whether a new request should be offloaded to a prefill worker or handled locally. The policy should account for prompt length, cache hits, and cluster load.
  • Route wisely. vLLM, SGLang, and NVIDIA Dynamo use a multi-factor scoring algorithm. Track TTFT (p50/p95/p99) and ITL/TPOT (p50/p95/p99) separately for prefill and decode nodes.
  • Use QoS to maintain SLAs at scale. Apply admission control and prioritization under heavy load.
  • Start with an aggregated baseline. Before deploying disaggregation, measure the monolithic configuration's performance.
  • Validate RDMA. Without RDMA, disaggregation is practically inapplicable. Validate with a NIXL benchmark before going to production.
  • Consider heterogeneity for cost savings. For 32B+ models with unbalanced load, the H100/B200 for prefill + L40S/A100 for decode pairing can yield 30–60% savings.

XIVFuture Directions

Disaggregated quantization. Using different quantization formats for prefill (hardware-native NVFP4) and decode (weight-only 2–3 bit) with joint weight optimization. QADD showed accuracy gains on decode tasks while preserving prefill speed — up to 1.49× speedup over BF16 on Qwen3-8B and Gemma3-12B.

Adaptive speculative decoding. Combining disaggregation with online tuning of speculation depth based on runtime metrics. StreamServe showed super-additive benefit from this combination.

Phase-specialized chips. Projects such as DUET propose chips designed exclusively for prefill or decode, with different memory architecture and compute blocks.

Disaggregation for diffusion LLMs. Prefilling-dLLM extends disaggregation to diffusion language models, caching chunked prefix KV once and reusing it across denoising steps. On LongBench and Infinitebench — 9.1–28.0× speedup at 8K–32K contexts.

Multimodal disaggregation. Extending to a three-phase architecture: encode (vision encoder) → prefill (language prefill) → decode. NVIDIA Dynamo already supports disaggregated encode/prefill/decode with embedding cache — 30% faster TTFT on image workloads.

XVConclusion

Prefill/decode disaggregation has become standard practice in modern high-scale LLM inference. Virtually all major AI providers — Meta, Amazon, NVIDIA, Google, and OpenAI — have deployed a disaggregated architecture in some form in their large-scale LLM deployments.

Although most of these companies do not publish their full production architecture, many open implementations — vLLM, SGLang, NVIDIA Dynamo, llm-d, LMCache, Mooncake — demonstrate the approach and its benefits. Disaggregated prefill-decode yields higher goodput — useful throughput within latency constraints — and better economic efficiency than monolithic designs.

Eighteen months after DistServe, the concept evolved from a small prototype to a foundational technique powering virtually every modern inference engine.

Summary

Prefill/decode disaggregation is not an endpoint but a platform for further optimizations: disaggregated quantization, adaptive speculative decoding, phase-specialized chips, multimodal disaggregation. Each layer gives its own gain, and the right order of steps — profiling, KV cache, routing, QoS, heterogeneity — matters more than any single "silver bullet".