Mise en œuvre pratique du RDMA + Conception de liaison montante en cluster

Les articles précédents de la section N plaidaient en faveur du RDMA (N02) et a passé en revue les choix de topologie (N04, N05). Voici la partie pratique : installer les pilotes, vérifier que le chemin d’accès fonctionne, activer GPUDirect, valider NCCL, puis passer à la vitesse supérieure et réfléchir à la manière dont l’ensemble du cluster se connecte au monde.

Nous supposons l'utilisation d'Ubuntu 22.04 ou 24.04, de cartes réseau Mellanox/NVIDIA ConnectX-5 ou ConnectX-6, et d'une interface InfiniBand HDR/NDR ou RoCEv2 sur un réseau Ethernet sans perte. Les commandes sont celles que nous saisissons sur les bancs de test Kentino avant l'expédition d'un cluster K-AI à 4 nœuds.

Pilotes : MLNX_OFED ou en amont rdma-core?

Chemin Ce que vous obtenez Quand le cueillir
MLNX_OFED (maintenant NVIDIA DOCA-OFED) Ensemble de pilotes testés par NVIDIA, GPUDirect peermem, perftest, mlxconfig Clusters d'IA de production avec ConnectX-6/7 et GPUDirect
En amont rdma-core + dans l'arbre mlx5 Ce qu'Ubuntu fournit, aucun dépôt supplémentaire Boîtiers de laboratoire, nœud unique, sans GPUDirect, sans outils de firmware

Pour tout système transportant du trafic NCCL en production, installez MLNX_OFED. mlx5 Ça marche, mais tu perds. mlxconfig, le groupé perftestet — plus important encore — un côté noyau nvidia-peermem testé par rapport au même arbre OFED.

Installation propre sur Ubuntu 22.04 avec noyau 5.15.x :

tar xf MLNX_OFED_LINUX-*.tgz && cd MLNX_OFED_LINUX-*
sudo ./mlnxofedinstall --add-kernel-support --with-nvmf --force
sudo /etc/init.d/openibd restart && sudo systemctl enable openibd

Le --add-kernel-support L'indicateur est important. Si vous l'omettez sur un noyau hors de la matrice OFED, la compilation DKMS échouera silencieusement ; vous utiliserez alors la version par défaut. mlx5 sans le savoir. Confirmez la pile d'espace utilisateur avec dpkg -l | grep -E 'libibverbs|rdma-core|mlnx-ofed'.

Activez la liaison et vérifiez que la carte réseau détecte bien le réseau.

Trois commandes vous disent tout ce qui est important :

sudo mst start && mst status   # firmware tools
ibstat                          # port state, width, speed
ibv_devinfo -v                  # GIDs, max_qp, MTU, hw revision

Un port sain montre State: Active, Physical state: LinkUp, l'attendu Rate: (par exemple 200), et le droit Link layer: (InfiniBand ou Ethernet). Les deux domaines souvent négligés :

  • Link layer: InfiniBand vs Ethernet. Un ConnectX à double mode se retourne avec mlxconfig -d /dev/mst/mt4125_pciconf0 set LINK_TYPE_P1=2 (1=IB, 2=Ethernet). Redémarrage requis.
  • Rate: Correspond à la vitesse attendue. Un port NDR 200 Gb/s fonctionnant à 100 Gb/s est la panne silencieuse la plus courante : câble défectueux, longueur de convertisseur numérique-analogique incorrecte ou port du commutateur forcé à l’état bas. Vérifiez avant d’effectuer des tests de performance.

Sur RoCE, vérifiez également que v2 est sélectionné (v1 correspond à ethertype 0x8915, v2 à UDP/4791 et est utilisé par toutes les piles modernes) : sudo cma_roce_mode -d mlx5_0 -p 1 -m 2.

Gestionnaire de sous-réseau (InfiniBand uniquement)

