Привет! Меня зовут Роман, в Yandex Infrastructure я работаю в команде Network Operations Center (NOC) и занимаюсь фабриками сетей дата‑центров. Это включает в себя и сети нашего внутреннего облака, связывающие наши GPU, где ML‑инженеры запускают множество обучений различных моделей. Учитывая взрывной рост ML за последнее время, важно учитывать, что смешанная нагрузка на внутреннее облако постоянно увеличивается, но мы при этом хотим обеспечивать предсказуемые SLO для внутренних пользователей.

Мы не так часто рассказываем о сетях, связывающих наши GPU‑серверы. В этом посте речь пойдёт о технологии InfiniBand и концепции Quality of Service, которая была реализована в ней, несмотря на ограниченную вендорскую поддержку. Я разберу конфигурацию QoS и тестовый сетап GPU‑кластера InfiniBand, а также покажу, как мы реализовали приоритизацию трафика различных обучений в кластере. Поехали!

Что представляет собой InfiniBand QoS

Одна из особенностей сетей InfiniBand, кардинально отличающая их от сетей TCP/IP, — централизованный Control Plane. В InfiniBand-фабрике всем управляет контроллер — Subnet Manager; в нашем случае это OpenSM. Не уходя в подробности (про это можно достаточно много написать), отмечу самые важные его функции:

  • Контроллер управляет адресацией в фабрике, назначает Local ID (LID) всем узлам, по которым осуществляется коммутация.

  • Контроллер программирует таблицы форвардинга коммутаторов (Linear Forwarding Table — LFT).

  • …и даже политиками Quality of Service, о которых я хочу рассказать сегодня, тоже управляет контроллер.

Чуть более подробно про то, что такое InfiniBand и что у него под капотом, можно посмотреть в докладе с нашей конференции по сетевым технологиям nexthop 2022.

Поскольку статья рассчитана на широкую аудиторию, добавлю контекста: что же такое Quality of Service, качество какого сервиса имеется в виду? Здесь важно помнить несколько моментов:

  • QoS позволяет задавать различный приоритет для разных типов трафика.

  • В InfiniBand QoS реализуется с помощью Service Level (SL) и Virtual Lanes (VL).

  • VL — механизм создания виртуальных линков внутри одного физического линка. По сути, очень похоже на «очереди» на порту коммутатора в сетях TCP/IP.

  • SL — поле в Local Routing Header (LRH), которое определяет сервисный класс пакета. Тут также можно найти аналогию в сетях TCP/IP: поле DSCP в L3-заголовке, например, задающее приоритет пакета.

В современных IP‑коммутаторах, как правило, реализуется 8 очередей на интерфейсе. Спецификация InfiniBand определяет 16 VL: пятнадцать для Data Plane и один для Control Plane. Но когда мы говорим про текущую реализацию InfiniBand, в железе реализовано также восемь линий. Как и в IP‑коммутаторах, в InfiniBand есть выделенная очередь для control‑plane‑трафика. В InfiniBand это VL15, в Ethernet таких специальных очередей может быть несколько — 6 и 7.

Дальше принцип максимально простой: разные VL могут иметь приоритет, высокий или низкий, и разный вес: он определяется числом 64-битных юнитов, от 0 до 255. Мы можем «покрасить» пакеты в разные цвета (SL) и «замаппить» определённым образом в VL с заданным приоритетом и весом:

Эту картинку я увидел когда‑то на тренинге по сетям InfiniBand от Mellanox в 2020 году. В тот момент мне казалось, что всё супер просто и понятно.

  1. К нам прилетает пакет, в нём есть Local Routing Header (LRH).

  2. Мы смотрим Destination LID, определяем в какой порт отправить пакет далее.

  3. Если у нас настроен QoS, мы также учитываем соответствие SL‑to‑VL, и маппим в конкретную виртуальную линию.

Реальность же, как это часто бывает, оказалась несколько сложнее.

