Это первая (после нулевой) статья из серии Нейро сети для самых маленьких, в которой мы разбираем инфраструктуру для запуска нейронных сетей.

Для обучения и инференса нейросетей и для любых видов High Performance Computing используются специализированные технологии: GPU/TPU, RDMA, Kernel bypass, NVLink, InfiniBand, RoCE и другие. Про некоторые из них большинство только что-то слышали, но сталкиваться с ними не приходилось.

Нельзя просто взять ванильный стек Linux, воткнуть в него 400 Gb Ethernet+IP и получить рабочее решение. Почему?

Потому что общее решение на масштабе в большинстве случаев проигрывает специализированным как в скорости, так и в стоимости. Как бы странно последнее ни звучало.

До стрелки сеть была настроена неправильно, и прогресс обучения был нестабильным
До стрелки сеть была настроена неправильно, и прогресс обучения был нестабильным

С каждой приведённой технологией мы будем разбираться в отдельных статьях глубоко и подробно, а главное так, чтобы вы не раздробили зубы, читая это. А сегодня просто сделаем несколько подкопов под них, чтобы понять, что же они такого дают, что половина земного шара работает над подобными оптимизациями (другая половина, конечно, создаёт медленно работающие продукты).

И вообще, нет такого греха, на который не пойдут вендоры и провайдеры услуг ради оптимизации.

Предыдущая часть, очень рекомендованная к ознакомлению, если с нейросетками не на «ты»:

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

Чтобы построить дом, нужны кирпичи. Чтобы создать кирпич, нужны глина и песок. Чтобы их раздобыть, нужно найти, где их можно набрать. А чтобы набрать, понадобится лопата и тачка. Они сделаны из тонкого железа. Значит, нужно найти железо, расплавить его и раскатать. Чтобы расплавить железо, нужны руда и уголь. Чтобы добыть и то, и другое, нужны шахты и инструменты, чтобы изготовить инструменты, нужно дерево и железо. И так до бесконечности.

Но нам не нужно об этом задумываться. Эта сложность скрыта за множеством слоёв от нас. Мы просто идём в строительный магазин и покупаем кирпич. Который стоит намного дороже, чем глина и песок, из которых он состоит, но экономит нам уйму времени.

Если нужен песок, чтобы замешать бетон фундамента, — вы можете заказать камаз песка с доставкой.

Мы платим за удобство.

Но

При этом, если нужен кремний для производства процессора, вы уже не можете пойти и купить песок в строительном магазине — он для этого не подходит — нужно выстраивать свои логистические цепочки.

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

Для конкретики — мы будем говорить про большие вычислительные кластера (сотни и тысячи машин), серверные GPU Nvidia, содержащие сотни гигабайт встроенной памяти, и скорости сетевых подключений 100/400/800Гб/с.


Содержание

  1. Микрочипы, CPU, GPU, TPU

  2. Операционные системы, сетевой стек, работа с памятью, DMA

  3. RDMA — Remote DMA

  4. The Network. Скорости, задержки, TCP, InfiniBand, RoCE

  5. А что у них? Nvidia: NVLink, GPUDirect RDMA

  6. Суммируем

  7. Заключаем


Словарь: что вам может понадобиться..
  • CPU (Central Processing Unit) — Универсальный микрочип, который выполняет произвольные инструкции.

  • GPU (Graphics Processing Unit) — Специализированный микрочип для работы с графикой и вычислениями. Архитектурно родственен CPU, но оптимизирован под массовый параллелизм.

  • ASIC (Application-specific integrated circuit) — Узкоспециализированный чип, который решает только одну конкретную задачу, но делает это очень быстро.

  • TPU (Tensor Processing Unit) — ASIC, разработанный Google, для тензорных (матричных) вычислений.

  • RAM (Random Access Memory) — Оперативка — системная память компьютера для оперативных данных.

  • Memory Bus — шина между CPU и RAM.

  • VRAM (Video RAM) — Память, аналогичная оперативной, но расположенная на GPU. Используется также для хранения оперативных данных. Управляется чипом GPU.

  • HBM (High Bandwidth Memory) — Один из видов VRAM. Разновидность физической архитектуры памяти. Насколько сверхбыстрая, настолько же и сверхдорогая. В видеокартах потребительского сегмента вместо HBM используется GDDR.

  • Интерпозер — промежуточный слой, который служит сверхбыстрым мостиком между чипами. Например, память HBM и чип GPU располагаются на одном интерпозере.

  • PCIe (Peripheral Component Interconnect Express) — Шина компьютера для подключения периферийных устройств — сетевых карт, устройств ввода-вывода, хранения итд.

  • NIC (Network Interface Card) — Сетевая карта для подключения к внешней сети.

  • PIO (Programmed Input-Output) — Метод передачи данных между двумя устройствами, использующий CPU для передачи данных.

  • DMA (Direct Memory Access) — Прямой доступ периферийных устройств к локальной RAM. Позволяет избежать обращения к CPU для записи/чтения RAM. В отличие от PIO.

  • RDMA (Remote DMA) — Тот же DMA, но прямой доступ не к локальной памяти на том же компьютере, а к удалённой — на другом.

  • OS (Operating System) — Операционная система (ОС), управляющая компьютером.

  • Kernel (Ядро OS) — Управляет работой процессора, процессами, доступом к памяти, периферийными устройствами.

  • User Space (Пользовательская среда OS) — Здесь запускаются произвольные пользовательские приложения. Доступ к любому железу только посредством Ядра.

  • Kernel Bypass — Механизмы обхода ядра для снижения нагрузки и увеличения скорости.

  • Zero Copy — Механизмы работы, не требующие копирования данных из одних участков RAM в другие.

  • TCP/IP/Ethernet — Классический стек сетевых протоколов для обмена данными между компьютерами.

  • InfiniBand (IB) — Стек сетевых протоколов, альтернативный TCP/IP/Ethernet, для реализации RDMA и Lossless-сетей.

  • RoCE (RDMA over Converged Ethernet) — Альтернативный IB стек протоколов для реализации RDMA поверх Ethernet.

  • GPUDirect RDMA — Механизм прямого доступа NIC к VRAM, находящейся на GPU в обход системного RAM и CPU. Технология Nvidia.

  • NVLink — Сверхбыстрая сеть между GPU-карточками, расположенными в одном сервере. Альтернатива PCIe. Технология Nvidia.

  • NVSwitch — NVLink-коммутатор, соединяющий между собой GPU-карты по NVLink. Аналог обычного свитча.

  • V100, A100, H100, H200, B100, B200 — Виды GPU-карт Nvidia разных поколений.

И отдельного упоминания достойны единицы измерения. Где-то полоса измеряется в Гигабитах в секунду (Гб/с — Ethernet, IB), где-то в Гигабайтах в секунду (ГБ/с — PCIe, NVLink). Обращайте на это внимание, потому что иногда приходится приводить одно к другому.


1. Микрочипы, CPU, GPU, TPU

Всё началось в 1947-м, когда в Bell Labs трое инженеров: Бардин, Браттейн и Шокли — изобрели транзистор — простейший электронный компонент любого современного микрочипа.

Первый транзистор. Отсюда
Первый транзистор. Отсюда


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

Но «внезапно» оказалось, что на основе нового трёхногого изобретения можно реализовать любую логику, то есть создать логическую схему, процессор, компьютер в конце концов.

Полезные ссылки

Мы рассказывали про историю транзисторов в двух эпизодах До нас дошло: S05E07 и S05E08.

А про «внезапное» изобретение компьютеров тут: S03E10.  Отец цифровой эпохи

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

Эволюция электроники
Эволюция электроники

А дальше, если пропустить пару витков эволюции, ассортимент транзисторосодержащих продуктов разделился на процессоры, микропроцессоры, CPU, ASIC, FPGA. Позже к ним добавились GPU, NPU, TPU и другие.

Ключевое отличие между всеми этими видами в том, насколько они гибкие.

Так, ASIC — это чип, который решает строго одну конкретную задачу. И возможности изменить её логику, то есть запрограммировать, минимальны.
На другом полюсе CPU — сердце компьютера. CPU решает любые задачи, которые на него возложит приложение. Он буквально может ВСЁ! Но медленно.

Виды микросхем. Отсюда
Виды микросхем. Отсюда

Давайте посмотрим на чипы, использующиеся для массовых вычислений:

  • CPU

  • GPU

  • TPU


1.1 CPU — Central Processing Unit

Intel 4004 или хорошо многим знакомый 8086 появились как решения для массового сегмента, которые могут решать широкий спектр задач.

Intel 4004. 2300 транзисторов. Отсюда
Intel 4004. 2300 транзисторов. Отсюда
Intel 8086. 29 000 транзисторов. Отсюда
Intel 8086. 29 000 транзисторов. Отсюда


Они работали на частоте 740 кГц и 5–10 МГц и содержали 2300 и 29 000 транзисторов соответственно.

Чем выше частота, тем больше операций в секунду они могли совершать. Чем больше транзисторов, тем сложнее логику можно реализовать.

И началась гонка частот и размеров: всё быстрее, всё выше, всё сильнее, всё меньше. Современные процессоры — это уже десятки миллиардов транзисторов размером единицы нанометров и частота до 5 ГГц. В 1000 раз больше тактов, чем на заре.

При этом процы уже давно не так просты: они обвешены кешами, работают не с 4, а с 64 битами и даже больше, состоят из нескольких ядер, а ещё прям на том же самом интерпозере содержат дополнительные чипы, такие как криптография или ИИ-ускорители.
И вот, казалось бы, у нас есть крутое, очень быстрое решение, которое может делать ну прям всё-всё-всё — CPU.
Давайте его возьмём и будем эксплуатировать. Массовое производство, универсальное решение.

