Привет! Проводил тестирование на рабочих стендах и хочу поделиться своими результатами с Habr.
В работе исследуется влияние транспорта 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 прогонов.
TL;DR
В основной матрице 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 Гбит/с, InfiniBand в свою очередь 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.
1. Введение
Увеличение размеров языковых моделей делает полезным разделение инференса LLM на две стадии. На стадии prefill модель обрабатывает входной контекст и формирует KV‑кэш attention. На стадии decode этот кэш используется для последовательной генерации выходных токенов. При PD‑disaggregation стадии размещаются на разных GPU‑узлах, поэтому KV‑кэш пересекает границу машины.
Такое размещение меняет статус сетевого транспорта. В монолитном inference KV остаётся внутри памяти одного процесса или узла; в PD‑топологии транспорт KV входит в критический путь получения первого токена. При этом пропускная способность интерфейса не описывает всю стоимость переноса: реализация может потребовать копирования данных из VRAM в host memory, дополнительных буферов и синхронизации.
Цель исследования — разделить влияние сетевой фабрики и программного пути переноса, а также проверить, сохраняет ли TCP функциональную работоспособность на профилях с большим KV‑кэшем.
1.1. Исследовательские вопросы
Как транспорт KV влияет на TTFT, TPOT, E2E latency и throughput?
При каких профилях длины входа/выхода и конкурентности TCP перестаёт быть работоспособным?
Является ли причиной деградации насыщение сетевой фабрики или программный staging path?
Даёт ли устойчивый выигрыш выбор 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 |
|
Запуск |
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 читается локально из памяти своей ноды.
После завершения 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 |
MoE backend |
|
Attention backend |
|
KV backend M1 |
mooncake |
RDMA |
NDR 400G, HCA |
Ethernet |
|
CUDA / OFED |
CUDA 13.0.1 / MLNX‑OFED 24.10 |
Базовый runtime |
|
Для исключения расхождения артефактов контейнер был пересобран с подавлением записи pycache и очисткой TorchInductor cache. Content‑addressed diffID всех 64 слоёв совпадали на обеих нодах.
2.3. Матрица нагрузок
Основная матрица M1 содержала пять профилей ISL/OSL, три уровня concurrency и пять повторов для каждого из двух транспортов.
Профиль ISL/OSL |
Назначение |
|---|---|
|
короткий вход и короткий выход |
|
базовый прикладной профиль |
|
длинный вход |
|
очень длинный вход |
|
длинный вход и длинный выход |
Всего 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 |
|
потолок фабрики, latency |
L0b |
|
GDR/host staging, read/write, status |
L1 |
IB counters, |
дельта переданных байтов |
L2 |
|
alloc/bootstrap KV‑transfer |
L3 |
|
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 не является причинным эффектом и связано со смещением валидной выборки после исключения отказов.
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 |
Ошибки по хронологии:
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‑буфером воспроизвёл тот же класс отказа.
3.3. Маршрут KV и утилизация фабрики
Транспорт |
|
|
|---|---|---|
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‑хэша не подтверждена.
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 используют разные инструменты и режимы, поэтому их абсолютные значения нельзя смешивать как одно измерение.
3.5. Backend переноса: mooncake и nixl
M2 проводился на IB и холодном стеке. Поэтому значения TTFT сопоставимы только между backend'ами внутри M2.
Backend |
Профиль |
c |
TTFT, мс |
TPOT, мс |
Output tok/s |
|
|---|---|---|---|---|---|---|
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.
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.
Профиль |
|
|
Δ 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.
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.
Увеличение номинальной Ethernet‑полосы без устранения staging path не должно считаться решением наблюдаемого TCP failure mode.
4.3. Практическое значение результата triton
Выигрыш triton существенно превышал эффекты микро‑тюнинга mooncake, но получен сменой вычислительного пути attention, а не оптимизацией транспорта. Перед production‑переключением требуются тесты на реальных распределениях контекстов, длинных цепочках, p99, потреблении памяти, качестве ответов и speculative decoding.
5. Ограничения и угрозы валидности
Ограниченный набор транспортов. Сравнивались только RDMA/InfiniBand с GPUDirect и TCP/Ethernet; иные варианты транспорта KV не исследовались.
Масштаб decode. Использовался один decode‑узел; влияние числа decode workers и балансировки не исследовалось.
Смещение TCP‑выборки. 31 TCP‑прогон завершился отказом и исключён из агрегатов производительности. Failure rate приводится отдельно.
Холодный M2. Абсолютные TTFT M2 нельзя сравнивать с прогретым M1; M2 предназначен для относительного сравнения backend'ов.
Малые выборки tuning. В осях C/D и attention verification использовалось 2–3 тёплых повтора на конфигурацию.
Attention layouts.
fa4иtritonнеэквивалентны на уровне paged/non‑paged KV layout.Метрики движка и дельты.
sglang:kv_transfer_*— монотонные счётчики Prometheus, поэтому в харнессе берётся дельтаafter - beforeза прогон (чтениеafterдаёт lifetime‑среднее).kvtransfer_speed_gb_s/_latency_ms/_total_mbотдаёт передающая (prefill) сторона,bootstrapms/_alloc_ms— принимающая (decode). Скорость KV подтверждается двумя независимыми источниками — метриками движка и Δ портовых счётчиков, — абсолюты которых расходятся.Конкретная сборка. Вывод о TCP относится к MiniMax‑M3, данной версии sglang/mooncake и конфигурации памяти.
Конфаундеры модели. Перенос результата на другую точность, модель или layout требует отдельного эксперимента.
6. Что забрать в свой кластер
Измерять end‑to‑end
Считать TTFT, TPOT и failure rate одновременно.
Проверять маршрут KV дельтой счётчиков IB и Ethernet после тестового запроса.
Включать длинный input, длинный output и их сочетание.
Не портить бенчмарк
Прогревать стек и исключать cold‑run: 4,1–4,3 с против 0,41–0,43 с TTFT.
Ставить health‑gate после каждого прогона и не измерять мёртвый prefill.
Разделять transport tuning и смену attention backend.
Cпасибо. А посмотреть интерактивные графики вы можете тут.