Выигрыш IB по TTFT5,4-11,5×на валидных прогонах
IB M175/75валидных прогонов
TCP M131/75отказов, 41%
GDR write48,82GB/s, 390,56 Гбит/с
Triton TTFT-33-44%против fa4 на 2 профилях

Аннотация

В работе исследуется влияние транспорта KV-кэша на производительность и работоспособность disaggregated inference, в котором стадии prefill и decode выполняются на разных GPU-узлах. На кластере из двух узлов с восемью NVIDIA B200 на каждом сравниваются RDMA/InfiniBand с GPUDirect и TCP/Ethernet в инференсе MiniMax-M3 через sglang. Эксперимент включает четыре уровня наблюдения: потолок фабрики (L0), изолированный microbenchmark transfer engine (L0b), фактический маршрут трафика по счётчикам портов (L1) и end-to-end метрики движка и запросов (L2/L3). Всего проанализировано 268 прогонов.

В основной матрице M1 RDMA/InfiniBand уменьшил медианный TTFT в 5,4-11,5 раза и увеличил output throughput в 2,8-3,8 раза относительно TCP на валидных прогонах. TPOT оставался сопоставимым, что указывает на локализацию влияния транспорта в переходе prefill → decode, а не в самом цикле decode. TCP завершился отказом в 31 из 75 прогонов (41%); все 75 прогонов IB были валидны. По логам отказ начинается с ошибки копирования из CUDA memory (out of memory), продолжается таймаутом KV-transfer, после чего prefill завершается, а router возвращает HTTP 503. Изолированный microbenchmark воспроизвёл отказ TCP и одновременно показал преимущество GPUDirect над host staging на 6,3-6,5%.

End-to-end поток не насыщал ни одну из сетевых фабрик: TCP достигал максимум 8,7 Гбит/с из 200 Гбит/с, IB - 52,4-61,7 Гбит/с из приблизительно 2933 Гбит/с суммарного измеренного L0-потолка восьми NDR-портов. Следовательно, наблюдаемая разница объясняется прежде всего архитектурой переноса - host staging против zero-copy GPUDirect, - а не нехваткой полосы. Дополнительная верификация attention backend показала снижение TTFT на 33,5-44,4% у triton относительно fa4, однако эти пути используют разные layouts KV и требуют отдельной проверки на production-нагрузках.

Вывод: в исследованной конфигурации выбор KV-транспорта является архитектурным ограничением PD-инференса. TCP нельзя рассматривать как функционально эквивалентный fallback для тяжёлых профилей MiniMax-M3.

Ключевые слова: LLM inference, PD-disaggregation, KV-cache, RDMA, InfiniBand, GPUDirect, TCP, TTFT, sglang, MiniMax-M3.

1. Введение

Увеличение размеров языковых моделей делает полезным разделение inference pipeline на две стадии. На стадии prefill модель обрабатывает входной контекст и формирует KV-кэш attention. На стадии decode этот кэш используется для последовательной генерации выходных токенов. При PD-disaggregation стадии размещаются на разных GPU-узлах, поэтому KV-кэш пересекает границу машины.

Такое размещение меняет статус сетевого транспорта. В монолитном inference KV остаётся внутри памяти одного процесса или узла; в PD-топологии транспорт KV входит в критический путь получения первого токена. При этом пропускная способность интерфейса не описывает всю стоимость переноса: реализация может потребовать копирования данных из VRAM в host memory, дополнительных буферов и синхронизации.

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

1.1. Исследовательские вопросы

  1. Как транспорт KV влияет на TTFT, TPOT, E2E latency и throughput?

  2. При каких профилях длины входа/выхода и конкурентности TCP перестаёт быть работоспособным?

  3. Является ли причиной деградации насыщение сетевой фабрики или программный staging path?

  4. Даёт ли устойчивый выигрыш выбор backend'а переноса, микро-тюнинг mooncake или смена attention backend?

1.2. Проверяемые гипотезы

Обозначение

Гипотеза

Критерий проверки

H1

Транспорт влияет главным образом на TTFT, а не на TPOT

Сопоставление TTFT и TPOT

H2

Деградация TCP растёт с размером KV-переноса

Профили ISL/OSL и concurrency

H3

GPUDirect быстрее host staging

VRAM против DRAM в L0b

H4

TCP ограничен LACP-хэшем или полосой Ethernet

End-to-end rate против L0/L1

H5

RDMA даёт кратный выигрыш на длинных prefill

Валидные M1-прогоны

H6

fake даёт лучший TPOT, но худший TTFT (decode пересчитывает префилл)