Да, вот только CPU умеет делать всё.. одинаково плохо. Как батя: может и велик починить, и плитку положить, и с математикой помочь, и Wi-Fi настроить.
Но велик — только колёса накачать, плитку потом после него хоть перекладывай, Wi-Fi — да, но в дальний конец квартиры не добивает, а пока с математикой помогает, думаешь, не пора ли ювенальную полицию вызывать.

Батя отсюда
Батя отсюда

И если вы захотите починить сто великов, вы наймёте мастера по велосипедам, а если отремонтировать сто ванных — то плиточника.

То же и с процессором. Он прекрасен для домашнего использования: думскроллинг ленты, работа с текстом, посмотреть кино, обработать фотки, попрограммировать. И всё это «одновременно», как любит современное поколение «сдвг-шников». В кавычках, потому что из-за просто охрененной частоты в ГигаГерцы (это, на секундочку, миллиарды тиков в секунду), мы не замечаем, что на самом деле всё происходит последовательно.
Да, когда на фоне идёт ютубчик, Клод-код сам с собой вайбкодит вам новую программу, а вы при этом пишете в чатик коллеге — это всё происходит последовательно, просто CPU очень быстро работает и очень часто переключается между задачами.

Оговорка для принципиальных

Да, современные процессоры многоядерные. Серверные платформы вообще содержат под сотню ядер. И между ядрами процессы действительно прекрасно параллелятся.Но это не отменяет последовательную природу одного ядра и исторический контекст, когда CPU действительно содержал одно ядро.

Прекрасен CPU и для общих задач: обработать входящие HTTP-запросы к энжинксу, поселектить из постгри, запустить скриптик и телеграм-ботика, передать файл, отрендерить видео.

CPU универсален: какие инструкции вы в него положите, то он и будет делать. Неукоснительно — даже на ноль поделит, если скажете. Буквально: вы можете заставить его решать любые задачи.

И поэтому он должен быть очень «умным». И сложным. И дорогим.

CPU Отсюда

Но как только речь заходит о чём-то достаточно простом, всё становится странно. Очень странно.
Как какой-то категоричный пример: управлять лазерной указкой никому в голову не придёт* с помощью CPU, хотя он смог бы.

*Вообще-то пришло

Так появились LIDAR-ы.

Или наоборот, когда говорим о чём-то серьёзном, таком как майнинг крипты или обучение нейросетей, или шифрование, всё становится плохо. Очень плохо.

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

Это именно то, что нужно, когда вы работаете с нейронками: перемножать огромное количество матриц и векторов. Ну или просчитывать графику в видеоигре.

И тут как раз мы отходим от общего универсального дешёвого решения в специализированное — GPU и TPU.


1.2 GPU — Graphic Processing Unit

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

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

 CS1.6. Отсюда
CS1.6. Отсюда

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

То есть много разных вычислений одновременно.

И это одна из тысяч задач CPU.

«Ооок, — подумали тогдашние производители. — А почему бы не взять и не вынести блоки вычисления графики из CPU на отдельный чипПусть CPU там себе занимается, чем хочет, — и это больше не будет влиять на хедшоты геймеров». И придумали графические ускорители.

А Nvidia не будь дурой и следом нарекла это всё GPU, что и пошло в мир.

Принцип его устройства очень похож на CPU. То есть в целом он остаётся всё ещё процессором общего назначения, но со специализацией.

CPU vs GPU
CPU vs GPU

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

То есть, вместо одного или нескольких очень сложных ядер в CPU, в графических процессорах используется тысячи простых ядер. И это ключевая разница.

Не путайте, я попрошу

Nvidia не была первой, кто придумал графические ускорители, она была всего лишь первой, кто начал использовать название GPU.

До неё уже были ускорители 3dfx Voodoo, ATI и другие.

Отсюда

При этом работа с графикой это постоянное перемножение матриц: как меняются координаты и цвет пикселей в каждый игровой тик.
Очень много параллельно происходящих перемножений матриц. А строго говоря, тензоров.
Ровно то же, что происходит при обучении и инференсе глубоких нейронных сетей.
Ровно то, что мы разбирали в прошлой статье Нейро сети для самых маленьких. Часть нулевая. Обзорная.

Слой FFN. Отсюда
Слой FFNОтсюда

В 2007-м году Nvidia представила CUDA (Compute Unified Device Architecture) — это платформа, можно сказать SDK, к карточкам Nvidia.
Если раньше можно было заставить GPU считать только графику, то CUDA позволила заряжать на карточки общие вычисления, а значит использовать GPU не только в играх, но и для любых других интенсивных подсчётов.

И так началась новая эра.

В 2012 на соревновании ImageNet нейросеть AlexNet просто порвала всех конкурентов, показав ошибку распознавания изображения 15% против 26% у ближайшего результата.
Они добились этого, обучив свою глубокую свёрточную сеть на значительно большем датасете, чем кто-либо делал это прежде.
Кстати, уже тогда они использовали ReLU как функцию активации.
И самое главное: это стало возможным благодаря распараллеливанию обучения на две Nvidia GTX 580 по 3 гига VRAM.

Они не были первыми, кто использовал GPU, не были первыми кто распараллеливал, зато они первыми показали результативность и целесообразность распараллеливания на GPU.

С тех пор начался победоносный ход GPU по миру нейросетей.
Капитализация Nvidia говорит сама за себя.

Капитализация бигтехов. В плюсе продавцы лопат. Отсюда
Капитализация бигтехов. В плюсе продавцы лопат. Отсюда

Глядя на архитектуру GPU, можно справедливо заключить, что это специализированная версия CPU под массивные вычисления. При этом GPU всё ещё остаётся процессором общего назначения.
Классический CPU же слишком дорог, медленен и горяч для того, чтобы решать такие задачи, как HPC, обучение нейросетей, работа с видео и графикой.

При всей безумной стоимости GPU они всё равно будут значительно дешевле, чем аналогичное количество CPU.

Но GPU мы не воспринимаем как отход от общих решений — он нам очень привычен. Хотя по факту, это не просто отдельный чип, это уже отдельная сложная дорогая плата, на которую вынесена функция, в принципе выполнимая на CPU.


1.3 ASIC — Application-Specific Integrated Circuit

Есть и ещё более специализированные задачи, например, контроллеры тока в зарядке или автофокус в камерах, или кодирование видео, или шифрование. Они решаются с помощью ASIC — это чип, который разрабатывается под одну конкретную задачу, он производится миллионами и делает хорошо ровно одну задачу и никакие другие не делает.

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

Отсюда

То есть CPU — универсальный боец, который делает то, что ты ему скажешь, любую программу.

GPU — товарищ попроще, меньше умеет, но то, что умеет, делает быстро. Всё ещё очень гибкий. Хоть SHA считай, хоть Qwen файнтюнь, хоть базы данных ускоряй, хоть томограммы распознавай.

ASIC — сотрудник на конвейере — строгий набор действий, ни шага в сторону.


1.4 TPU — Tensor Processing Unit

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

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

А TPU устроен совсем иначе — это чип, запечённый под плотные тензорные вычисления, в частности умножения матриц (matmul). Его ритм очень простой: умножить, сложить, передать дальше.

Я не зря использовал слово «ритм» — ключевая часть TPU — систолические массивы. Это буквально решётки из маленьких вычислительных ячеек. Данные проходят через них ритмичной волной, как кровь, выталкиваемая сердцем во время систолы, а каждая ячейка делает свою крошечную часть общей матричной операции.

Архитектура систолических массивов в TPU. Отсюда
Архитектура систолических массивов в TPUОтсюда

Если CPU и GPU прокручивают через себя данные, неторопливо пережёвывая и пересоздавая, то через TPU данные словно проходят волнами сами.
Или иными словами: в случае CPU и GPU данные лежат рядом в памяти, а на чип идут волны инструкций, что с ними делать — и чипам приходится постоянно доставать данные из памяти и записывать обратно. А в случае TPU есть физическая структура, на вход которой подаются данные, каждая ячейка делает свою маленькую часть большой матричной операции.

Google TPU. Отсюда
Google TPU. Отсюда

Но позволить себе такие ASIC-и мало кто может — буквально единицы компаний в мире.


Ключевая мысль этой части

У нас есть универсальный быстрый «дешёвый» CPU, к которому мы шли много десятилетий.
И на нём вполне можно иметь дело с нейронками.
Но он дёшев и удобен только для общих задач.

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

Точно так же шифрование выносится из CPU на отдельный чип в компьютерах, передача данных — в коммутаторах, обработка цифровых сигналов в мультимедиасистемах, bluetooth в телефонах и так далее.

Всему своё место.


2. Операционные системы, сетевой стек, работа с памятью, DMA

Операционные системы давно пришли к «идеальной» архитектуре kernel + user space.
Kernel, ядро, обеспечивает управление железом, многозадачность и многопользовательность.
А User space — место для работы пользователя и его приложений, а также системных утилит, не требующих максимальных привилегий.

За словом «идеальная» на самом деле замаскирована «компромиссная». Бывают и другие: микроядерные, например, униядерные. Но для подавляющего большинства применений подходит именно монолитное ядро, как в Linux, Windows и Unix.

2.1 Операционные системы, Kernel + User Space

В 1969 году Кен Томпсон из того же Bell Labs написал первую версию Unix.. на ассемблере. Чтобы поиграть в свою игру Space Travel. На заброшенном компьютере PDP-7 . С объёмом памяти в 8000 слов (около 18 кБ). И ему пришлось крутиться — написать ОС, которая делала бы самый минимум и поместилась в ровно половину памяти, чтобы столько же осталось под пользовательские приложения.

PDP-7
Заброшенный PDP-7
Заброшенный PDP-7

Операционные системы были и прежде — тот же многострадальный Multics, из которого Bell Labs сбежала и зареклась иметь дальше дело с операционками.