Когда история про QoS в нашей сети InfiniBand начала переходить из плоскости картинок в презентациях к практическому применению, я решил обратиться к первоисточнику — спецификации InfiniBand. С удивлением обнаружил, что в заголовке LRH есть не только поле SL, про которое нам рассказывали на курсе, но и поле VL, про которое почему‑то не рассказывали ничего. К такому жизнь тренинг по сетям InfiniBand от Mellanox меня не готовил.

Вот что обо всём этом говорит спецификация InfiniBand: приведу несколько тезисов, которые кажутся мне наиболее важными.

  • Поле SL не должно изменяться при прохождении пакета через подсеть.

  • Поле VL может меняться при прохождении пакета через подсеть.

  • SL to VL mapping используется для изменения виртуальных каналов (VL) при прохождении пакета через подсеть.

  • В коммутаторах должна существовать таблица SL2VL mapping, которая сопоставляет SL, входной порт и выходной порт пакета с виртуальным каналом VL, который будет использован на следующем хопе.

Последнее утверждение особенно важно, потому что фактически оно означает, что допускается изменение VL не только на основе SL‑метки пакета, но и в зависимости от того, откуда и куда этот пакет направляется. Таким образом, механизм SL2VL‑маппинга может быть частью Control Plane при принятии решения о маршрутизации (к этому тезису мы ещё вернемся). На этом вводную часть по теории считаем завершённой. Очень интересно, но зачем всё это нам?

А какую проблему вы хотите решить с помощью QoS? (с)

Несмотря на то, что этот подзаголовок является нашим локальным мемом внутри NOC, очень важно правильно ответить на этот вопрос. Чтобы добавить контекста, покажу, как устроена сеть InfiniBand, которая связывает между собой наши GPU.

В общем случае группа серверов с GPU, объединённая отдельной interconnect‑сетью InfiniBand (или RoCEv2), называется кластером с загадочной аббревиатурой YATI‑{NUM}. Таких кластеров у нас достаточно много. Они могут быть разных размеров, GPU в них могут быть разных поколений, сеть может быть построена по разным топологиям и на разных поколениях оборудования.

Неизменным во всех этих кластерах остаётся одно: каждый такой кластер является облачным ресурсом, на котором могут обучаться модели разных пользователей. В единицу времени на кластере могут быть запущены десятки (или даже больше — в зависимости от величины кластера и количества обучений) операций. И для всех этих операций сеть кластера InfiniBand будет представлять собой разделяемый ресурс, за который они могут конкурировать между собой. Логично предположить, что какие‑то обучения важнее и приоритетнее, и нужно обеспечить трансляцию этих приоритетов с точки зрения сетевых гарантий.

Долгое время все эти мысли просто жили внутри нас: было интуитивно понятно, что неплохо бы этим заняться, но явного ответа на вопрос о том, что именно должно стать лучше, у нас не было. Всё поменялось, когда на одном из синков команд GPU‑инфраструктуры и NOC коллеги показали нам картинку ниже.

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

В этот момент у нас появился ответ на вопрос из подзаголовка: мы хотим научиться задавать приоритет операции с точки зрения сети.

Как понять, что это работает?

Как мы уже выяснили, всеми политиками QoS в фабрике InfiniBand управляет контроллер. Не буду приводить в этом посте конфигурационные файлы (если кому‑то интересно, можно посмотреть видео с nexthop 2025, где мы про это рассказывали) — опишу лишь базовую гипотезу, которую нужно было проверить. Мы хотели убедиться, что сценарий приоритизации одного типа трафика над другим базово работает. Гипотеза была следующей:

  • У нас есть два типа трафика, «покрашенные» соответственно в SL0 и SL1.

  • SL1 считаем более приоритетным, и ему выделяется 80% ёмкости порта.

  • SL0 используется для менее приоритетного трафика, и ему отводятся оставшиеся 20%.