InfiniBand n'est pas Ethernet : aucun trafic n'est routé sur le réseau tant qu'un gestionnaire de sous-réseau (SM) n'a pas attribué d'identifiants de liaison (LID). Sur un réseau de laboratoire, sudo apt install opensm && sudo systemctl enable --now opensm Sur un seul nœud. En production, exécutez le SM intégré sur le commutateur. Deux SM logiciels en concurrence représentent un après-midi de débogage inutile. RoCE ne possède pas de SM : le routage est assuré par l'infrastructure Ethernet, c'est pourquoi la configuration de RoCE concerne principalement la QoS du commutateur, et non celle de l'hôte.

Prouver que RDMA fonctionne réellement : perftest

Avant toute exécution NCCL ou de framework, vérifiez le câblage avec perftestDeux nœuds, le serveur en premier :

# server (node A)        # client (node B)
ib_send_bw -d mlx5_0 -F --report_gbits -D 10
ib_send_bw -d mlx5_0 -F --report_gbits -D 10 10.10.1.1

Nombre attendu sur un tissu propre :

Lien ib_send_bw (message volumineux) ib_send_lat (2 octets)
100 Gb/s EDR / 100 GbE RoCE 95–98 Gb/s 1.0 à 1.5 µs
200 Gb/s HDR / 200 GbE RoCE 188–197 Gb/s 0.9 à 1.3 µs
NDR de 400 Gb/s 370–395 Gb/s 0.8 à 1.1 µs

Si vos performances sont inférieures de 20 % à ces valeurs, ne cherchez pas à optimiser le NCCL. Le problème vient de la configuration réseau. Vérifiez dans l'ordre : (1) la MTU, (2) le PFC sur RoCE, (3) la paire câble/émetteur-récepteur, (4) le nombre de générations et de voies PCIe de la carte réseau, (5) l'emplacement NUMA. Une latence inférieure à la microseconde est possible pour un NDR en rack ; toute latence supérieure à 5 µs sur une infrastructure RoCE à un seul commutateur indique un dysfonctionnement.

GPUDirect RDMA : activation du chemin DMA

L'intérêt principal du RDMA dans un cluster d'IA réside dans la lecture et l'écriture directes de la mémoire GPU par la carte réseau, sans passer par l'hôte. Cela nécessite nvidia-peermem (ou, sur les noyaux plus récents, DMA-BUF — NVIDIA recommande désormais DMA-BUF lorsque le noyau le prend en charge, mais la plupart des piles de production sont toujours livrées avec peermem).

sudo modprobe nvidia-peermem
lsmod | grep nvidia_peermem
echo nvidia-peermem | sudo tee /etc/modules-load.d/nvidia-peermem.conf

Si le chargement échoue, le noyau n'a pas été compilé avec une API mémoire homologue RDMA compatible OFED. L'ordre d'installation est important : OFED en premier, puis le pilote NVIDIA, puis… nvidia-peermem — peermem est construit en fonction des en-têtes OFED au moment de l'installation.

Démontrer le chemin de bout en bout avec une écriture RDMA GPU-à-GPU :

# server                                # client
ib_write_bw -d mlx5_0 --use_cuda=0 -F --report_gbits -D 10
ib_write_bw -d mlx5_0 --use_cuda=0 -F --report_gbits -D 10 10.10.1.1

--use_cuda=0 GPUDirect enregistre la mémoire CUDA du GPU 0 comme tampon RDMA. Si le résultat est comparable à celui obtenu avec la mémoire hôte (à quelques pourcents près), GPUDirect fonctionne correctement. En revanche, s'il est cinq fois plus lent, le traitement passe par la mémoire hôte ; il s'agit généralement d'un problème de charge peermem ou d'une topologie PCIe où la carte réseau et le GPU se trouvent sur des nœuds NUMA opposés.