Запуск fake backend в PD-режиме

H7

Микро-тюнинг даёт не более порядка 10%

OFAT по sglang и mooncake

H8

nixl/UCX сопоставим с mooncake на RDMA

M2 на одинаковых профилях

2. Материалы и методы

2.1. Топология эксперимента

Две машины использовались следующим образом: node-a выполняла prefill и router, node-b - decode. Каждая роль модели работала с tensor parallelism TP=8 на восьми B200. Имена узлов, адреса и имена сетевых устройств обезличены; конфигурация воспроизводима на любой паре узлов с тем же железом.

PD-disaggregation (prefill/decode disaggregation) разделяет две фазы инференса по разным GPU-узлам: prefill считает префилл промпта и владеет его KV-кэшем, decode генерирует токены, читая этот кэш. Между фазами KV-кэш (единицы-сотни МиБ на запрос) должен физически переехать с узла prefill на узел decode - этот перенос и есть предмет работы. Поскольку decode не может начать работу до переноса, латентность транспорта лежит в критическом пути TTFT, но не в цикле декодирования (TPOT), где KV читается локально из памяти своей ноды.

Топология PD-disaggregation: prefill и decode на разных TP8-узлах; после prefill KV-кэш передаётся на decode.

После завершения prefill KV-кэш передавался на decode. Сравнивались RDMA/InfiniBand через восемь NDR-портов 400G с GPUDirect и TCP/Ethernet через bond0, LACP 2 × 100G, MTU 9000.

2.2. Аппаратная и программная конфигурация

Компонент

Значение

GPU

2 узла × 8 NVIDIA B200

Модель

MiniMax-M3 MXFP8, 31 shard, 443 771 536 556 байт

Engine

sglang 0.0.0.dev1+g56e290315

MoE backend

deep_gemm

Attention backend

fa4, page size 128

KV backend M1

mooncake

RDMA

NDR 400G, HCA mlx5_4,7,8,9,10,13,14,15

Ethernet

bond0, LACP 802.3ad, 2 × 100G

CUDA / OFED

CUDA 13.0.1 / MLNX-OFED 24.10

Базовый runtime

mem-fraction-static=0.85, chunked prefill 8192, max running requests 20, lpm

Для исключения расхождения артефактов контейнер был пересобран с подавлением записи __pycache__ и очисткой TorchInductor cache. Content-addressed diffID всех 64 слоёв совпадали на обеих нодах.

2.3. Матрица нагрузок

Основная матрица M1 содержала пять профилей ISL/OSL, три уровня concurrency и пять повторов для каждого из двух транспортов.

Профиль ISL/OSL

Назначение

128/128

короткий вход и короткий выход

2048/256

базовый прикладной профиль

8192/256

длинный вход

32768/256

очень длинный вход

2048/2048

длинный вход и длинный выход

Всего M1: 5 × 3 × 5 × 2 = 150 прогонов. Дополнительно проведены M2, ось D (18 конфигураций sglang), ось C (13 конфигураций mooncake), отдельная верификация fa4/triton и L0/L0b. В summary.json - 268 записей.

2.4. Процедура и метрики

Перед стартом выполнялась жёсткая очистка контейнеров и orphan-процессов. Стек запускался в порядке prefill → decode → router. Перед измерениями выполнялись прогрев MSA JIT, HF processor и warmup-запрос. Использовались фиксированные seed=1234, num-prompts=32 и пять повторов на ячейку.

В аналитических графиках M1 валидным считался прогон с положительным TTFT выше артефактного порога и положительным output throughput. Отказы с ttft=0 не включались в медианы производительности, но учитывались отдельно в failure-rate и heatmap. Для агрегатов использовались медианы, графики показывают межквартильный разброс.

Термины адаптеров. HCA (Host Channel Adapter) - сетевой адаптер InfiniBand, ядро видит его как устройство mlx5_N. NDR = 400 Гбит/с на порт, HDR = 100 Гбит/с - поколения скорости IB. PIX-local означает, что адаптер и GPU висят под общим PCIe-switch: копия VRAM→HCA не пересекает межпроцессорную шину, что важно для GPUDirect. bond0 - агрегированный Ethernet-интерфейс узла (Linux bonding): два порта объединены по LACP 802.3ad в один логический канал 2 × 100G с MTU 9000. Счётчики bond0 и IB-портов mlx5_* независимы, поэтому по их дельтам однозначно определяется фактический маршрут KV (раздел 3.3).

Уровень

Инструмент

Наблюдаемые величины

L0