Далее нам нужна была рабочая среда для проверки этой гипотезы. В качестве таковой мы решили воспользоваться окном регламентных работ на одном из кластеров YATI, который построен на оборудовании предыдущего (на самом деле предпредыдущего) поколения — InfiniBand HDR. Кластер представляет собой FatTree‑топологию с одним уровнем Spine‑коммутаторов (на всякий случай явно укажу что в контексте данной статьи Clos‑топология и FatTree могут считаться синонимами):

  • 40 Leaf‑коммутаторов,

  • 20 Spine‑коммутаторов.

Общая ёмкость кластера — 800 клиентских портов в сторону GPU‑серверов. Переподписки между уровнями Leaf‑Spine нет. Рейловая схема подключения хостов (4 сетевых интерфейса одного хоста подключаются к 4 Leaf‑коммутаторам).

В этом сетапе мы решили разделить хосты на две группы, учитывая при этом их распределение по Leaf‑коммутаторам. Далее применить настройки QoS на контроллере и «покрасить» трафик обеих групп хостов в разные SL: одну группу — в SL0, другую — в SL1. После этого мы запустили одновременно All2All‑бенчмарк на обеих группах хостов. Наши ожидания базировались на том, что бенчмарк, «покрашенный» в SL1, будет утилизировать больше полосы относительно бенчмарка, «покрашенного» в SL0.

В реальности этого не произошло: результаты были совершенно идентичны. Сначала мы немного расстроились, но объяснение, как я писал выше, в том, что наш тестовый кластер не имеет переподписки с точки зрения сети между уровнями Leaf <-> Spine. При бенчмарке, который мы использовали, создать конкуренцию между разными типами трафика на линках Leaf<->Spine было невозможно (точнее, возможно в случае неэквивалентной балансировки, но это был не наш случай). Чтобы получить желаемое состояние конкуренции двух типов трафика на линках между уровнями Leaf и Spine, нам нужно было создать переподписку. Это мы умеем. Отключив 15 spine‑коммутаторов из 20, таким образом создав переподписку 1:4, мы повторили тест.

В этом случае мы увидели существенную разницу: бенчмарк, «покрашенный» в SL1, существенно выигрывал у бенчмарка, «покрашенного» в SL0, — всё, как и задумано. После этого мы провели ещё несколько тестов, подтверждающих, что это поведение не случайно. В этот момент мы получили возможность приоритизировать трафик в InfiniBand-фабрике.

Топология сети и QoS

Казалось бы, на этом всё: тесты проведены, результат получен, можно переходить к реализации и на этом заканчивать. Но нет. В предыдущем параграфе я не случайно делал акцент на топологии, в которой мы проводили тесты, — FatTree. Настройки, которые мы тестировали, были справедливы именно для неё. Но что будет, если топология сети поменяется, например, на DragonFly+?

Про эту топологию, правда в контексте TCP/IP сетей, мы рассказывали, на nexthop 2024

Если бы речь шла про привычную сеть TCP/IP, я бы с уверенностью ответил, что ничего не поменяется. Настройки QoS‑очередей никак не связаны с топологией сети, они локальны для каждого коммутатора и никак не участвуют в Control Plane сети. Иными словами, топология сети может быть абсолютно любой, и это не потребует переизобретения нужного QoS‑конфига.

— Справедливо ли это утверждение для сети InfiniBand?

— Нет.

В начале поста я приводил формат заголовка Local Routing Header (LRH), по которому осуществляется форвардинг в InfiniBand‑фабрике, и выдержки из спецификации, касающиеся его полей SL и VL. Это, опять, же было не случайно. Спецификация подразумевает использование SL2VL для задачи Control Plane сети при принятии решения о том, по какому пути будет пересылаться пакет. Но обо всём по порядку: сначала разберёмся с DragonFly+‑топологией.

DragonFly+