Но Unix стал первой суперуспешной ОС, потому что был удобен, прост и многозадачен. Впоследствии его переписали на высокоуровневом языке C, который создал Деннис Ритчи, что позволяло легко переносить Unix на разные архитектуры — раньше, без шуток, под каждый процессор писали новую ОС.
А теперь есть единая операционная система под все процессоры.

Unix породил (или вдохновил) Linux, Android, MacOS, iOS. На операционках этого ряда работают компьютеры, телефоны, сервера, сетевые устройства, умные часы, банкоматы, бортовые компьютеры и даже очень маленькие специфические вещи вроде умных трансиверов.

Рекомендую почитать
Краткая история и личные воспоминания о создании и развитии операционной системы UNIX в Bell Labs: как небольшая исследовательская разработка Кена Томпсона, Денниса Ритчи и их коллег превратилась в одну из самых влиятельных технологий в истории компьютеров, породив язык C, культуру инструментов командной строки и философию простых программ, из которых строятся сложные системы.
Краткая история и личные воспоминания о создании и развитии операционной системы UNIX в Bell Labs: как небольшая исследовательская разработка Кена Томпсона, Денниса Ритчи и их коллег превратилась в одну из самых влиятельных технологий в истории компьютеров, породив язык C, культуру инструментов командной строки и философию простых программ, из которых строятся сложные системы.
Архитектура Kernel + User mode и их роли
Архитектура Kernel + User mode и их роли

Ядро обеспечивает ввод-вывод, безопасную работу с памятью, распределяет процессорное время, позволяет разным процессам общаться друг с другом, использовать железо.
В ядро несут всё самое необходимое и стабильное.

Получается очень удобная слоёная структура, где разные уровни изолированы друг от друга: приложению не нужно уметь делать TCP 3-way handshake и следить за окном, а модулю IP — думать о том, какая физика — оптика, медь или WiFi.

Всё для того, чтобы разработчикам приложения нужно было как можно меньше знать о реальности.
Чтобы мы могли на питоне накидать своего унылого ботика за часок, не задумываясь о том, как он будет получать сигнал от сервера, обрабатывать его, как он будет читать память, как записывать данные в неё так, чтобы не затереть ячейку другого приложения, как он будет выводить логи в файл, и как этот файл вообще выглядит на диске. Диске? Каком диске? HDD, SSD, Floppy? Ему не нужно думать о вращении физического диска и положении его шпинделя, не нужно контролировать биты чётности в SSD и «понимать», что там квантовое туннелирование используется.

Точно так же вы не думаете о том, как и куда поместить инструкции в транзисторы CPU и как запускать в них данные.
Мы просто написали своего унылого ботика и развернули его в контейнере. А дальше оно само.
Ну и раз вы пишете на питоне, то, скорее всего, вы даже не задумывались, насколько это неоптимально, насколько дорогие и многочисленные вызовы происходят под капотом.


2.2 Когда нужна операционная система?

Операционная система нужна не везде — достаточно представить себе электрическую зубную щётку с Linux, управляющим её режимами.
Блин, сегодня это даже несложно представить.
Или паяльник.

Мы не будем копать в различия между обычной ОС, Real-time ОС, прошивкой и микрокодом — это нас не слишком приближает к цели статьи. Важно лишь помнить, что такая универсальная и удобная штука, как операционная система, тоже нужна не всегда.

Где-то достаточно просто внутренних инструкций для железа. Где-то нужна гибкая прошивка, позволяющая настраивать параметры поведения чипа. В некоторых системах нужны операционные системы реального времени, которые очень отличаются от пользовательских — вещь весьма, скажем, специфическая.
Тут мы тоже видим отказ от зрелого универсального решения в пользу частных.

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

Да.. серверов, вот тут начинается интересное.

Если пользовательская электроника должна быть просто универсальной, доступной, работающей на человеческих скоростях, или точнее тормозить ровно настолько, чтобы человек (обычно один единственный, кто ей прямо сейчас пользуется) не успевал заметить, то сервера — совсем другая история — они серьёзными делишками ворочают.
Одни — обрабатывают миллиарды запросов на главную гугла, другие — хранят петабайты данных на Яндекс Диске, на третьих — обучаются нейросети Open AI, на четвёртых — запускается их инференс.
Это сценарии, где нет места тормозам, где на счету каждый переход из user space в kernel space, каждая запись в память и чтение, каждое прерывание процессора.

Представьте кластер на тысячу машин. Вы пишете код на питоне и добавили какую-то функцию, которая делает лишнее прерывание, оно длится, например микросекунду. И этот код исполняется в цикле тысячу раз.
Поздравляю, вы только что добавили в кластер общую задержку в одну миллисекунду. А если ещё и на каждом хосте.
Ну, нам, питонистам, простительно.

И вот в случае серверов, решающих важные вопросики, начинаются такие лютые оптимизации, что многим и не снилось. С другой стороны, Томпсону и Ритчи тоже и не снилось, насколько далеко шагнёт человечество — туда, где 16ГБ оперативки съедает один браузер, банковское приложение на телефон весит 200МБ, а contactsd на MacOS съедает 130% CPU.

Давайте дальше мы возьмём такой пример: перемещение данных с одного компьютера на другой — и озвучим проблему.


2.3 А где проблема?

Благодаря существованию ОС и сетевого стека, разработчик не реализует TCP 3-way handshake или работу ARP — для него это базовые инстинкты, выдающиеся по факту рождения.
Весь сетевой стек обеспечивается ядром операционной системы.
Это позволяет нам быстро создавать программы, запускать новые сервисы, не задумываясь о сложности реального мира.

Слои, интерфейсы и абстракции — это благо.

Приложению достаточно знать, к какому адресу и порту подключаться, и уметь открыть сокет.

Как эти сокеты работают на уровне ОС, что такое Ethernet, E1 или DWDM, через радио, медь или оптику пойдёт сигнал, и какие усилители он по дороге преодолеет, приложению совершенно до лампочки.
Слои: физический, канальный, сетевой, транспортный, прикладной — позволили создать нам глобальную сеть Интернет, работающую по единым принципам.

Модель OSI. Осторожно: нейроконтент
Модель OSI. Осторожно: нейроконтент

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

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

И тут пора вспомнить про вещи, которые не прощают лишних задержек:

  • Обучение нейросетей

  • Системы хранения данных

  • Распределённые базы данных

  • High Performance Computing

  • High Frequency Trading

  • Высоконагруженное что угодно

В каждой из них лишние миллисекунды — это реальные деньги, и мы их в конце даже прикинем. Просто спросите у CTO какого-нибудь трейдера, не хочет ли он сэкономить и купить свитчи, у которых порт-порт будет не 100 нс задержка, а 500.
Поэтому для них как раз существуют отдельные сети, вроде Fibre Channel, InfiniBand, и всевозможные извращённые тюнинги TCP/IP и UDP.

А также всевозможные оптимизации и срезания углов в самой ОС.


2.4 Работа с памятью и DMA

Ядро ОС — это такой медиатор, который склеивает все части компьютера вместе: процессор, оперативную память, устройства ввода-вывода, пользовательские приложения. Оно всё это контролирует, обеспечивает изоляцию процессов и их безопасность, а также общение как между процессами, так и между всеми устройствами компьютера.
Ну то есть буквально каждой бочке затычка.
Это удобная универсальная архитектура, когда власть сосредоточена в одних руках.
Но и из неё делается множество исключений для оптимизации. И одно из них DMA (Direct Memory Access).
Давайте посмотрим, что это такое.

Как в обычной ситуации устроена работа пользовательского приложения с памятью?
Ему просто доступна выделенная ему область оперативной памяти.
Оно обращается к ней напрямую, без системных вызовов ядра. Ядро всё ещё нужно здесь для того, чтобы всё подготовить и потом следить за порядком (PAGE FAULT, SWAP). Но в норме в процессе работы с памятью приложение не обращается к ядру.

Хорошо, а как такая работа с памятью проявляется в реальных задачах?

Допустим, приложение хочет скачать объект по HTTP.
Для этого нужно установить TCP-сессию и собственно загрузить объект.
Само приложение этого не делает.
Во-первых, нафига бы ему реализовывать стандартный TCP-стек и, в частности, его 3-way handshake, ACK-и на получение сегментов, финализировать сессию?
А во-вторых, да кто ж ему даст напрямую работать с периферией?

Что при этом происходит?

  1. Приложение создаёт сокет и делает системный вызов в ядро, чтобы установить соединение.

  2. Ядро через сетевой стек и драйвер работает с сетевой картой.

  3. Запрос улетает через карту на сервер.

  4. Пакеты данных от HTTP-сервера приходят на сетевую карту.

  5. Сетевая карта уведомляет CPU прерыванием.

  6. Данные переносятся из буфера сетевой карты в сокетные буферы ядра в оперативной памяти. ⚡️ ⚡️⚡️ Внимание на этот пункт ⚡️ ⚡️⚡️

  7. Ядро обрабатывает пакет в сетевом стеке: заголовки Ethernet, IP, TCP. Понимает, что они предназначаются конкретному приложению.

  8. Когда приложение вызывает recv/read, CPU копирует данные из буфера ядра в буфер приложения. ??? И на этот ???

  9. Приложение продолжает работу с этими данными.

Если уж совсем заморочиться — подробная mermaid-диаграмка..
И для совсем упоротых..
Обработка пакета в Linux. Отсюда
Обработка пакета в Linux. Отсюда

То есть тут процессор и ядро при получении ответа: устанавливают соединение, распечатывают лишние заголовки, копируют данные из памяти ядра в память приложения. Ну и, естественно, обрабатывают прерывания, и переключают контекст.
Но!
Не копируют данные с NIC в RAM — NIC имеет прямой доступ к области памяти и пишет в неё получаемые данные. Это и есть DMA.