ib_write_bw, ib_write_lat

потолок фабрики, latency

L0b

transfer_engine_bench

GDR/host staging, read/write, status

L1

IB counters, bond0

дельта переданных байтов

L2

/metrics sglang

alloc/bootstrap KV-transfer

L3

bench_serving

TTFT, TPOT, ITL (inter-token latency), E2E, tok/s

L0 и L0b измеряют железо и переносчик в изоляции (L0 - полосу IB утилитой ib_write_bw независимо от sglang; L0b - transfer_engine_bench без модели). L1-L3 - end-to-end: L1 по счётчикам портов доказывает, куда пошёл байт, L2 берёт телеметрию движка, L3 - пользовательские метрики. IB-счётчики PortXmitData/PortRcvData отдаются в 4-байтных словах (×4 для байт); величины ib_tx/bond_tx - приращение за прогон (after - before), а не абсолютное значение счётчика.

3. Результаты

3.1. End-to-end сравнение транспорта

При concurrency=8 и только на валидных прогонах получены следующие медианы. Здесь TTFT - время до первого токена, TPOT - время на последующие токены.

Профиль

IB TTFT, мс

TCP TTFT, мс

Выигрыш IB

IB tok/s

TCP tok/s

Выигрыш IB

128/128

451.8

2427.8

5.4×

414.7

128.4

3.2×

2048/256

398.2

4575.5

11.5×

519.2

182.2

2.8×

8192/256

554.0

3215.5

5.8×

495.7

130.4

3.8×

Транспорт входит в TTFT через перенос KV и bootstrap, но не участвует в основном decode-цикле. Поэтому TPOT составил 10.8-11.7 мс для IB и 10.0-10.5 мс для TCP; небольшое преимущество TCP не является причинным эффектом и связано со смещением валидной выборки после исключения отказов.

GTTFT=TTFTTCPTTFTIB;Gthr=ThroughputIBThroughputTCPG_{\mathrm{TTFT}} = \frac{\mathrm{TTFT}_{\mathrm{TCP}}}{\mathrm{TTFT}_{\mathrm{IB}}};\quad G_{\mathrm{thr}} = \frac{\mathrm{Throughput}_{\mathrm{IB}}}{\mathrm{Throughput}_{\mathrm{TCP}}}
Рисунок 1. TTFT против длины входа (isl/osl). Медиана по повторам при conc=8, усы - IQR. Серии: RDMA / IB - RDMA/InfiniBand NDR 400G; TCP / Ethernet - Ethernet bond0, LACP 2 × 100G.
Рисунок 2. TPOT против длины входа (isl/osl). Медиана по повторам при conc=8. Проверка H1: транспорт не влияет на TPOT; серии обозначены как на Рисунке 1.
Рисунок 3. Пропускная способность против конкурентности: output и total tok/s для профиля 2048/256. TCP-отказы исключены из агрегатов, а не заменены нулями.
Рисунок 4. Метрики KV-transfer engine (M1, валидные прогоны, дельта за прогон): prefill - GB/s и мс/оп, decode - bootstrap, мс/оп. speed/latency/total_mb отдаёт передающая (prefill) сторона; принимающая (decode) - только bootstrap/alloc.
Рисунок 5. Выигрыш RDMA/IB относительно TCP, %. Положительное значение означает преимущество IB; conc=8.

3.2. Граница отказа TCP

Все 75 прогонов IB были валидны. Для TCP 44 из 75 прогонов были валидны, а 31 завершились отказом.

Профиль

c=1

c=8

c=32

128/128

0/5 bad

0/5 bad

0/5 bad

2048/256

0/5 bad

0/5 bad

0/5 bad

8192/256

0/5 bad

0/5 bad

1/5 bad

2048/2048

5/5 bad

5/5 bad

5/5 bad

32768/256

5/5 bad

5/5 bad

5/5 bad

plaintext
ClientSession::writeBody failed to copy from CUDA memory: out of memory
↓
KVTransferError: timeout after 300 s in KVPoll.WaitingForInput
↓
prefill: running_phase_sigquit_handler → kill_process_tree
↓
router: No available prefill workers
↓
HTTP 503

Профиль 2048/2048 ломается уже при c=1, тогда как 8192/256 выдерживает c=8. Это согласуется с зависимостью от объёма KV на запрос, а не только от concurrency. Изолированный transfer_engine_bench с TCP и VRAM-буфером воспроизвёл тот же класс отказа.

Рисунок 6. Граница отказа TCP: доля bad-прогонов (prefill мёртв, ttft=0, KVTransferError/503) по профилям и concurrency. IB - 0% на всех профилях.

