К содержимому
MoranaLabs.
Инженерные гайды7 мин чтения0 просмотров

NCCL и сеть кластера: почему распределенное обучение упирается не в GPU 

Мы закупили 64 карты A100, связали их обычным Ethernet и попытались запустить FSDP. Кластер показал 18% scaling efficiency, превратив дорогой кремний в обогреватели. Рассказываю, как мы уперлись в сеть и почему программные хаки здесь не работают.

0xReality

Мы закупили шестьдесят четыре ускорителя A100, распихали их по стандартным шасси с обычным 100G Ethernet и решили, что сейчас порвем рынок файнтюном тяжелых LLM. Спустя неделю кластер показал 18% эффективности масштабирования (scaling efficiency), превратив кремний на пару миллионов долларов в очень дорогие обогреватели. Тема, о которой почему-то молчат продавцы железа — NCCL и сеть кластера: почему распределенное обучение упирается не в GPU, а в то, как эти карты общаются между собой.

Если при проектировании кластера для AI ваш бюджет на сеть составляет меньше тридцати процентов от бюджета на видеокарты, вы строите не суперкомпьютер, а дорогую гирлянду.

Обучение на нескольких узлах — это не независимая работа. Как только мы выходим за пределы одной машины, в игру вступает NVIDIA Collective Communications Library, она же NCCL. Это слой, который отвечает за синхронизацию данных. В стандартном Data Parallel обучении каждая карта считает градиенты на своем куске батча, а потом они должны сложиться и усредниться, чтобы веса модели обновились синхронно. Операция называется all-reduce. И вот здесь начинается физика. GPU молотят матрицы с чудовищной скоростью, выплевывая гигабайты градиентов за миллисекунды. Затем они останавливаются и ждут, пока эти гигабайты пролезут через межузловой линк. В нашем случае это был классический TCP/IP поверх витой пары.

Если копнуть в топологию, NCCL строит логические кольца (Ring) или деревья (Tree) для передачи данных. В алгоритме Ring All-Reduce каждая видеокарта передает кусок данных следующей по кругу. Если у вас восемь карт на шине NVLink внутри сервера, этот круг замыкается со свистом на пропускной способности в 600 гигабайт в секунду. Карты общаются друг с другом практически на скорости видеопамяти. Но когда кольцо выходит за пределы сервера, пакеты падают в узкое горлышко межузловой сети.

Сначала данные должны спуститься с видеокарты по шине PCIe. Без аппаратного RDMA вы не можете использовать прямой доступ к памяти соседей. Данные копируются в оперативку, центральный процессор берет их, заворачивает в TCP-пакеты, считает контрольные суммы и только потом отдает сетевой карте (NIC). Здесь срабатывает закон слабого звена. Скорость всего логического кольца определяется самым медленным линком. Если хотя бы один коммутатор по пути решил буферизовать трафик или отбросить пакет, все шестьдесят четыре карты в кластере синхронно сбрасывают обороты.

Мы наивно рассчитывали на communication/computation overlap — перекрытие вычислений и передачи данных. Идея проста: пока считается следующий слой бэкпропа, градиенты предыдущего уже летят по сети. В теории это позволяет спрятать сетевые задержки за вычислительной нагрузкой. Но перекрытие работает только тогда, когда сеть способна прожевать данные быстрее, чем железо их генерирует. В профайлере PyTorch мы видели чудовищную картину. Вместо красивой диаграммы, где блоки связи идут параллельно с математикой, мы получили строгую последовательность. Сеть была настолько медленной, что очередь передачи забивалась мгновенно. Слой градиентов не успевал улететь до того, как был готов следующий. График утилизации чипов напоминал редкий штакетник: короткий пик вычислений, а затем долгая полка ожидания завершения синхронизации.

Попытка затащить на эту инфраструктуру Fully Sharded Data Parallel (FSDP) обернулась катастрофой. Чтобы уместить 70-миллиардную модель в память, FSDP режет веса, градиенты и состояния оптимизатора на куски и раздает разным узлам. Звучит логично, пока вы не смотрите на сетевой профиль. Для того чтобы сделать форвард-пасс, каждой видеокарте нужны полные веса текущего слоя. Она запрашивает недостающие куски у соседей — это операция all-gather. Как только слой посчитан, эти куски весов удаляются из памяти. На бэкворд-пассе все повторяется: снова all-gather для весов, вычисление градиентов, а затем reduce-scatter, чтобы размазать посчитанные градиенты обратно по кластеру.

Вы променяли ограничения по памяти на сетевой трафик. Объем пересылаемых данных взлетает в небеса. И вот тут наша стогигабитная сеть просто умерла. Стек ядра Linux начал захлебываться прерываниями. Процессоры ушли в стопроцентную загрузку, обрабатывая входящие пакеты, потому что ядро физически не успевало парсить TCP-заголовки на такой скорости. Задержки (latency) улетели в сотни миллисекунд. Распределенное обучение жестко синхронно. Хвосты задержек p99 в Ethernet убивают все: вы можете иметь средний пинг в доли миллисекунды, но если один пакет летит десять миллисекунд, эффективная производительность всего суперкомпьютера падает до этого уровня.

Если с Data Parallel мы просто ждали синхронизации градиентов, то попытка запустить Pipeline Parallelism показала нам, как выглядит настоящая деградация. В пайплайн-параллелизме мы режем саму модель на слои и раскладываем их по разным узлам. Первая машина считает первые десять слоев трансформера и передает активации на вторую машину по сети. Вторая считает свои слои и передает дальше. Задержка при передаче активаций заставляет последующие узлы сидеть в так называемом пузыре (pipeline bubble). Железо ждет данных, чтобы начать работу. Чем выше latency вашей сети, тем больше этот пузырь, и тем меньше полезного времени работают транзисторы.