А ещё, когда-то давно, на заре компьютерных технологий, CPU побайтово копировал данные с сетевой карты в память ядра. Это называлось PIO — Programmed Input-output.
Да, NIC сообщал CPU «для вас новое сообщение», и CPU перетаскивал его из буфера карты в пространство ядра.

Работа DMA
Работа DMA

И это называется DMA, технология старая, как мир.
В этом случае периферийное устройство получает прямой доступ к выделенному ему блоку памяти, и когда оно хочет записать данные в память, то не обращается к ядру и процессору — а просто пишет, куда сказали. CPU здесь всё ещё участвует, но как прораб, который указывает, какие именно адреса ячеек доступны карточке, но не носит кирпичи.

И вот мы уже сознательно отказались от удобной абстракции и общего решения в пользу быстродействия.
⚡️⚡️⚡️ DMA ⚡️⚡️⚡️ — это прямая работа периферии с памятью.

Режим PIO для сетевых карт умер ещё в 90-х годах. Любая современная сетевая карта, даже самая дешёвая в домашнем ПК, по умолчанию использует DMA для записи пакетов в RAM при работе с обычным TCP/IP.

Но у нас всё ещё остаётся шаг, когда данные должны быть скопированы из памяти ядра в память приложения посредством ??? CPU ???. Это место сложно обойти, потому что требуется обработка заголовков Ethernet/IP/TCP, проверка контрольной суммы и так далее.

Обработка пакетов в ядре
Обработка пакетов в ядре

И это нормально, когда пользователь хочет посмотреть картинку с чихуахуа (о вкусах мы не спорим), и вообще ненормально, когда нейросеть должна научиться распознавать картинки с чихуахуа.


2.5 Kernel Bypass и zero copy

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

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

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

Это и называется Kernel Bypass.

Обработка пакетов в user space в обход ядра
Обработка пакетов в user space в обход ядра

Поскольку мы избегаем в таком случае копирования ядром данных из сокетного буфера в память приложения, этот механизм получил название Zero Copy.

Принцип Zero Copy
Принцип Zero Copy

Kernel Bypass vs Zero Copy

Тут важно не путать эти два механизма. Kernel Bypass часто использует Zero Copy. Но может и не использовать. Самое главное, что он исключает ядро вообще — всю его бюрократию и накладные расходы.

А Zero Copy — это механизм, предотвращающий лишние копирования, который может быть применён и за пределами kernel bypass.

Проведём такую аналогию: обычный путь через стек ядра — это магистраль с инфраструктурой, по которой можно ездить на ультразаниженной приоре, но между двумя точками она может идти очень окольными путями — с учётом особенностей рельефа и задач оптимальной логистики. А kernel bypass — это дорожка в лесу, которая может пролегать почти прямо, но доступна только на эндуриках.

Есть несколько хорошо известных механизмов обхода ядра.

Один из них — DPDK — в этом случае сетевая карта целиком отдаётся в User Space и хостовое ядро ничего о ней даже не знает.
Другой вариант — AF_XDP — расширение XDP, позволяющее перехватывать пакеты до попадания в сетевой стек ядра и крутить ими, как хочешь.
Это не обход прям ядра — скорее обход сетевого стека ядра.

И отдельный вид Kernel Bypass — это RDMA.


3. RDMA — Remote DMA

DMA позволяет сетевой карте взаимодействовать с оперативной памятью, не привлекая внимания санитаров ядро и процессор.
Вот как будет выглядеть взаимодействие приложений на разных серверах:

Путь трафика без RDMA
Путь трафика без RDMA

Но инженеры пошли дальше: они придумали, что при сетевом взаимодействии между машинами можно без участия процессора писать/читать не только локальную память, но и удалённую.
Представьте, что локальная сетевая карта пишет напрямую в удалённую память?
Это называется RDMA — Remote DMA.

Локальная сетевая карта, через DMA, минуя процессор, считывает данные из локальной памяти. Она заранее знает адреса блоков в удалённой оперативке, куда нужно эти данные положить и определённым образом помечает эти данные информацией, куда их нужно записать.
Далее по кабелю передаёт их на удалённую машину, где удалённая карта, вообще не задумываясь, кладёт полученные данные в нужный сегмент оперативки, используя DMA.
Причём эта память далее читается не ядром, а сразу приложением. То есть мы обходим и ядро, и перекладывание трафика из одного места в памяти в другое как на отправителе, так и на приёмнике.

И, грубо говоря, RDMA включает в себя всё:

  • DMA — для прямой работы NIC и RAM — уже совершенно стандартный механизм,

  • Kernel Bypass — ядро не участвует в обработке этих данных вообще никак — приложение получает напрямую данные,

  • Direct Placement — данные сразу же кладутся карточкой в область приложения,

  • Zero Copy — данные не нужно перекладывать в оперативке из области ядра в область приложения.

То есть RDMA — это фактически прямой доступ в самый мозг удалённой машины.

Вот как это выглядит:

Путь трафика c RDMA
Путь трафика c RDMA

И давайте иными словами

Приложения на разных машинах буквально напрямую общаются друг с другом, минуя все слои абстракции.
Мы выкидываем ядро из Data Path, выкидываем лишнее копирование между областями памяти через CPU, передаём всё приложению.

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

Так! Стоп!
Выкинули ядро! А кто будет заголовки всех уровней разбирать: Ethernet, IP, TCP? Пушкин?

Нуу.. Даа.. TCP больше нет.
Того самого родненького TCP/IP, который делает всю привычную работу по детекции ошибок, реализует пересылки потерянных сегментов, контроль порядка и дублирования пакетов.
Весь мусор можно навалить в удалённую память, с которой работаем теперь напрямую. Очень страшно.

Выкинули TCP — и слава богу!

А почему?


4. The Network. Скорости, задержки, TCP, InfiniBand, RoCE

4.1 Чем плох стек TCP+IP+Ethernet?

А всё просто — потому что все эти технологии создавались для решения конкретной задачи в конкретной области, но чудесным образом вышли далеко за пределы своих зон, причём со всеми своими компромиссами и недостатками.

Например Ethernet

Ethernet должен был всего лишь обеспечить связность устройств в пределах маленькой локальной сети — пары сотен узлов максимум. При этом это на заре технологии была общая среда — все устройства находились в одном кабеле и не могли общаться одновременно — одно ждало, пока другие не закончат говорить.

Роберт Меткалф и Радья Перлман — изобретатели Ethernet. Отсюда
Роберт Меткалф и Радья Перлман — изобретатели Ethernet. Отсюда

Сейчас это уже не так, но именно оттуда тянутся артефакты CSMA/CD в виде half-duplex-ных режимов работы порта и минимального размера Ethernet-кадра в 64 байта.

Локальной природой Ethernet объясняется и отсутствие поля TTL, и поля для хранения признака QoS в изначальной реализации. А ещё весь ворох проблем с Discovery, BUM-трафиком, недоиспользованием резервных линий и мучения с протоколами семейства STP.

Скудный заголовок Ethernet отсюда
Скудный заголовок Ethernet отсюда

Отсутствие маркировки QoS блокирует возможность замедления трафика в конкретной очереди, что важно для того, чтобы снять перегрузку.

А сегодня это отраслевой стандарт, натянутый на локальные, кампусные и глобальные сети, на сети систем хранения данных и суперкомпьютеры, на телефонные и телевизионные. И называется это Converged Ethernet (будь он неладен вместе со всеми своими костылями!).

Ну, в этом есть и плюсы — учить нужно только Ethernet, и забыть уже про Frame Relay, ATM, SDH, HDLC, Token Ring, Fibre Channel и другие.

Спасибо тебе, Роберт Меткалф!

Поправочка на самом деле: хоронить можно не все технологии. Вот старички ATM и SDH ещё вполне используются. Например, на гонках F1, команда Ferrari вполне себе из паддоков на трассе во Франкфурт заказывает гиг эзернета поверх SDH. А комментаторы гонки работают на ISDN BRI (автор статьи ни разу в жизни с ним не сталкивался — а он живой)

За не-историческую вставку спасибо Андрею Пазычеву.

А например IP

Был создан Винтоном Сёрфом и Бобом Каном в 1973-м, чтобы любые два устройства на планете (Ха! Типа мы закрываем глаза на МКС и Cтарлинки) могли связаться друг с другом.
Каждому устройству выдаётся уникальный идентификатор, который однозначно его определяет в глобальной сети.

В глобальной!

Винтон Сёрф — изобретатель IP. Отсюда
Винтон Сёрф — изобретатель IP. Отсюда

А когда вы строите вычислительный кластер или систему хранения данных, которые сами в себе варятся, вам IP на каждом узле не нужен по факту.
Тем более IPv4 — 32 бита, 4 млрд адресов — даже по одному адресу на человека не найдётся. А знаете почему? Потому что он задумывался как временный, чтобы сделать прототип. Но заменить его ни на что не успели — он врос корнями в каждое хоть сколько-то умное устройство на планете.
А IPv6 всем прекрасен — 128 бит. Но, опять же, бессмысленно большой заголовок и всё равно нужен какой-то шлюз доступа в IPv4-мир.

Ещё IP — это маршрутизация узел за узлом, hop-by-hop. Каждый узел на пути от источника до получателя принимает самостоятельное решение, куда отправить пакет. Ищет кратчайший путь. А это время.
Плюс, при наличии нескольких путей, разные пакеты данных могут приходить с разными задержками, теряться и даже путаться местами.

А раз могут, значит будут — даже не сомневайтесь.
И кто-то должен все эти косяки разгребать.
Ну а кто, если не вышестоящие уровни?

И тут появляется великий и ужасный

TCP

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