3.3. Маршрут KV и утилизация фабрики

Транспорт

ib_tx

bond_tx

IB

3 654-206 714 МиБ

примерно 0-12 МиБ

TCP

0

3 642-55 158 МиБ (валидные прогоны)

В самых тяжёлых валидных TCP-прогонах скорость по bond0 составляла 7.4-8.7 Гбит/с, до 4.4% от 200 Гбит/с. Для IB максимум составлял 61,7 Гбит/с (c=32), не более 2,1% от суммарного измеренного L0-потолка восьми NDR-портов - около 2933 Гбит/с. Гипотеза о насыщении LACP-хэша не подтверждена.

Рисунок 7. Маршрут KV-трафика: дельта счётчиков портов IB (tx) и Ethernet bond (tx) за прогон, conc=8, по профилям isl/osl.

3.4. L0 и L0b: GPUDirect против host staging

Cross-node ib_write_bw на восьми рабочих NDR-портах дал среднюю скорость 366.7 Гбит/с при диапазоне 364.2-368.5 Гбит/с; latency на измеренных портах составляла 1.78-2.00 мкс.

Режим

GB/s

Гбит/с

GDR write из VRAM

48.82

390.56

host write из DRAM

45.93

367.44

GDR read из VRAM

49.00

392.00

host read из DRAM

46.01

368.08

TCP write из VRAM

FAILED

-

GDR составил 97.6% от номинальных 400 Гбит/с NDR и превысил host staging на 6.29% для write и 6.50% для read. L0 и L0b используют разные инструменты и режимы, поэтому их абсолютные значения нельзя смешивать как одно измерение.

Рисунок 8. L0: потолок NDR-фабрики по портам (ib_write_bw cross-node, 64K msg) и ориентир Ethernet bond0 (8 потоков).
Рисунок 9. L0b: mooncake transfer_engine_bench - GPUDirect (GDR) против host staging. mlx5_4, RDMA RC, block=64K, 8 каналов, cross-node node-a→node-b.

3.5. Backend переноса: mooncake и nixl

M2 проводился на IB и холодном стеке. Поэтому значения TTFT сопоставимы только между backend'ами внутри M2.

Backend

Профиль

c

TTFT, мс

TPOT, мс

Output tok/s

ib_tx, МиБ

mooncake

2048/256

8

4295.6

11.28

200.1

16 016

mooncake

2048/256

32

1344.8

13.45

749.6

16 016

mooncake

8192/256

8

3121.6

10.27

254.4

51 430

mooncake

8192/256

32

3901.3

13.10

567.7

51 430

nixl

2048/256

8

3775.9

11.37

194.4

15 862

nixl

2048/256

32

4104.7

13.33

595.8

15 862

nixl

8192/256

8

2065.4

10.64

268.4

50 938

nixl

8192/256

32

4407.6

12.19

589.2

50 938

nixl работоспособен и использует сопоставимый IB-маршрут: различие ib_tx не превышало примерно 1%. fake не может использоваться как prefill backend в PD-режиме: sglang завершается assertion в pd_disaggregation_hook.py:70.

Рисунок 10. M2: backend переноса KV - mooncake против nixl (UCX). IB, холодный стек (без прогрева), поэтому сравнение только между backend'ами внутри M2. fake недоступен для prefill (assertion pd_disaggregation_hook.py:70).

3.6. OFAT и attention backend

По оси D измерены 18 конфигураций sglang (n=2-3, с прогревом) на профиле 2048/256, c=8, IB, mooncake. Единственный выигрыш дал attention-backend triton; остальные 16 измеренных параметров базу не улучшили - их TTFT составил 435-562 мс против 418 мс у base (включая варианты max-running-req 8/16/32/64, mem-fraction 0.70-0.90, schedule-policy fcfs/random, chunked-prefill off/4096/16384, cuda-graph-* и max-total-tokens 500k). Ещё две конфигурации - cuda-graph-prefill full и attention-backend fa3 - стек не подняли (таймаут health) и в число 18 не входят. По оси C проверены 13 параметров mooncake на профиле 8192/256, c=8, IB; все рабочие варианты находились в диапазоне разброса M1, а MC_NUM_QP_PER_EP=4 приводил к зависанию decode.

Профиль

fa4 TTFT

triton TTFT

Δ TTFT

Δ throughput

2048/256

536.4 мс

298.3 мс

-44.4%

+19.9%

8192/256

578.7 мс

384.7 мс

-33.5%

+17.7%