DragonFly+ (сокращённо DF+, также встречается название Megafly) представляет собой полносвязную full‑mesh топологию, состоящую из групп узлов. Каждая группа, в свою очередь, представляет собой уже знакомую Leaf‑Spine топологию FatTree (в контексте DF+ часто употребляют термин Clos‑топологии).

Глядя на эту топологию, довольно легко прийти к выводу, что из одной группы, например, 1-й, можно попасть в другую группу, например, 17-ю, несколькими разными способами. Первый и самый очевидный — мы можем пройти по прямому линку, соединяющему группы 1 и 17. Но что если этот линк имеет ограниченную ёмкость (а это так и есть), и весь трафик между заданными группами в него не помещается? Тогда мы можем пройти по пути +1 hop, например, через группу 15, и таким образом получить дополнительную ёмкость между группами. На этом принципе — получении дополнительной ёмкости через транзитную группу — основан весь принцип маршрутизации в топологии DF+. Помимо описанного выше роутинга +1 hop, возможен также вариант с +3 hop, когда в транзитной группе мы спускаемся со Spine‑уровня до Leaf и потом поднимаемся вновь на Spine‑уровень.

Зачем вся эта сложность? Чем это лучше понятной и удобной FatTree‑топологии? Ответ очень простой: DF+ позволяет строить сеть без дополнительного слоя Super‑Spine‑коммутаторов (или Spine второго уровня, как больше нравится), что, в свою очередь, приводит к прямой экономии денег. Именно эта мотивация лежит в основе того, что у нас есть кластеры InfiniBand, построенные по топологии DF+.

Infiniband QoS в DF+

Так как же всё‑таки QoS‑политики и топология DF+ связаны между собой в сети InfiniBand? Как бы это шокирующе ни звучало, но самым непосредственным образом. Дело в том, что в сети InfiniBand в зависимости от того, по какому пути пойдёт пакет — прямому или же +1 или +3 хопа, — он будет обрабатываться в различных VL.

Если пакет идёт по прямому пути, то ничего не меняется. Если же пакет идёт по пути +1 или +3 хопа, то в том месте сети, где пакет начинает «подниматься» вверх по топологии во второй раз, происходит ремаппинг VL. Это описано в спецификации касательно поля VL, которое может меняться при прохождении пакета через фабрику. В примере на картинке ниже это VL0 и VL1.

Но зачем этот ремаппинг нужен? Чтобы ответить на этот вопрос, нужно вспомнить о фундаментальном принципе InfiniBand‑сети: она работает с Credit Based Flow Control, что, в свою очередь, обеспечивает lossless‑передачу данных. Для того чтобы порт в сети InfiniBand начал передачу пакетов, он должен сначала получить кредиты от пир‑порта, что гарантирует, в свою очередь, что принимающий порт сможет принять наш пакет и отправить его дальше. И здесь важно отметить, что для разных VL эти кредиты будут свои, с отдельным выделенным буфером.

Этот механизм порождает фундаментальную проблему, известную как «credit loop deadlock», когда циклические зависимости между буферами разных портов могут привести к тому, что порты перестанут выдавать друг другу кредиты по кругу, и передача данных в сети InfiniBand в этот момент полностью остановится. В разных топологиях эта проблема решается по‑разному. Так, в алгоритмах маршрутизации для FatTree (в терминологии InfiniBand это обычно называется routing engine; основные из них — ftree, updn) эта проблема решается ограничением путей, которые ведут к кольцевой зависимости буфера. Так, при прохождении пакета через FatTree‑топологию пакет может подняться от Leaf‑уровня до Spine‑уровня только один раз; если пакет спустился от Spine‑коммутатора в Leaf, он уже не может подняться обратно на уровень Spine — такой путь будет считаться невалидным. Но применить это решение к топологии DF+ невозможно, так как в этой топологии весь смысл в том, чтобы получать дополнительную ёмкость между группами через транзитные, что требует возможности опуститься «вниз» по фабрике и подняться обратно.