Кроме:

  • TCP требует установки и разрыва соединения,

  • У TCP есть дюжина разных реализаций управления скоростью и перегрузками,

  • У TCP большие накладные расходы при передаче коротких частых сообщений,

  • TCP остро реагирует снижением скорости на потери и рост задержки,

  • Весь контроль целостности, управление окнами, подтверждения, ретрансмиты, предотвращение и обработка перегрузок происходят на CPU.

Все оптимизации на kernel bypass и zero copy в пределах сервера мы просто выбросим в мусорное ведро, потому что сеть — это самый-самый-самый медленный компонент всей схемы. И если он ещё и косячно будет работать, то зачем всё это?

Из-за всего этого задержки доставки данных из конца в конец и доступная полоса могут плавать от Африки до Южной Америки.

Итого, то, что мы десятилетиями создавали, прекрасно работает в 95% случаев — Интернет буквально держится на TCO. Мы не радуемся, когда всё работает, мы замечаем и сердимся, когда Интернет не работает.
Но это будет из рук вон плохо работать в оставшихся 5%: в кластерах суперкомпьютеров или для обучения нейронок, или в СХД.

Вот давайте кинем первый взгляд, насколько всё действительно плохо.


4.2 Принцесса была прекрасная, система была ужасная

Мы уже видели в разделе 2.4, что происходит внутри хоста — теперь добавим к этому сеть.

Какой путь нужно проделать, чтобы скачать файл по HTTP:

  1. Приложение на клиенте должно сделать системный вызов в ядро для открытия сокета.

    …The CPU…

  2. Ядро формирует TCP SYN, упаковывает его в нужные заголовки и кладёт в свою область RAM через DMA.

    …The CPU…

  3. NIC забирает пакет из RAM и отправляет в сеть.

    …The Network…

  4. На каждом сетевом узле нужно сделать лукап пути до точки назначения в таблице маршрутизации/коммутации.

    …The Network…

  5. На удалённой стороне вызвать прерывание процессора, который в своём сетевом стеке снимет заголовки Ethernet, IP и TCP, обработает TCP SYN, подготовит и отправит TCP SYN-ACK.

    …The Network…

  6. Дождаться на локальной TCP SYN-ACK — прерывание процессора и обработка ядром.

    …The Network…

  7. Отправить ACK. Обычно этот ACK пиггибечится (piggyback) к данным. В данном случае отправляется вместе с HTTP-GET запросом.

    …The Network…

  8. Получить на сервере и обработать ACK в ядре. Сессия установлена

    …The CPU…

  9. Передать HTTP-GET приложению — для этого взять его из области ядра и переложить в область приложения в RAM.
    Теперь сервер может начать передавать данные.

    …The CPU…

  10. Сервер начинает записывать байтовый поток в свою область памяти в User Space.

    …The CPU…

  11. Локальное ядро копирует данные в область ядра, формирует заголовки и отправляет в сетевую карту.

    …The CPU…
    …The Network…

  12. На удалённой стороне сетевая карта пишет в область ядра. Ядро в свою очередь обрабатывает все заголовки, следит за целостностью потока, копирует полезную нагрузку в область приложения.

    …The CPU…

То же, но в mermaid

При этом это всё с негарантированным временем доставки

С возможными потерями.

С буферизацией на промежуточных хопах и в памяти конечного хоста.

И всё это многократно в процессе передачи файла. А самая дорогая операция на процессоре — это переключение контекста.

И всё это через CPU.
Ну кроме DMA между NIC и RAM

RDMA тут нет

 

Это даже читать неприятно, согласитесь? А каково процессору?

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

И тут на сцену и выходит InfiniBand, реализующий RDMA, когда от скачивания файла мы переходим к низкоуровневой передаче сообщений из памяти в память.


4.3 InfiniBand

Собственно InfiniBand (IB)— один из двух актуальных сетевых стеков, реализующий RDMA. Другой RoCEv2.

В него вшита сложная логика управления памятью, планирования очередей, борьбы с перегрузками и обеспечения столь важной для RDMA Lossless Low Latency сети.

Это совершенно иной, чуждый классическому сетевику, мир со своей собственной слоёной моделью, набором протоколов и механик.

На основе этого
На основе этого

Это отдельные сетевые карты, коммутаторы, трансиверы. Хотя внешне вы их не отличите.

Infinibang-всё: карта, DAC-кабель, коммутатор. Отсюда
Infinibang-всё: карта, DAC-кабель, коммутатор. Отсюда

Причём стек не просто предоставляет те же самые сервисы, что TCP/IP/Ethernet, только более лучшие, он изначально разработан и развивается под задачи HPC и в том числе обучения нейронок, а значит и решает специфические для них задачи (SHARP, SHIELD, Adaptive Routing).
Но обо всём об этом будет в отдельной статье.

То есть IB — это не альтернатива Ethernet, как может показаться, это альтернатива всему сетевому стеку.

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

Но!

Прелесть IB в том, что ты его поставил, включил — и он работает. Сразу хорошо, в общем-то даже прекрасно, почти идеально. RDMA через него летает.
И его не нужно настраивать.

Оговорка для принципиальных

Безусловно его нужно настраивать, и для этого есть даже SDN-контоллер Subnet Manager, но сложности IB против Ethernet несопоставимы.

Однако стремление к генерализации никуда не исчезло. Всем нужен кто? Ethernet. Правильно.


4.4 RoCE

Поэтому появился такой кадавр, как RoCE — RDMA over Converged Ethernet.
Здесь и далее мы говорим про RoCEv2. RoCEv1 упомянем и помянем в следующей статье.

Что придумали эти удивительные люди? Они взяли верхние слои InfiniBand, который обеспечивает работу RDMA, упаковали их в UDP (конечно, в UDP) и запустили это всё поверх Ethernet.
И ты его поставил, включил — а он не работает. Потому что для того, чтобы Ethernet+IP+UDP стал LossLess и Low Latency, нужно дьяволу душу продать.

Ну или не продавать, а просто настроить:

  • очереди QoS,

  • DSCP-mapping,

  • ECN,

  • PFC,

  • буферы коммутаторов,

  • MTU,

  • IRQ affinity,

  • KDE под Freebsd.

А если не настроить, будут потери сообщений RDMA, PFC Deadlock, Head-of-line-blocking, бесконечный срок обучения ваших нейронок.
Выгоднее душу дьяволу продать, да.

Победит ли RoCE InfiniBang в этой борьбе? Кто знает? Предлагаю обсудить в комментариях.

Вообще-то

перед нашим взором уже есть одна специальная сеть, которая медленно уступает в конкуренции с Ethernet — Fibre Channel для SAN (Storage Area Network). Она сначала должна была уступить место FCoE (Fibre Channel over Ethernet), но в итоге в этой гонке побеждает NVME over Fabric over Ethernet.
FC при этом продолжает использоваться в enterprise SAN в банках, телекомах и некоторых крупных ДЦ.

При этом, что любопытно, FCoE — это ровно RoCE в мире FC — взяли протокольный стек FC со всей его архитектурой и перенесли на другую физику.

Но с IB и RoCE мы будем разбираться в отдельных статьях.


5. А что у них? Nvidia: NVLink, GPUDirect RDMA

Пожалуй, последнее, чего коснёмся в этой статье, — это ультимативные ходы Nvidia: NVLink и GPUDirect RDMA.

Тут нам нужно мельком взглянуть на то, как устроен сервер с GPU-картами.
GPU-сервер на текущий момент — это 8 GPU-карточек.

GPU-сервер с восемью GPU-картами без радиаторов. Отсюда
GPU-сервер с восемью GPU-картами без радиаторовОтсюда

У каждой карточки на борту своя собственная память VRAM — аналог системной RAM.
В случае датацентровых GPU, вроде H100/B100, сверхбыстрая память HBM находится на том же самом интерпозере, что собственно чип GPU

VRAM, расположенная прямо на той же подложке, что чип GPU. Уже не помню откуда — картинок таких миллион.
VRAM, расположенная прямо на той же подложке, что чип GPU. Уже не помню откуда — картинок таких миллион.

5.1 PCIe и NVLink

В классической архитектуре все GPU соединялись бы друг с другом через универсальную шину PCI-Express.

Общая универсальная шина PCIe. Осторожно: нейроконтент на основе этого
Общая универсальная шина PCIe. Осторожно: нейроконтент на основе этого

Но с PCIe есть некоторые проблемы для высокоскоростных вычислений. Собственно, потому что это тоже универсальное общее решение.

  1. Не все архитектуры и драйверы поддерживают прямое общение между периферийными устройствами.
    Трафик между двумя GPU может передаваться через RAM или даже CPU, проходя через шину PCIe дважды

  2. Скорость PCIe Gen5 — это 126 ГБ/с full-duplex на слот (×16), то есть фактически 63 ГБ/с в одном направлении.
    И это (63 ГБ/с × 8 Бит/Байт = 504 Гб/с) уже сравнимо с 400 Гб/с, которые даёт сеть. И заметно меньше 800 Гб/с, шагающего по планете. То есть PCIe становится узким местом.

  3. При массивном обмене данными между 8 GPU внутри одного сервера, шина PCI становится узким горлышком.

Nvidia разумно решила, что играть в этом архитектурно-топологическом цирке ей неинтересно, и соединила между собой все GPU на одном хосте специальной сверхбыстрой сетью — NVLink, в обход всех процессоров, PCI-шин и оперативок.

NVLink
NVLink

Скорость NVLink Gen 4 — 900 ГБ/с с каждой GPU. А Gen5 — уже 1800.

И это по сути превращает 8 карточек, каждая со своей «видеопамятью» VRAM, в одну виртуальную, с общей памятью. И одна GPU может читать из памяти другой напрямую, будто бы это её собственная: GPU0 → NVLink/NVSwitch → GPU1 VRAM

И тут мы прослеживаем прямую аналогию с RDMA, только в пределах сервера — в NVLink это называется просто P2P — peer-to-peer.