MTU et PFC pour RoCE (c'est là que les clusters RoCE vivent ou meurent)

RoCEv2 sur un réseau Ethernet sans perte nécessite le fonctionnement simultané de trois éléments :

  1. Une grande MTU de bout en bout. Configurez la valeur 9000 sur chaque carte réseau, port de commutateur et routeur. RoCE sélectionne la plus grande MTU de type IB compatible avec la MTU Ethernet ; la valeur 9000 pour Ethernet correspond à une MTU de 4096 octets, ce qui est idéal.
  2. PFC sur la priorité RDMA. Pause au niveau de la couche liaison pour éviter les pertes de paquets sur une classe de trafic désignée. Pratique courante : RDMA en priorité 3, tout le reste en priorité 0.
  3. Marquage ECN sur les commutateurs et les cartes réseau. L'ECN est le signal de congestion à long terme ; le PFC est le frein d'urgence à court terme. L'ECN est généralement actif ; le PFC se déclenche uniquement lorsque l'ECN est débordé.

Du côté hôte, avec mlnx_qos:

sudo mlnx_qos -i enp1s0f0 --pfc 0,0,0,1,0,0,0,0   # PFC on prio 3
sudo mlnx_qos -i enp1s0f0 --trust dscp
echo 106 | sudo tee /sys/class/infiniband/mlx5_0/tc/1/traffic_class

La valeur DSCP (26) et la priorité PFC (3) doivent correspondre à chaque saut. L'architecture du commutateur doit refléter cette configuration : PFC activé en priorité 3, marquage ECN sur les files d'attente concernées, configuration de tampon sans perte et marge de sécurité par port dimensionnée pour le BDP de la liaison la plus longue.

L'achat d'un commutateur auprès d'un fournisseur proposant des modèles RoCE documentés (NVIDIA Spectrum, Arista, Cisco Nexus 9000) permet de gagner une semaine. Configurer manuellement le PFC sur un commutateur Broadcom générique est possible, mais fastidieux. Nous l'avons fait, mais nous le déconseillons.

DCQCN (Notification de congestion quantifiée du centre de données) est la boucle de contrôle qui relie PFC et ECN : ECN marque les paquets lorsqu'une file d'attente est pleine, le récepteur renvoie une notification de congestion, l'émetteur ralentit son débit, puis l'accélère lorsque la file d'attente est vide. PFC intervient lorsque DCQCN ne peut pas réagir assez rapidement. Sur les firmwares ConnectX-6/7 modernes, il est activé par défaut, et les paramètres par défaut conviennent pour 4 à 16 nœuds. Le réglage fin (alpha, débit cible, seuils d'octets/de temporisateur) est réservé aux utilisateurs exploitant des infrastructures à grande échelle où une réduction de 0.5 % du débit global représente deux semaines de travail.

NCCL : les variables qui comptent

NCCL est la couche qui utilise RDMA pour PyTorch, JAX, DeepSpeed, vLLM tensor-parallel et autres. Elle effectue une détection automatique, généralement correcte. Quatre variables d'environnement apparaissent dans chaque script de lancement en production :

Variable Ce qu'il fait Quand le régler
NCCL_IB_DISABLE 1 impose l'utilisation de sockets TCP au lieu d'IB/RoCE Débogage uniquement
NCCL_SOCKET_IFNAME Interface pour le bootstrap NCCL (et non le chemin de données) Toujours — pointer vers la carte réseau de gestion afin que le processus d'amorçage ne se précipite pas sur le réseau RDMA
NCCL_IB_HCA Quel(s) HCA NCCL utilise-t-il pour le plan de données ? Nœuds multi-NIC — battements explicites automatiques
NCCL_NET_GDR_LEVEL Comment utiliser GPUDirect RDMA de manière agressive en fonction de la topologie PCIe ? PIX/PHB lorsque les GPU et les NIC partagent un commutateur PCIe / nœud NUMA

Lancement fonctionnel sur un cluster de 4 nœuds, 4 GPU par nœud :

export NCCL_SOCKET_IFNAME=eno1            # 1 GbE management network
export NCCL_IB_HCA=mlx5_0,mlx5_1          # both RDMA NICs
export NCCL_IB_GID_INDEX=3                # RoCE v2 GID
export NCCL_NET_GDR_LEVEL=PHB
export NCCL_DEBUG=INFO                    # one-shot, then drop to WARN