В обоих режимах завершились 32/32 запроса. При temperature=0 два повторения детерминированного semantic check дали идентичные корректные ответы. Однако fa4 использовал page_size=128, а triton - page_size=None; результат не доказывает эквивалентность на длинных контекстах или при speculative decoding.

Рисунок 11. Ось D: полный OFAT по 18 параметрам sglang, профиль 2048/256, c=8, IB, с прогревом. Зелёное - лучше base; cold-прогоны (TTFT > 1000 мс) отброшены. cuda-graph-prefill full и attention-backend fa3 стек не подняли.
Рисунок 12. Ось C: микро-тюнинг mooncake, профиль 8192/256, c=8, IB, с прогревом. Все варианты в пределах шума M1 (413-574 мс); MC_NUM_QP_PER_EP=4 - decode зависает.
Рисунок 13. Отдельная верификация attention backend: fa4 против triton (n=3 warm, тот же стек). triton использует page_size=None (без paged-KV), ib_tx -4.2%, p99 TTFT 420 против 1619 мс; 32/32 запроса завершены в обоих режимах.

4. Обсуждение

4.1. Почему эффект транспорта виден в TTFT, но не в TPOT

В PD-disaggregation decode не может начать полноценную генерацию до получения KV-кэша. Поэтому задержка переноса прибавляется ко времени первого токена. После bootstrap decode выполняет вычисления локально; транспорт уже не участвует в каждом шаге генерации. Наблюдаемая разница - секунды по TTFT против менее 1.7 мс/токен по TPOT - соответствует этой структуре пути.

4.2. Почему скорость линии не объясняет результат

Если бы TCP упирался в физическую полосу или LACP-хэш, end-to-end поток должен был бы приближаться к потолку bond0. Наблюдалось обратное: максимум 8.7 Гбит/с составлял лишь 4.4% от 200 Гбит/с. Наиболее согласованная с логами и L0b интерпретация - различие software path: TCP требует копирования KV из VRAM в host bounce-buffer, а GPUDirect RDMA передаёт KV без промежуточного host staging.

4.3. Практическое значение результата triton

Выигрыш triton существенно превышал эффекты микро-тюнинга mooncake, но получен сменой вычислительного пути attention, а не оптимизацией транспорта. Перед production-переключением требуются тесты на реальных распределениях контекстов, длинных цепочках, p99, потреблении памяти, качестве ответов и speculative decoding.

5. Ограничения и угрозы валидности

  1. Ограниченный набор транспортов. Сравнивались только RDMA/InfiniBand с GPUDirect и TCP/Ethernet; иные варианты транспорта KV не исследовались.

  2. Масштаб decode. Использовался один decode-узел; влияние числа decode workers и балансировки не исследовалось.

  3. Смещение TCP-выборки. 31 TCP-прогон завершился отказом и исключён из агрегатов производительности. Failure rate приводится отдельно.

  4. Холодный M2. Абсолютные TTFT M2 нельзя сравнивать с прогретым M1; M2 предназначен для относительного сравнения backend'ов.

  5. Малые выборки tuning. В осях C/D и attention verification использовалось 2-3 тёплых повтора на конфигурацию.

  6. Attention layouts. fa4 и triton неэквивалентны на уровне paged/non-paged KV layout.

  7. Метрики движка и дельты. sglang:kv_transfer_* - монотонные счётчики Prometheus, поэтому в харнессе берётся дельта after - before за прогон (чтение _after даёт lifetime-среднее). kv_transfer_speed_gb_s/_latency_ms/_total_mb отдаёт передающая (prefill) сторона, _bootstrap_ms/_alloc_ms - принимающая (decode). Скорость KV подтверждается двумя независимыми источниками - метриками движка и Δ портовых счётчиков, - абсолюты которых расходятся.

  8. Конкретная сборка. Вывод о TCP относится к MiniMax-M3, данной версии sglang/mooncake и конфигурации памяти.

  9. Конфаундеры модели. Перенос результата на другую точность, модель или layout требует отдельного эксперимента.

6. Что забрать в свой кластер

Измерять end-to-end

  • Считать TTFT, TPOT и failure rate одновременно.

  • Проверять маршрут KV дельтой счётчиков IB и Ethernet после тестового запроса.

  • Включать длинный input, длинный output и их сочетание.

Не портить benchmark

  • Прогревать стек и исключать cold-run: 4,1-4,3 с против 0,41-0,43 с TTFT.

  • Ставить health-gate после каждого прогона и не измерять мёртвый prefill.

  • Разделять transport tuning и смену attention backend.