Как вы, наверное, уже догадались, механизм ремаппинга VL решает проблему «credit loop deadlock» для этого случая: фактически мы разрываем один непрерывный буфер на два независимых. Это, в свою очередь, разрывает кольцевую зависимость и предотвращает deadlock.

Что меняет этот ремаппинг VL для DF+ применительно к нашей исходной задаче? На самом деле многое.

Начнём с того, что routing engine для топологии DF+ (dfp, dfp2) требует двух VL для прохождения одного класса трафика: один VL — для прямого трафика, второй — для трафика по пути +1 или +3 хопа. Это означает, что мы не можем использовать маппинг SL <→ VL один в один, мы должны маппить каждый SL в 2 VL — это очевидным образом приводит к сокращению доступных к использованию «SL‑красок» в фабрике в два раза. SL2VL больше не нужно настраивать в конфигурационном файле, так как SL2VL‑маппинг становится частью Сontrol Plane и управляет им теперь непосредственно routing engine (dfp/dfp2).

Драматизма истории добавляет тот факт, что официальная документация по InfiniBand от NVIDIA (ранее Mellanox) никак не раскрывает всей этой истории и содержит в себе в основном описание самых примитивных сценариев работы с SM, связанных со сценарием его базового запуска. Наиболее полезными источниками информации были community‑посты и статьи для профессионального сообщества. Тщательно погрузившись в них, мы в конце концов заполучили QoS‑конфиг для наших кластеров, построенных по DF+ топологии. Наконец‑то можно переходить к реализации!

InfiniBand QoS as a product

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

Были разные гипотезы, как это можно сделать. Одной из них была гипотеза о выделении отдельной «краски» каждому проекту (или одной «краски» группе проектов). Но она оставляла кучу белых пятен: начиная с того, как распределять веса SL разных проектов, и заканчивая технической реализацией. Количество «красок», которые мы можем использовать, сильно меньше, чем количество наших проектов. Логика некоего маппинга проектов в различные «краски» также выглядит крайне неочевидной.

В результате мы остановились на самом понятном и простом варианте. В итоговой реализации мы решили оставить наш тестовый конфиг с SL0 весом 20% и SL1 с весом 80%. Приоритетными мы считаем БОЛЬШИЕ обучения, то есть обучения, которые задействуют количество GPU в кластере больше определённого порога. Логику этого порога мы постарались сделать гибкой. В эксплуатации у нас довольно большое количество кластеров разных поколений и разного размера, и потому иметь одну бизнес‑логику, объединяющую их все, будет не очень удобно. Поэтому мы решили, что порог должен быть конфигурируемым параметром отдельно взятого кластера. Порог этот может быть задан как процентом от общего количества GPU‑хостов в кластере, так и абсолютным значением.

Планировщик обучения определяет SL обучения при его аллокации. Далее он передаёт эту информацию агенту на хосте, который красит трафик в заданный SL в момент, когда на нём идёт обучение. Важно отметить, что агент на хосте в любом случае перекрашивает трафик обучения. Если обучение приоритетное — в SL1, если нет — в SL0. Если пользователь принесёт «краску» в своём коде (а это можно сделать), то трафик в любом случае будет перекрашен. В этом месте никакого доверия 😎

Что дальше?

На самом деле вся эта история может быть полезна нам ещё в одном проекте. При определённых условиях может возникнуть ситуация, когда у нас в одном кластере могут сосуществовать проекты с обучениями и проекты с мультихостовым инференсом, которые также будут потреблять ресурс сети. В этой ситуации кажется логичным также разнести эти два разных типа трафика в разные «краски». Приоритет в этом случае логично отдать инференсу, так как это по своей сути real‑time трафик.


Надеюсь, что статья была полезна! Буду рад ответить на вопросы здесь в комментариях или в нашем сообществе Yandex Infrastructure — заглядывайте к нам в ТГ, чтобы узнать больше, как мы делаем внутреннюю инфраструктуру Яндекса.