mpirun -np 16 -N 4 --hostfile hosts -x NCCL_SOCKET_IFNAME \
    -x NCCL_IB_HCA -x NCCL_IB_GID_INDEX -x NCCL_NET_GDR_LEVEL \
    -x NCCL_DEBUG ./build/all_reduce_perf -b 8 -e 8G -f 2 -g 1

Le NCCL_DEBUG=INFO La sortie est une lecture obligatoire lors de la première exécution. Elle vous indique quel transport NCCL a sélectionné (Channel ... via NET/IB/0 GDR) par rang, par canal. Voir via NET/Socket N'importe où et le chemin RDMA n'est pas utilisé — vous n'avez pas testé ce que vous pensez avoir testé.

Valider avec nccl-tests

nccl-tests valide l'ensemble de la pile (pilote, OFED, mémoire pair à pair, NCCL, réseau) de bout en bout. Le chiffre qui compte est bande passante du bus (busbw), et non la bande passante de l'algorithme (algbwLa bande passante du bus est normalisée en fonction de la taille de l'anneau/de l'arbre et c'est ce que vous comparez à la vitesse du réseau filaire de la carte réseau.

Taille de cluster Réduction attendue du busbw (message volumineux)
1 nœud, 4 GPU via NVLink 200–400 Go/s
1 nœud, 8 GPU via NVLink 250–500 Go/s
2 nœuds, 4 GPU chacun, RDMA 200 GbE 20–24 Go/s
4 nœuds, 4 GPU chacun, RDMA 200 GbE + GDR 20–22 Go/s

Le débit AllReduce inter-nœuds est limité à environ la moitié du débit de la ligne NIC (AllReduce envoie et reçoit chaque octet une fois par rang). Un débit maximal de 200 Gb/s est d'environ 25 Go/s ; un débit observé de 22 Go/s est normal. Si le débit est divisé par 5 lors du passage de 1 à 2 nœuds, cela signifie que le protocole RDMA n'est pas utilisé pour le saut inter-nœuds. Consultez la documentation. NCCL_DEBUG=INFO sortie.

Dézoomons maintenant : conception de la liaison montante du cluster

Tout ce qui précède concerne le plan de données — les GPU du réseau qui communiquent entre eux. L'autre moitié d'un cluster fonctionnel est constituée par… liaison montante: comment ce réseau se connecte au monde extérieur. On conçoit constamment de mauvaises liaisons montantes.

Un cluster d'entraînement K-AI à 4 nœuds possède trois relations externes :

  1. Réseau d'entreprise / WAN — registres de modèles, stockage de jeux de données (S3, NFS, MinIO), Git, registres de conteneurs, télémétrie.
  2. Postes de travail de développement — des ingénieurs se connectent en SSH, lancent des tâches, copient des points de contrôle, exécutent Jupyter.
  3. Autres groupes — un deuxième groupe d'entraînement, un groupe d'inférence, un groupe CI/évaluation.

Calculs de bande passante

Si 4 nœuds effectuent tous une réduction d'environ 22 Go/s chacun, le interne Le réseau transporte environ 700 Gb/s de données agrégées d'est en ouest. liaison montante n'a pas besoin de correspondre à cela. Il doit correspondre au taux d'ingestion de données:

  • 4 nœuds × 4 GPU × ~1 Go/s par GPU (modèle image/vidéo) = 16 Go/s ≈ 128 Go/s Lecture soutenue à partir du stockage d'objets.
  • Le pré-entraînement LLM sur du texte tokenisé est beaucoup plus petit — 1 à 4 Gb/s, car les tokens sont denses et un lot dure longtemps.
  • Un réglage fin des points de contrôle de rechargement atteint fréquemment un pic de 40 Gb/s pendant quelques secondes, puis chute à presque zéro.
Charge de travail Ingestion prolongée Burst Uplink
Pré-entraînement LLM (texte tokenisé) 1–4 Gb/s 20 Gb / s 25 GbE
Formation sur des modèles d'images/vidéos 50–150 Gb/s 200 Gb / s 2 × 100 GbE LAG ou 1 × 200 GbE
Réglage fin / RLHF avec changement aléatoire des points de contrôle 5–20 Gb/s 50 Gb / s 25–100 GbE
Cluster d'inférence derrière un équilibreur de charge 5–50 Gb/s dépendant du modèle 25–100 GbE

Erreur fréquente : dépenser 40 000 € pour une liaison montante de 400 GbE sous prétexte que l’infrastructure interne est de 400 GbE. Mauvaise cible. La cible pertinente est le débit de lecture des données. Nous avons construit des clusters à 4 nœuds avec une liaison montante de 25 GbE qui ont fonctionné à plein régime pendant des semaines avec des données LLM token.

Bande passante agrégée vs allouée

Un nœud doté de quatre cartes réseau 100 GbE possède agrégat de 400 Gb/s Capacité du réseau. Cette capacité est allouée par flux et non mutualisée. Une connexion TCP unique entre deux adresses IP utilise une seule carte réseau (100 Gbit/s maximum). ECMP et le hachage par flux répartissent cette capacité. différent flux à travers les quatre NIC.

  • Allreduce Il s'agit de nombreux flux en parallèle — un par canal et par pair. NCCL se répartit nativement sur plusieurs NIC (NCCL_IB_HCA (en listant les deux). 4× 100 GbE est fonctionnellement proche de 400 Gb/s pour NCCL.
  • Un flux de données unique (Une requête HTTP GET récupérant un fragment de 1 To) constitue un flux. Quatre liaisons 100 GbE offrent un débit de 100 Gb/s, et non de 400. Pour utiliser l'agrégat, le chargeur de données doit ouvrir des flux parallèles ; DALI, WebDataset et Streaming de MosaicML le font par conception.

Séparation du tissu

Plan de données
  • 100/200/400 GbE RoCE ou HDR/NDR InfiniBand
  • NCCL, lectures de jeux de données, écritures de points de contrôle
  • Sans perte, PFC/ECN, commutateurs dédiés
  • Stérile — aucun trafic non lié à l'IA
Plan de gestion
  • 1 GbE ou 10 GbE
  • SSH, Prometheus, NTP, syslog, IPMI/BMC
  • Commutateurs bon marché, L2/L3 standard, sans QoS spécifique
  • Fonctionne toujours, même si l'infrastructure de données est hors service.

Utilisez toujours deux réseaux de données. Le plan de gestion ne doit pas dépendre du plan de données pour fonctionner ; un accès SSH est nécessaire même en cas de panne du réseau RDMA.

Le plan de gestion est indispensable. En cas de défaillance du réseau de données (émetteur-récepteur défectueux, mauvaise configuration PFC, panne de commutateur), un chemin SSH indépendant du réseau défaillant est nécessaire. Tenter de déboguer une tempête RoCE sur la liaison affectée est une erreur à ne commettre qu'une seule fois. IPMI/BMC et NTP y sont également présents ; les décalages d'horloge restent invisibles tant que votre infrastructure distribuée ne génère pas de gradients erronés.

BGP non numéroté pour les Clos routés

Au-delà de 8 nœuds environ, l'architecture feuille-épine de couche 2 devient problématique : limitations de l'arbre de recouvrement, mise à l'échelle des tables MAC, tempêtes de diffusion, absence de routage multi-chemin natif. La solution moderne est un réseau Clos routé en couche 3 : chaque liaison feuille-épine est non numérotée, BGP transporte les routes et ECMP répartit les flux entre les épines.

Les pairs BGP non numérotés utilisent des adresses IPv6 locales attribuées automatiquement par le noyau, ce qui évite toute gestion des /31 par lien. Un nœud feuille exécutant FRRouting sous Linux ressemble approximativement à ceci :

router bgp 65001
 neighbor swp1 interface remote-as external
 neighbor swp2 interface remote-as external
 address-family ipv4 unicast
  network 10.1.1.0/24
  redistribute connected

Chaque feuille et chaque colonne vertébrale constitue son propre système autonome (AS). eBGP annonce les adresses de bouclage, et le protocole ECMP entre les colonnes vertébrales est gratuit. La RFC 7938 décrit ce modèle ; Cumulus/NVIDIA, Arista, Cisco et Juniper prennent tous en charge le BGP non numéroté. Avec 4 nœuds, un seul commutateur suffit. À partir de 8 à 16 nœuds avec deux colonnes vertébrales, le routage Clos devient rentable. Au-delà de 16 nœuds, c'est la seule solution pertinente.

Connexion à d'autres clusters

Ne placez pas un cluster d'entraînement et un cluster d'inférence sur la même infrastructure RDMA. L'entraînement génère des pics importants de requêtes allreduce ; l'inférence, quant à elle, traite des messages courts et réguliers ; les exigences de QoS divergent ; un dysfonctionnement lors de l'entraînement saturera le chemin d'inférence. La solution optimale consiste à utiliser deux infrastructures distinctes se rejoignant au niveau d'un routeur de couche 3 avec un routage IP standard. Le trafic de contrôle inter-clusters (files d'attente de tâches, transfert de journaux, transfert d'artefacts) emprunte le plan de gestion ou une liaison Ethernet inter-clusters dédiée. Un fichier de poids de 70 octets pèse environ 140 Go ; un point de contrôle pèse le double. À 25 GbE, cela prend environ 90 secondes ; à 100 GbE, environ 22 secondes. Prévoyez une marge de sécurité.

Que faire ensuite

Un flux de travail raisonnable pour la mise en place de RDMA sur un nouveau cluster :

  1. Câblez-le et vérifiez d'abord la couche de liaison. Courir ibstat Sur chaque nœud. Même débit, même MTU, même couche liaison. Corrigez la couche physique avant de toucher au logiciel.
  2. Installez MLNX_OFED, et pas seulement rdma-core, Si GPUDirect ou NCCL est concerné, faites correspondre la version OFED au noyau en cours d'exécution.
  3. Courir perftest entre chaque paire de nœuds Avant de toucher aux structures. Les chiffres à moins de 5 % des valeurs théoriques sont considérés comme satisfaisants. En dessous, il faut arrêter et corriger.
  4. Charge nvidia-peermem, prouvez-le avec ib_write_bw --use_cuda=0. Le résultat doit correspondre au cas de la mémoire hôte.
  5. Configurer PFC, ECN et DCQCN Si vous êtes sur RoCE. Sur IB, cette étape n'existe pas ; c'est d'ailleurs une des principales raisons pour lesquelles on choisit IB.
  6. Courir nccl-tests allreduce sur 2 nœuds, puis 4, puis 8. Inspectez le NCCL_DEBUG=INFO Résultat de la première exécution pour chaque taille de cluster. Confirmer NET/IB ... GDR révéler.
  7. Tissus séparés. Gestion via une connexion 1/10 GbE économique. Données sur le réseau RDMA. Ne pas partager.
  8. Dimensionnez la liaison montante en fonction du débit d'ingestion de votre ensemble de données, et non à la vitesse du réseau interne. La plupart des clusters nécessitent une bande passante externe bien inférieure à celle dont ils disposent.
  9. Au-delà de 8 nœuds, planifiez un routage Clos avec BGP non numéroté. En dessous de 8 ans, un seul interrupteur suffit.

Les articles suivants dans la section N traitent de l'analyse de la latence (N06) et la complexité du routage (N07C’est là que résident les problèmes de réglage de DCQCN et de hachage ECMP. La branche K prend le relais avec l’entraînement distribué (K02), les clusters d’inférence (K03) et le stockage (K04), en supposant que la pile RDMA décrite sur cette page soit déjà fonctionnelle.


Ceci fait partie du Kentino Wiki, une série de référence sur le calcul en intelligence artificielle et les systèmes qui le connectent. Les corrections sont les bienvenues. info@kentino.com.