5.2 GPUDirect RDMA

Внутри сервера используется проприетарная сверхбыстрая сеть NVLink со своими технологиями прямого доступа к памяти.
Но при этом на сервере каждой GPU-карты выделяется ещё и свой собственный интерфейс наружу для соединения с остальной частью кластера. Соединяются друг с другом они всё так же через PCIe.

Также мы знаем, что помимо оперативной памяти хоста у нас есть ещё «видеопамять» VRAM, располагающаяся прямо на чипе GPU, которая хранит в себе как сами параметры модели, так и промежуточные вычисления, которыми надо обмениваться.

Изначально сетевые карты с поддержкой RDMA умели работать только с системной оперативной памятью серверов RAM. Но GPU-кластеры хранят данные во встроенной памяти (VRAM), а сетевая карта раньше не умела туда стучаться.

Выглядело это так: VRAM (GPU) ➔ шина PCIe ➔ RAM (CPU) ➔ шина PCIe ➔ Сетевая карта ➔ IB/RoCEv2 ➔ Сетевая карта ➔ шина PCIe ➔ RAM (CPU) ➔ шина PCIe ➔ VRAM (GPU).

Путь трафика от GPU в кластер за пределы сервера через PCIe
Путь трафика от GPU в кластер за пределы сервера через PCIe

Данные приходилось копировать через CPU и RAM. Это создавало очень узкое «бутылочное горлышко».

Даже с обычным RDMA, когда удалённый хост пишет напрямую в оперативку, нужно на скорости 100/400/800 Гб/с прокачивать через внутреннюю шину PCIe данные дважды! Сначала сетевая карта пишет в оперативку (DMA), а потом из неё GPU перекладывает данные в свою видеопамять.

Путь трафика от GPU в кластер за пределы сервера через PCIe
Путь трафика от GPU в кластер за пределы сервера через PCIe

Проще сжечь и выбросить! Это невозможно! Мы покупаем дорогущие коммутаторы и карточки, а узким местом становится шина PCI-E, а точнее даже оперативная память, которая участвует здесь как буферная зона.

И тут на сцену выходит GPUDirect RDMA — это технология Nvidia, которая позволяет сетевой карте обращаться напрямую в VRAM GPU.
Тут, как и в случае обычного RDMA, CPU принимает участие только на стадии регистрации адресов, прав доступа, но не при фактической передаче данных.

Итого при получении или передаче данных оперативку не трогаем, процессор не отвлекаем, PCIe задействован только один раз.

А фреймворки, вроде PyTorch, в свою очередь управляют всем этим.

В итоге, вот как выглядит альтернативная архитектура Nvidia: GPUDirect RDMA для работы с другими серверами, и NVLink между GPU внутри одного сервера:

Сумма технологий
Сумма технологий

И тут возникает вопрос, а зачем тогда мы разбирали Kernel Bypass, Zero Copy и RDMA, если в современных кластерах Nvidia всё по-другому?
Так а не по-другому! Как раз таки:

  • GPUDirect RDMA — это и есть RDMA, просто не в оперативку сервера, а в VRAM. Тут не используется процессор.

  • Zero-Copy — никакого копирования в оперативку сервера, как должно было бы быть в классике, — пишем сразу в VRAM.

  • Kernel Bypass — при получении данных, никаких прерываний в ядро и вообще его посредничества.

Nvidia взяла все эти «костыльные» технологии и собрали из них нечто действительно крутое и производительное.

И вот казалось бы — осталось совместить NIC с видеокартой — и весь остальной компьютер не нужен. Верно? GPU пишут друг другу в VRAM-ы через свои собственные NIC-и, в пределах сервера NVLink, за пределами — IB. Зачем тогда CPU, RAM, PCIe и всё остальное?

Ну вы интересные! Управлять-то всем этим всё равно нужно:

  • Электропитание и охлаждение,

  • Запуск и контроль всей системы,

  • Долговременное хранение данных,

  • Программирование нового обучения и, соответственно, подгрузка данных для него или инференс,

  • Получение и обработка результатов.

Можно, конечно, это всё засунуть в GPU, но тогда.. oh wait.. мы же получаем CPU.


6. Суммируем

Давайте взглянем на всю картину издалека.
Мы хотим создать систему, которая занимается обучением и инференсом нейросетей. Эффективно.
Как мы помним из прошлой части, это предполагает обмен информацией: регулярный, большими объёмами, но зачастую небольшого размера.

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

Вот так выглядит процесс обучения в плохо построенной сети:

Чуть лучше ситуация, когда сеть просто приходится ждать:

В ожидании сети кластер проводит 20% времени
В ожидании сети кластер проводит 20% времени

И для того, чтобы то, на что потратили миллиарды долларов, не простаивало 20% времени (а то и все 50%), нужно правильно проектировать сеть — все сегменты от памяти одного компьютера до памяти другого.
И везде, где можно срезать пару миллисекунд, их нужно срезать.

  1. Специализированные чипы (GPU, TPU) — позволяют параллельно выполнять множество операций, что не доступно процессору общего назначения.

  2. DMA — позволяет сетевой карте работать с памятью напрямую, не обращаясь к процессору.

  3. Kernel-bypass — исключает обработку трафика ядром ОС вообще — он улетает напрямую в приложение, минуя область ядра.

  4. Zero-copy — исключает лишнее перекладывание данных с места на место, а соответственно и экономит циклы процессора.

  5. RDMA — это синергия всех механизмов выше, которая позволяет приложению на разных хостах общаться, просто напрямую обращаясь в память друг друга.

  6. GPUDirect RDMA — задействует не системный RAM хоста, а VRAM — память на GPU.

  7. InfiniBand — протокол, реализующий RDMA, а также, на фоне TCP/IP/Ethernet, делает последний вклад в эффективность, срезающий микросекунды на поворотах реальной сети, а ещё и участвующий в коллективных вычислениях при работе с нейросетями.

  8. RoCEc2 — как альтернатива InfiniBand.

И вся вот эта ядрёная комбинация пробивает молотом Тора все слои абстракции, любовно создаваемые инженерами все прошлые десятилетия.

Давайте теперь, чтобы не быть голословными, всё это переложим уже на какие-то приблизительно реальные цифры и поймём, а даёт ли это всё какие-то преимущества на самом деле?

6.1 Упрощённый расчёт

Сначала возьмём упрощённый случай: передачу 100 кБ данных через сеть 100 Гб/с.
В одном случае скачаем их по HTTP, в другом передадим через RDMA Message.

Простой случай

Этап передачи

Стандартный стек (Linux TCP/IP + Ethernet)

Оценка времени (TCP) мкс

Стек InfiniBand с RDMA (Mellanox/NVIDIA HCA)

Оценка времени (мкс)

1. Инициация

Приложение вызывает send()Переключение контекста (User Space → Kernel Space).

~0.5 — 1.0

Приложение пишет Work Request напрямую в очередь NIC через Memory Mapped I/O. Без syscall'ов.

~0.1

2. Доступ к памяти

CPU копирует 100 кБ данных из буфера приложения в буфер сокета (sk_buff) в ядре.

~2.0 — 4.0

Zero-copy. CPU не трогает данные. Сетевая карта (HCA) сама читает 100 кБ из RAM через DMA.

0

3. Транспортный уровень

Процессор ОС нарезает данные, формирует заголовки TCP/IP, пишет дескрипторы в Ring-буфер драйвера.

~1.5 — 3.0

Обработка транспорта (нарезка, подтверждения) происходит аппаратно внутри чипа сетевой карты (HCA).

0

4. Передача по кабелю

NIC по кускам отправляет 71 кадр Ethernet (MTU 1500) на 100 Гб/с.

~8.7

HCA отправляет 25 пакетов InfiniBand (MTU 4096) на 100 Гб/с.

~8.3

5. Прием

NIC принимает пакеты и генерирует аппаратные прерывания (IRQ). ОС запускает SoftIRQ (NAPI).

~1.0 — 2.0

Пакеты поступают в HCA. Транспортный уровень обрабатывается чипом без привлечения ЦПУ хоста.

0

6. Транспортный уровень

ОС собирает TCP-пакеты, проверяет чек-суммы, сортирует пакеты (TCP Reassembly).

~1.5 — 3.0

HCA сам собирает данные и пишет их напрямую в память приложения-получателя по локальному DMA.

0

7. Передача приложению

Приложение вызывает read(). CPU копирует 100 кБ из ядра в память приложения (User Space).

~2.0 — 4.0

Приложение просто читает Completion Queue (CQ) из User Space или получает lightweight event.

~0.1

---

---

---

---

---

ИТОГО задержка End-to-End

App-to-App Latency

~17.2 — 25.7

App-to-App Latency

~8.5 — 9.5

Нагрузка на CPU (такты)

Сотни тысяч тактов процессора на копирование и прерывания.

Высокая

Считанные такты на запись "звонка" (doorbell) в шину PCIe.

Околонулевая

Сравнительный дашборд RDMA-TCP
Сравнительный дашборд RDMA-TCP

При передаче 100 кБ на скорости 100 Гб/с через TCP/Ethernet сама физическая передача данных по кабелю занимает ~8.7 микросекунд, а еще 10–15 микросекунд данные «тормозят» в процессорах и оперативнке отправителя и получателя.

В случае с InfiniBand/RDMA, CPU отправителя и получателя практически не участвуют в процессе. Передача 100 кБ происходит со скоростью, близкой к физически возможной. Общее время стремится к чистым ~8.5–9 микросекундам .
Время передачи по сети одинаковое — 8 мкс. В случае RDMA накладные расходы на обработку на хосте (1 мкс) — это 10% общего времени, а в TCP (~12 мкс) — 60%.
И по грубым расчётам даже в лоб выигрываем в 2 раза чистого времени. Или в 12 раз, если считать накладные расходы, исключив время передачи по сети.