Пришлось остановить эксперименты и начать считать. Первое правило отладки кластера — никогда не верить заявленной скорости портов. Нам нужна была эффективная алгоритмическая пропускная способность на уровне приложения. Мы запустили стандартный бенчмарк nccl-tests, принудительно выставив отладочные флаги для сетевой подсистемы.

NCCL_DEBUG=INFO NCCL_DEBUG_SUBSYS=INIT,NET \
NCCL_ALGO=Ring,Tree \
mpirun -np 64 -hostfile nodes.txt \
-x NCCL_SOCKET_IFNAME=eth0 \
/opt/nccl-tests/build/all_reduce_perf -b 8 -e 8G -f 2 -g 1

Когда вы смотрите на вывод nccl-tests, нужно понимать разницу между двумя ключевыми метриками. Первая — это busBandwidth, фактическая скорость передачи байт по физической шине. Вторая — algoBandwidth, полезная пропускная способность алгоритма. Из-за особенностей коллективных операций алгоритмическая пропускная способность всегда ниже физической. На идеальной сети 100G мы должны были видеть algoBandwidth в районе 10 гигабайт в секунду для крупных тензоров. Мы видели едва ли 4 гигабайта в секунду, и эти цифры непредсказуемо скакали.

В логах мы увидели, что NCCL честно пытался поднять RDMA-соединения, не находил соответствующих адаптеров, ругался в stderr и откатывался на сокеты. На мелких тензорах latency была неприличной из-за накладных расходов на системные вызовы. На крупных тензорах мы упирались в полосу пропускания, но графики прыгали из-за инкаст-трафика (incast traffic). Когда десятки узлов одновременно начинают передавать данные одному узлу, буферы на коммутаторах переполняются за микросекунды. Срабатывает механизм congestion control, окно передачи схлопывается, и пропускная способность падает в разы. Физику нельзя обмануть патчами конфигурации.

Мы пытались выжать максимум. Включили gradient bucketing — механизм, который собирает мелкие градиенты в большие куски памяти перед отправкой, чтобы снизить количество вызовов сетевого API. Тюнили размеры этих бакетов до посинения. Слишком маленький бакет — сеть захлебывается мелкими пакетами. Слишком большой — вы убиваете overlap, потому что ускоритель ждет накопления огромного массива данных. Мы настраивали CPU-аффинность для сетевых прерываний, прибивали процессы к нужным NUMA-нодам, чтобы избежать кросс-сокетного трафика. Это дало прибавку в жалкие несколько процентов.

Взрослые дяди не просто так строят кластеры на InfiniBand или на RoCEv2 (RDMA over Converged Ethernet). Технология RDMA позволяет сетевой карте одного сервера писать данные напрямую в память видеокарты другого сервера, вообще минуя процессор и ядро операционной системы. Задержки падают до микросекунд. Но RoCEv2 требует идеальной настройки сети без потерь (lossless network) — приоритетного управления потоком (Priority Flow Control) и явного уведомления о перегрузке (ECN). Настроить это в масштабах стойки — черная магия. Чуть ошибся с порогами срабатывания на коммутаторах, и сеть ловит шторм pause-фреймов, когда порты каскадно блокируют друг друга. InfiniBand в этом плане надежнее, так как кредит-базированное управление потоком встроено в протокол аппаратно. Железо Mellanox стоит космических денег, но без него ускорители простаивают.

Мы пересчитали экономику провала. Выяснилось, что нам было бы дешевле и эффективнее купить в два раза меньше серверов, но упаковать каждый максимальным количеством карт с шиной NVSwitch, чем пытаться масштабироваться дешевыми узлами. Внутри NVSwitch карты видят единое адресное пространство, там нет TCP-стека и нет потери пакетов. Трейд-офф предельно честный: без быстрой, низколатентной сети на базе RDMA 3D-параллелизм и FSDP не просто бесполезны, они парализуют инфраструктуру. В итоге мы разобрали этот кластер, перевели машины на инференс, где межузловая сеть почти не нагружена, и начали проектировать новый, но уже отталкиваясь от архитектуры коммутаторов, а не от терафлопсов.

  • #distributed-training
  • #FSDP
  • #NCCL
  • #network-architecture
  • #RoCEv2
ПоделитьсяTelegramX
рассылка

Новые статьи — на почту

Лонгриды про ML в проде, edge и компьютерное зрение — сразу после выхода.

Канал в Telegram: morana.log

Без спама. Нажимая «Подписаться», соглашаетесь с обработкой персональных данных

бесплатный pdf-гайд

Edge AI или облако: когда тащить нейросеть на железо

Признаки, фреймворк выбора и прикидка экономии — короткий PDF-гайд на почту.

PDF · 5 страниц · без спама. Нажимая «Получить», соглашаетесь с обработкой персональных данных

Читать дальше
— заявка

Опишите задачу  ответим как инженеры. 

Оставьте имя и Telegram — остальное обсудим. Без брифов на 40 слайдов и звонков по три раза.

Отвечаем за пару часовотвечает инженер, а не отдел продажNDA по запросу

Сюда напишем — это быстрее всего

Или сразу написать в Telegram

Без спама и звонков-роботов. Нажимая кнопку, вы соглашаетесь с политикой конфиденциальности и обработкой персональных данных.