Если же взять передачу 1 МБ, то цифры будут такие:

  • TCP/Ethernet: ~220 мкс

  • RDMA/InfiniBand: ~86 мкс

Физическое время передачи самих битов 1 МБ по медному/оптическому кабелю на 100 Гб/с составляет ~84 мкс. RDMA передает данные почти со скоростью провода, а TCP добавляет больше 100 мкс задержки на копирование памяти и работу ядра ОС.


6.2 А что там у серьёзных мужчин?

А там всё интересно.
Дело в том, что на первый наивный взгляд накладные расходы с ростом масштаба остаются неизменными для IB+RDMA, и растут линейно для Ethernet+TCP.
Ведь каждый дополнительный байт нужно будет 2–3 раза провернуть через CPU и RAM.

Но на второй грубый и реалистичный взгляд для Ethernet+TCP это будет что-то более близкое к экспоненте, потому что в случае TCP проблемы копятся, как снежный ком, и резко замедляют всё.

Давайте теперь прикинем цифры для одного шага обучения GPT-3 на кластере в 1000 карточек и с сетью 100 Гб/с.
Полный размер 175 млрд двухбайтовых параметров — 350 ГБ.

Что за старьё? GPT-3 в 2026? Серьёзно?

Ну, я, может, и хотел бы показать на примере GPT-5 .5 или Gemini 3.1, но там есть сложности с актуальными цифрами.

При синхронизации градиентов на этапе All Reduce каждый узел должен, если вспомнить формулу из прошлой части, передать 2 × (N–1)/N × 350 ГБ = 700 ГБ.

Визуальный спойлер, к котором стоит вернуться после прочтения этой главы:

Сравнение RDMA и TCP для обучения GPT-3
Сравнение RDMA и TCP для обучения GPT-3

6.2.1. RDMA + GPUDirect + InfiniBand

В случае RDMA с GPUDirect поверх InfiniBand мы используем почти полную полосу в 100Гб/с — в расходы на заголовки уходит меньше 2%.

Чистое время передачи 700 ГБ:

  • InfiniBand700 ГБ / 12.25 ГБ/с = 57.14 с. Эта цифра зависит от объёма трафика57.14 с

  • PCIe700 / 63 = 11.11 с. Эта цифра тоже зависит от объёма трафика. Но! Она не делает вклад в общее время, потому что NIC сразу кладёт данные в VRAM GPU, и узким местом, поставляющим их «медленно», является 100 Гб/с сеть, а не 504 Гб/с PCIe.

Накладные расходы на CPU

Около 3 мс. Они включают в себя всю обработку на хосте. Эта цифра зависит только от числа сообщений, которое фиксировано для алгоритма.
3 мс

Итого чистое время

получается около 57.14 с, потому что сеть и CPU не складываются.

57.14 с

Откуда дровишки?

Почему делим на 12.25?
100 Гб/с — это 12.5 ГБ/с.
Однако полезная пропускная способность — ещё минус 2% заголовков, то есть 0.25 ГБ/с: 12.5 – 0.25 = 12.25

Почему PCIe 63 ГБ/с, а не 64?
Кодирование 128b/130b (для самосинхронизации), превращает 64 ГБ/с в 63: 64 * 128 / 130 = 63.015

Почему расходы 3 мс?
Берём 1.5 мкс на передачу одного сообщения и умножаем на количество сообщений (считали выше), которое должен передать каждый хост за один шаг All Reduce: 1998.
1998 берётся из формулы 2 (N–1), где N — число карточек в кластере (1000).1998 1.5 мкс = ~3 мс


6.2.2 TCP/Ethernet (без RDMA)

Время передачи 700 ГБ:

  • Ethernet700 ГБ / 11.25 ГБ/с = 62.22 с. Что ж, неплохо. Это мы изъяли 10% на заголовки и ACK-и — с некоторым консервативным запасом.

    62.22 с

  • PCIe(700 ГБ / 63 ГБ/с) * 2 = 22.22 с. Умножаем на 2, потому что через PCIe нужно прогнать данные дважды:NIC --(DMA через PCIe)--> RAM (буфер ядра) --(копирует CPU)--> RAM (буфер приложения) --(DMA силами GPU через PCIe)--> VRAMДва раза через PCIe, два раза через шину CPU-RAM.Но, как и в случае с IB+RDMA тут у нас труба, через которую течёт трафик, поэтому время определяется самым узким местом — пока это Ethernet.

  • Memory bus(700 / 200) * 2 = 7 с. Это интерфейс CPU-RAM — проходим его туда и обратно, два раза. Тоже меньше 62.22 с, поэтому не складываем.

62.22 с

Накладные расходы

Теперь считаем накладные расходы на TCP. Самая главная засада с ним — это обработка на CPU и .. ну естественно, универсальность самого протокола.
Здесь следующие составные части: системные вызовы, прерывания, переключение контекста, обработка TCP ACK и можно ещё присовокупить механизмы congestion avoidance и congestion control, но мы пожалеем бедный TCP.

  • Syscalls. Стоимость одного — порядка 300 нс. Нам потребуется 1998 send() и 1998 recv(). Итого 1998 2 300 нс = 1 198 800 нс = 1.2 мс.

    1.2 мс

  • Прерывания. Если мы возьмём размер TCP-сегмента 8960 (Jumbo-frame), то для передачи 700 ГБ нужно будет 700 000 000 000 Б / 8960 Б = 78 125 000 сегментов. При получении каждого из 78 млн сегментов нужно 1 прерывание на отправителе и 1 на получателе. Стоимость каждого около 2 мкс. Получается 78 125 000 2 мкс 2 = 312 500 000 мкс = 312.5 с. Но обычно NIC всё же группирует прерывания, условно по 64 штуки, поэтому тут можно немного сэкономить: 78 125 000 / 64 2 мкс 2 = 4 882 812 мкс = 4.88 с — HARD IRQ. Но каждую пачку нужно ещё обработать в SOFT IRQ — а это ещё примерно по 50 мкс на пачку: 78 125 000 / 64 50 мкс 2 = 122 070 312 мкс = 122 с.

    127 с

  • По-ACK-ать каждые 2 TCP-сегмента с данными: 78 125 000 / 2 * 2 мкс = 78 125 000 мкс = 78 с

    78 с

  • Переключения контекстов. По грубой оценке 20 000 000 штук по 3 мкс каждое: 20 000 000 * 3 = 60 000 000 мкс = 60 с.

    60 с

Итого накладные расходы: 0.0012 + 127 + 78 + 60 = 265 с.

На самом деле всё не так, как в действительности

Мы рассматриваем здесь CPU с одним ядром, что нехарактерно для настоящего времени, где у серверных платформ под сотню ядер. И сетевую нагрузку можно распараллелить между ними. Тогда задержки на CPU не будут узким местом, что, впрочем, никуда не убирает сжигание процессорного времени.

Но CPU и сеть — это тоже части трубы. Тут мы их тоже не суммируем, а берём самую узкую часть — CPU 265 с.
265 с в TCP против 57.14 с в IB+RDMA. Разница в 4,6 раза, если считать по бутылочным горлышкам (в RDMA это сеть, а в TCP/Ethernet — CPU).
И тут важно держать в уме, что это всё прокручивается через  CPU:

  • Он ставит и держит тысячу TCP-сессий,

  • Он обрабатывает сетевые заголовки,

  • Он врукопашку копирует данные из буфера ядра в буфер приложения,

  • Он должен прерваться и сообщить GPU, что для него есть данные в RAM,

  • И все связанные с этим прерывания и переключения контекста.

То есть если в случае IB+RDMA CPU, RAM и ядро не задействуются вообще никак и с ростом объёма трафика накладные расходы остаются неизменными, то в случае TCP они растут как минимум линейно. CPU просто захлёбывается в обработке пакетов, PCIe и Memory bus залиты.
Ещё один негативный вклад CPU — это непредсказуемые задержки и как следствие плавающий джиттер. Из-за работы планировщика, прерываний, никаких гарантий на время обработки заголовков, копирования пакетов и даже прерываний — нет: где-то он добавляет 50 мкс, а где-то 1000.

И ещё раз посмотрим на эту картинку:

Сравнение RDMA и TCP для обучения GPT-3
Сравнение RDMA и TCP для обучения GPT-3

И это всё, если мы не будем сейчас брать congestion-механизмы TCP.
А если будем?

Собственно TCP, конгестия и здрасьте

В ДЦ средний процент потерь около 0.01%. Выглядит как пренебрежимо мало. Но давайте посчитаем: 78 125 000 0.01% = 7812.5. 7812 пакетов фьють — как с куста. Опять же, вроде немного. Но проблема тут в RTO (Retransmit Timeout) — в обратной связи о потере. Стандартный таймаут — 200 мс. А это значит — 7812.5 200 = 1 562 500 мс = 1562.5 с. 26 МИНУТ плюсом. Они просто стирают в пыль все и без того гигантские накладные расходы TCP без RDMA.

Лааадно, давайте без лишней драматизации. RTO зависит от RTT (Round Trip Time). В ДЦ задержки обычно <1 мс, поэтому и RTO может скрутиться до, например, 10 мс. И тогда получается всего лишь 80 добавочных мс.

Хах! Попались?!
В TCP есть механизм Fast Retransmit. Он не ждёт на самом деле никакой RTO. Если отправитель не увидел один ACK, но зато увидел несколько следующих, то он тут же фиксирует потерю и перепосылает потерянный пакет. То есть тут речь, скорее, о единицах миллисекунд.
И вклад в увеличение задержек будут делать Out-of-orderFast recovery и Slow Start. А они будут, потому что будут потери — Ethernet по природе своей Lossy-сеть. TCP призван уметь работать с потерями — и он это делает — на каждую потерю сбрасывает скорость, чтобы снять перегрузку и медленно её начинает набирать.

А когда кластер завершил шаг и обменивается градиентами — все тысячи узлов начинают единомоментно слать в сеть свои кусочки данных. Они небольшие, но их много — случается TCP Incast — и как следствие дропы, а значит снижение скорости и перепосылка потерянных сегментов.

Реалистичный вклад: единицы–десятки мс на ретрансмиты + просадка скорости от congestion control.

Вот почему важно обеспечить абсолютно lossless-сеть в кластерах для высокопроизводительных задач.


Думаете, это всё?

Да как бы не так! Это ведь мы ТОЛЬКО про сеть говорили.
А тут есть ещё что упомянуть и про вычисления.

GPU считают очень быстро, но они не делают это автономно: их нужно постоянно кормить — поставлять данные для расчётов.
И речь не про промежуточные расчёты, вроде градиентов или весов — нет, а про именно поставку новых внешних батчей данных, токенов для обучения.
Как это происходит? CPU считывает данные из хранилища — локального или сетевого, подаёт их в оперативку и инструктирует GPU, что это всё можно забрать к себе в VRAM.
Значит, он тоже использует циклы процессора и каналы memory bus и PCIe.

И значит, в случае TCP поставка данных и обмен градиентами будут конкурировать за одни ресурсы — циклы CPU, полоса PCIe и memory bus.
А значит, всё будет дополнительно замедляться.

Ну и собственно, CPU — это чип общего назначения, работающий последовательно, а значит с прерываниями. Чем большим количеством задач он занимается, тем больше прерываний, приключений контекста. И это всё приводит к плавающим задержкам.

А с ростом скоростей и объёмов передаваемых данных ситуация становится драматически хуже — CPU, RAM и PCI будут захлёбываться трафиком.

Итого, в случае TCP без RDMA GPU в плохом сценарии может простаивать 30–40% времени. Супер-дорогущие GPU. Супер! Простаивают 30–40% времени!

 

Давайте напоследок прикинем это всё в универсальной обменной единице

По экспертной оценке консилиума нейросетей обучение GPT-3 на кластере из 1000 шт. H100 заняло бы по грубой прикидке 12 дней — с IB и GPUDirect RDMA.
Для TCP возьмём нетравмирующий консервативный коэффициент 30% — получается 17 дней (12 1/(1 – 0.3)).
Стоимость часа аренды кластера в 1000 карточек Nvidia H100 — 
около 4000 $. 12 дней непрерывных вычислений будут стоить 12 24 * 4000 = 1 152 000. А 17 — 1 632 000. Сверху — 480 000 долларов.

На самом деле разница будет, скорее, в разы, чем в десятки процентов.

Ещё раз

Хочется как-то ещё раз просуммировать, не находите?

В IB + GPUDirect RDMA NIC пишет данные напрямую в VRAM GPU-карты через PCIe, используя DMA, минуя CPU, RAM, Memory bus.
Никакого копирования и двойного использования PCIe.
CPU полностью исключён из пути трафика. Он принимает участие в подготовке, но это константное время — об этом мы поговорим в части, посвящённой RDMA.
Нет никаких сессий, нет заголовков, которые должен обработать CPU, нет планировщиков, вносящих непредсказуемые задержки. Всё квадратно-гнездовое, прогнозируемое и скучное.
Время сравнимо с временем передачи по сети.

Путь коммуникации между GPU при GPUDirect RDMA
Путь коммуникации между GPU при GPUDirect RDMA

TCP же — это нескончаемое веселье. Весь трафик ходит через CPU. PCIe и Memory Bus нагружаются дважды. Тысячи сессий нужно устанавливать и поддерживать. Планировщик вносит джиттер. Пакеты теряются и перепосылаются. TCP сбрасывает скорость. CPU сгорает от нагрузки.

Реабилитация TCP

Всё же не нужно вколачивать гвозди в гроб TCP — нам с ним ещё жить.
Давно придуманы и работают механизмы выноса обработки некоторых операций с CPU на сетевые карты (Hardware Offload): таких как контрольные суммы, TSO и LRO.
Появились даже специальные «умные» сетевые карты: SmartNIC и DPU (Data Processing Unit), реализующие сложную логику, которую слишком дорого или невозможно «запечь» в виде жёстко заданной ASIC‑логики классических адаптеров.

Есть NAPI, который из режима прерываний от NIC переключается в режим поллинга NIC при высокой нагрузке.
Есть Interrupt Coalescing (агрегация прерываний), когда сетевая карта микросекунды копит пачку прилетевших пакетов в буфере, чтобы дернуть процессор прерыванием лишь один раз, а не спамить его на каждый пакет.
Есть те же Kernel Bypass и Zero Copy.
Есть Receive-Side Scaling, когда разные TCP-потоки распределяются в разные аппаратные очереди и обрабатываются разными ядрами — по сути балансировка по ядрам.

Но обо всём этом в другой раз.

Просто вместе со всеми оптимизациями TCP всё ещё драматически плох для задач высокой производительности, но не настолько катастрофически.


7. Заключаем

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

Давайте будем честными? Вся эта архитектура, мягко говоря, выглядит как костыль: мы ломаем абстракцию ради скорости.
Просто бросили молот на весь стек, он пробил брешь во всех слоях, а мы и рады успевать подставлять подпорки, чтобы это всё не рухнуло.

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

Нам ведь не приходит в голову называть костылём выделенные полосы для автобусов или приоритет служебных автомобилей с проблесковым маячком?

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

Примечание для нейрофизиологов

Можно найти ряд таких оптимизаций в природе и в нас.
Животные движимы в первую очередь инстинктами. Это более древние и базовые механизмы выживания. Сверхбыстрые, реактивные.
Ешь, размножайся, бей, беги, замри. Если больно — одёрни лапу. Если видишь орущего сородича — беги от него. Если видишь красивую самку — беги к ней. Итд.
Это лимбическая система.

Со временем жизни в социуме появились более сложные и медленные реакции. Общаться самому, отслеживать общение между сородичами, замечать слухи, плести интриги, оценивать долгосрочные последствия своих действий, прогнозировать события. Многие явления стали проходить через наш «процессор».
Это лобные доли.


Про «если больно — одёрни лапу» интересно, кстати, — вообще говоря, это спинномозговой рефлекс. До того, как сигнал дойдёт до головного мозга, он замыкается в спинном (говорят, рефлекторная дуга замкнулась в спинном моззгу), чтобы сэкономить миллисекунды RTT на быструю реакцию. А уже потом он доходит до головы и вызывает реакцию: злость, страх, порыв бежать с этого места, запомнить обидчика.
То есть тут прямая аналогия оптимизациям, описанными выше.
Ещё нагляднее было в эпоху динозавров: при длине их тела в десятки метров, сигнал до мозга шёл бы СЕКУНДЫ. Хищник буквально успеет отгрызть хвост, пока мозг осознает опасность. Поэтому Бог, создавший для людей kernel, добавил в стандартную комплектацию динозавров маршрутизатор в области таза, решающий проблему высокого сетевого пинга. Этот маршрутизатор умеет быстрее принимать решения о том, что делать с сигналом — поэтому быстрая реакция происходит в пределах секунды, а осознание может быть хоть через минуту

30 метров стеганозавра
30 метров стеганозавра

Есть также такие действия, которые сначала пропускаются через «процессор», но со временем происходит запоминание и срезание пути.
Во время танца, когда вы только учитесь, сгорают от напряжения префронтальная кора, гиппокамп, моторная кора. Каждое микродвижение организма проходит через длинный путь в мозге: планирование, прогнозирование, пробы, ошибки, обратная связь.
И так много раз.
Но мозг не дурак тратить свои циклы на то, что повторяется часто. Он перекладывает часть автоматических операций на свои «микросхемы»: базальные ганглии и мозжечок. А префронтальная кора освобождается от рутинных операций, хотя и после автоматизации через неё продолжают проходить сигналы.

Так и на высокопроизводительных кластерах сложные задачи снимаются с процессора CPU и передаются на специализированные микросхемы GPU/TPU.

Путь очень похож: врожденная программа (инстинкт/рефлекс) → сознательный контроль и расчет (мышление) → выученная программа (навык/привычка) и специальные схемы → универсальный процессор → специальные схемы.

То же самое, но в других терминах: у Даниеля Канемана в «Thinking Fast, Thinking Slow» — это система 1 и система 2. Первая отвечает за быстрое принятие решений, основанное на инстинктах, опыте, шаблонах, а второе — за сложные решения, требующие оценки последствий и прогнозирования.

В следующих статьях мы начнём погружаться в устройство GPU, RDMA, InfiniBand и RoCE, чтобы понять, как они работают и за счёт чего в них достигается оптимизация.


Ссылки


Спасибы

  • Никите Балабаеву за вычитку и замечания.

  • Александру Демиденко за фактические дополнения и корректировки.

  • Дмитрию Афанасьеву aka fl0w за комментарии из мира больших моделей, кластеров и серьёзного железа.

  • Павлу Остапенко за «я почти дочитал, но претензий нет(».

  • Вере Князевой за очень пристальное внимание к синтаксическим ошибкам и опечаткам. Все «, — » — это от неё.

  • Ольге Михайловне Базановой за рецензию вставки про нейрофизиологические аналогии.

  • Gemini 3.1

  • ChatGPT5.5 (проверять Gemini и рисовать нейроконтент)

  • Claude Sonnet 4.6 (проверять ChatGPT)

  • Алиса AI (когда нужны ссылки)

  • Qwen Coder 450B (когда кончились лимиты)

  • DeepSeek 3.1 (когда кончились лимиты, но нужно проверить Qwen)

  • NanoBanana 2 (рисовать нейроконтент)

Комментарии (0)