Ce document décrit les modèles de configuration et les bonnes pratiques à suivre pour utiliser les deux cartes d'interface réseau (NIC) de l'hôte pour le stockage et la gestion sur les instances Compute Engine.
Présentation
Certaines séries de machines optimisées pour les accélérateurs, y compris A5X, A4X Max, A4X, A4 et A3 Ultra, disposent de deux interfaces réseau LAN hôtes pour le stockage et la gestion qui s'associent aux réseaux cloud privé virtuel (VPC) standards. Ces machines disposent également d'interfaces réseau MRDMA qui doivent être associées à un réseau VPC RoCE (accès direct à la mémoire à distance sur Ethernet convergé).
Ce document se concentre sur la configuration des interfaces LAN hôtes (gVNIC ou IDPF) sur les réseaux VPC standards, et non sur les interfaces réseau RDMA.
Les interfaces LAN de l'hôte sont des unités de traitement d'infrastructure (IPU) Titanium qui se connectent à des sockets de processeur et à des nœuds NUMA (Non-Uniform Memory Access) distincts. Dans l'instance de calcul, ces IPU apparaissent sous la forme d'interfaces réseau Google Virtual NIC (gVNIC) ou Infrastructure Data Path Function (IDPF).
Ces interfaces fournissent une bande passante réseau pour les activités de stockage et de gestion, telles que la création de points de contrôle, le chargement des données d'entraînement et le chargement des modèles.
La topologie NUMA de la machine, y compris la topologie des interfaces réseau, est visible par le système d'exploitation (OS) invité.
Utilisez les configurations suivantes, quel que soit le modèle que vous choisissez pour plusieurs cartes d'interface réseau hôtes :
- Paramètres réseau : configurez chaque interface gVNIC ou IDPF pour utiliser un réseau VPC distinct.
Pour votre configuration de VPC, effectuez les configurations suivantes :
- Configurez une unité de transmission maximale (MTU) élevée pour chaque réseau VPC, par exemple
8896(la MTU maximale acceptée). - Si les paquets de données entrants perdus côté récepteur ralentissent les performances d'entrée de votre charge de travail, recherchez les paquets perdus à l'aide de l'utilitaire
ethtool. Pour optimiser l'allocation des données à partir du cache de pages afin que chaque trame de couche 2 entrante tienne dans deux tampons de 4 Ko, ajustez la taille maximale de segment (MSS) TCP, la MTU de l'interface ou la MTU du VPC.
- Configurez une unité de transmission maximale (MTU) élevée pour chaque réseau VPC, par exemple
- Paramètres de l'application :
- Alignez votre application sur NUMA en utilisant des cœurs de processeur, des allocations de mémoire et une interface réseau du même nœud NUMA. Si vous exécutez une instance dédiée de l'application pour un nœud NUMA ou une interface réseau spécifique, liez les ressources de processeur et de mémoire de l'application à ce nœud NUMA à l'aide d'un outil tel que
numactl.
- Alignez votre application sur NUMA en utilisant des cœurs de processeur, des allocations de mémoire et une interface réseau du même nœud NUMA. Si vous exécutez une instance dédiée de l'application pour un nœud NUMA ou une interface réseau spécifique, liez les ressources de processeur et de mémoire de l'application à ce nœud NUMA à l'aide d'un outil tel que
- Paramètres du système d'exploitation :
- Activez le déchargement de la segmentation TCP (TSO) et le déchargement de réception volumineux (LRO).
- Pour chaque interface gVNIC ou IDPF, configurez l'affinité de multitraitement symétrique (SMP) pour acheminer les requêtes d'interruption (IRQ) vers le même nœud NUMA que l'interface et répartir les interruptions entre les cœurs de processeur. Si vous utilisez une image Linux fournie par Google, l'agent invité Compute Engine exécute le script
google_set_multiqueueau démarrage pour appliquer automatiquement cette configuration. Si vous utilisez une image personnalisée, installez l'environnement invité. Si le script ne s'exécute pas automatiquement, exécutez la commandesudo /usr/bin/google_set_multiqueue. - Évaluez les paramètres Receive Flow Steering (RFS), Receive Packet Steering (RPS) et Transmit Packet Steering (XPS) pour déterminer s'ils sont bénéfiques pour votre charge de travail.
- Pour les instances A4X Max et A4X, NVIDIA vous recommande de désactiver la planification NUMA automatique.
- N'utilisez pas l'agrégation de liens du noyau Linux avec les interfaces gVNIC ou IDPF sur ces machines, car l'agrégation de liens du noyau n'est pas compatible.
Modèles d'utilisation de plusieurs cartes d'interface réseau hôtes
Le tableau suivant décrit les modèles généraux d'utilisation de plusieurs cartes d'interface réseau hôtes surGoogle Cloud :
| Modèle | Mise en page de processus compatible | Chemin de déploiement : Compute Engine | Chemin de déploiement : Google Kubernetes Engine | Chemin de déploiement : Slurm | Remarques |
|---|---|---|---|---|---|
| Modifier une application pour utiliser une interface spécifique | Segment de processus par interface | Oui | Oui | Oui | Des modifications de code sont requises dans l'application. |
| Modifier une application pour utiliser les deux interfaces | Processus à double interface | Oui | Oui | Oui | Des modifications de code sont requises dans l'application. |
| Utiliser un espace de noms réseau dédié pour des applications spécifiques | Segment de processus par interface | Oui | Oui (conteneurs privilégiés uniquement) | Non | Aucun |
| Mapper le trafic d'un conteneur entier vers une seule interface | Tout le trafic des conteneurs est mappé à une seule interface | Oui | Oui | Non | Aucun |
| Utiliser l'appairage de VPC et laisser le système équilibrer la charge des sessions entre les interfaces | Processus à double interface | Oui | Oui | Oui | Difficile ou impossible à aligner sur NUMA. Nécessite le noyau Linux 6.16 ou une version ultérieure. |
| Segmenter le trafic sur plusieurs réseaux |
|
Oui | Oui | Oui | Peut nécessiter des modifications de code pour l'alignement NUMA si vous exécutez un processus à double interface. |
| Utiliser la traduction d'adresse réseau source (SNAT) pour choisir l'interface source |
|
Oui | Oui (la configuration nécessite des droits d'administrateur) | Oui (la configuration nécessite des droits d'administrateur) | Peut être difficile à configurer. |
Remarques
- Pour les modèles Utiliser l'appairage de VPC et laisser le système équilibrer la charge des sessions entre les interfaces et Segmenter le trafic entre les réseaux : ces options ne sont généralement pas recommandées, mais elles peuvent être utiles pour des charges de travail limitées sur les plates-formes x86 (A4 et A3 Ultra).
Modifier une application pour qu'elle utilise une interface spécifique
Exigences :
- Nécessite des modifications du code de votre application.
- Nécessite des autorisations pour une ou plusieurs des méthodes suivantes :
bind(): nécessite des autorisations spéciales uniquement si vous utilisez un port source privilégié.SO_BINDTODEVICE: nécessite l'autorisationCAP_NET_RAW.
- Vous devrez peut-être modifier votre table de routage du noyau pour établir des routes et empêcher le routage asymétrique.
Vue d'ensemble
Pour configurer votre application afin qu'elle utilise une interface réseau spécifique, procédez comme suit :
- Ajoutez une liaison pour une interface réseau au code source de votre application à l'aide de l'une des options suivantes :
- Utilisez l'appel système
bind()pour lier un socket à une adresse IP source spécifique. - Utilisez l'option de socket
SO_BINDTODEVICEpour lier un socket à une interface réseau spécifique.
- Utilisez l'appel système
- Modifiez la table de routage du noyau si nécessaire pour vous assurer qu'il existe une route entre l'interface réseau source et l'adresse de destination. Pour éviter le routage asymétrique, configurez le routage des règles comme décrit dans Configurer le routage pour une interface réseau supplémentaire.
- Facultatif : Exécutez votre application sur la mémoire et les processeurs qui partagent le même nœud NUMA que l'interface réseau que vous avez choisie à l'aide de la commande
numactl.
Une fois ces étapes terminées, votre application utilise l'interface réseau spécifiée.
Modifier une application pour utiliser les deux interfaces
Exigences :
- Nécessite des modifications du code de votre application.
- Nécessite des autorisations pour une ou plusieurs des méthodes suivantes :
bind(): nécessite des autorisations spéciales uniquement si vous utilisez un port source privilégié.SO_BINDTODEVICE: nécessite l'autorisationCAP_NET_RAW.
- Vous devrez peut-être modifier votre table de routage du noyau pour établir des routes et empêcher le routage asymétrique.
Vue d'ensemble
Pour configurer votre application afin qu'elle utilise les deux interfaces réseau, procédez comme suit :
- Ajoutez une liaison pour chaque interface réseau au code source de votre application à l'aide de l'une des options suivantes :
- Utilisez l'appel système
bind()pour lier chaque socket à l'adresse IP source de l'interface réseau correspondante. - Utilisez l'option de socket
SO_BINDTODEVICEpour lier chaque socket à une interface réseau spécifique.
- Utilisez l'appel système
- Si votre application agit en tant que client, créez un socket client distinct pour chaque interface réseau source.
- Modifiez la table de routage du noyau si nécessaire pour vous assurer qu'il existe une route entre chaque interface réseau source et l'adresse de destination. Pour éviter le routage asymétrique, configurez le routage des règles comme décrit dans Configurer le routage pour une interface réseau supplémentaire.
- Partitionnez l'activité réseau en threads qui s'exécutent sur le même nœud NUMA que l'interface gVNIC ou IDPF correspondante, par exemple en appelant
pthread_setaffinity_np. Étant donné que l'application utilise des ressources sur plusieurs nœuds NUMA, évitez d'utilisernumactlou assurez-vous que votre commandenumactlinclut les nœuds NUMA de toutes les interfaces réseau utilisées par votre application.
Utiliser un espace de noms réseau dédié pour des applications spécifiques
Exigences :
- Nécessite la fonctionnalité
CAP_SYS_ADMIN. - N'est pas compatible avec GKE Autopilot.
- Si vous utilisez GKE, vous devez utiliser un conteneur privilégié.
Cette section décrit les modèles que vous pouvez utiliser pour créer un espace de noms réseau pour une interface réseau secondaire. Le meilleur modèle pour votre charge de travail dépend de votre scénario. Les approches qui utilisent un commutateur virtuel ou IPvlan fonctionnent mieux lorsque plusieurs applications doivent partager l'interface secondaire à partir de différents espaces de noms réseau.
Déplacer l'interface secondaire vers un espace de noms réseau dédié
Avec ce modèle, vous créez un espace de noms réseau, vous déplacez l'interface gVNIC ou IDPF secondaire vers le nouvel espace de noms, puis vous exécutez l'application à partir de cet espace de noms. Ce modèle est plus simple à configurer et à régler qu'un commutateur virtuel, mais les applications situées en dehors du nouvel espace de noms réseau ne peuvent pas accéder à l'interface réseau secondaire.
Pour déplacer l'interface eth1 dans un espace de noms réseau nommé app-net et exécuter une commande dans cet espace de noms, exécutez les commandes suivantes :
ip netns add app-net ip link set eth1 netns app-net ip netns exec app-net ip addr add ETH1_IP/PREFIX dev eth1 ip netns exec app-net ip link set dev eth1 up ip netns exec app-net ip route add default via GATEWAY_IP dev eth1 ip netns exec app-net COMMAND
Remplacez les éléments suivants :
ETH1_IP: adresse IP interne de l'interfaceeth1.PREFIX: longueur du préfixe de sous-réseau pour l'interfaceeth1.GATEWAY_IP: adresse IP de la passerelle par défaut pour le sous-réseaueth1.COMMAND: commande à exécuter dans l'espace de noms réseauapp-net.
Lorsque vous exécutez ces commandes, COMMAND s'exécute dans l'espace de noms réseau app-net et utilise l'interface eth1.
Les applications exécutées dans le nouvel espace de noms réseau utilisent l'interface gVNIC ou IDPF secondaire. Vous pouvez également utiliser la commande numactl pour exécuter votre application en utilisant la mémoire et les processeurs sur le même nœud NUMA que l'interface réseau choisie.
Utiliser un commutateur virtuel et un espace de noms réseau pour une interface secondaire
Avec ce modèle, vous configurez un commutateur virtuel pour accéder à l'interface gVNIC ou IDPF secondaire à partir d'un espace de noms réseau :
- Ouvrez une connexion SSH à l'instance de calcul. Pour en savoir plus, consultez Se connecter à des VM Linux.
- Créez une paire d'appareils Virtual Ethernet (
veth) à l'aide de la commandeip link add, par exempleip link add veth0 type veth peer name veth1. Ajustez la MTU sur chaque appareil pour qu'elle corresponde à la MTU de l'interface secondaire à l'aide de la commande
ip link set:ip link set dev veth0 mtu MTU ip link set dev veth1 mtu MTU
Remplacez
MTUpar la MTU de l'interface secondaire (par exemple,8896).Activez le transfert de paquets IPv4 :
sysctl -w net.ipv4.ip_forward=1
Déplacez une extrémité de la paire
vethvers un nouvel espace de noms réseau et laissez l'autre extrémité dans l'espace de noms racine.Mappez le trafic de l'appareil
vethvers l'interface secondaire. Pour configurer ce mappage, créez une plage d'adresses IP d'alias pour l'interface secondaire de l'instance de calcul et attribuez une adresse IP de cette plage à l'interface enfant dans l'espace de noms.Exécutez l'application à partir du nouvel espace de noms réseau. Vous pouvez utiliser la commande
numactlpour exécuter votre application en utilisant la mémoire et les processeurs sur le même nœud NUMA que l'interface réseau choisie.
Selon votre OS invité et la configuration de votre charge de travail, vous pouvez également associer une interface IPvlan à l'interface gVNIC ou IDPF secondaire au lieu de créer des appareils veth.
Mapper le trafic d'un conteneur entier vers une seule interface
Exigences :
- Votre application doit s'exécuter dans un conteneur qui utilise un espace de noms réseau pour la mise en réseau des conteneurs, comme GKE, Docker ou Podman. Vous ne pouvez pas utiliser le réseau hôte.
Les environnements d'exécution de conteneurs tels que GKE, Docker et Podman utilisent un espace de noms réseau dédié pour chaque conteneur afin d'isoler son trafic. Vous pouvez modifier cet espace de noms réseau, soit directement, soit à l'aide des outils de l'environnement d'exécution du conteneur, pour mapper le trafic vers une autre interface réseau.
GKE nécessite l'interface principale pour la communication Kubernetes interne. Toutefois, vous pouvez modifier la route par défaut dans le pod pour utiliser l'interface secondaire, comme indiqué dans le fichier manifeste de pod GKE suivant :
metadata:
# ...
annotations:
networking.gke.io/default-interface: 'eth1'
networking.gke.io/interfaces: |
[
{"interfaceName":"eth0","network":"default"},
{"interfaceName":"eth1","network":"secondary-network"}
]
Cette approche ne garantit pas l'alignement NUMA entre l'interface réseau par défaut et les processeurs ou la mémoire attribués.
Utiliser l'appairage de VPC et laisser le système équilibrer la charge des sessions entre les interfaces
Exigences :
- Vous devez établir un appairage de réseaux VPC entre les réseaux VPC des cartes d'interface réseau hôtes principale et secondaire.
- Vous devez utiliser la version 6.16 ou ultérieure du noyau Linux pour équilibrer la charge des sessions TCP sur les interfaces sources lors de l'envoi de trafic vers une adresse IP et un port de destination uniques.
- Votre charge de travail doit tolérer les transferts de mémoire entre sockets sans manquer ses objectifs de performances.
Vue d'ensemble
Si vous ne pouvez pas facilement segmenter les connexions réseau au sein d'une application ou entre des instances d'application, et que votre charge de travail s'exécute sur des instances de calcul A4 ou A3 Ultra qui ne sont pas sensibles aux transferts entre NUMA ou entre sockets, vous pouvez traiter les deux interfaces comme fongibles.
Pour configurer ce comportement, activez le paramètre sysctl fib_multipath_hash_policy et ajoutez une route multichemin :
PRIMARY_GW=192.168.1.1 # Gateway of nic0
SECONDARY_GW=192.168.2.1 # Gateway of nic1
PRIMARY_IP=192.168.1.15 # Internal IP address for nic0
SECONDARY_IP=192.168.2.27 # Internal IP address for nic1
# Enable L4 5-tuple equal-cost multipath (ECMP) hashing
sysctl -w net.ipv4.fib_multipath_hash_policy=1
ip route add DESTINATION_NETWORK/SUBNET_MASK \
nexthop via ${PRIMARY_GW} \
nexthop via ${SECONDARY_GW}
Remplacez les éléments suivants :
DESTINATION_NETWORK: plage d'adresses IP internes de destination.SUBNET_MASK: longueur du préfixe de sous-réseau pour le réseau de destination.
Segmenter le trafic sur plusieurs réseaux
Exigences :
nic0etnic1sur l'instance de calcul doivent se connecter à des réseaux et sous-réseaux VPC distincts, et les adresses IP de destination doivent être segmentées sur les deux réseaux VPC.
Vue d'ensemble
Par défaut, le noyau Linux crée des routes pour les sous-réseaux nic0 et nic1 qui acheminent le trafic par adresse IP de destination via l'interface réseau correspondante.
Par exemple, supposons que nic0 utilise le réseau VPC net1 avec le sous-réseau subnet-a, et que nic1 utilise le réseau VPC net2 avec le sous-réseau subnet-b. Par défaut, le trafic vers les adresses IP de pairs dans subnet-a utilise nic0, et le trafic vers les adresses IP de pairs dans subnet-b utilise nic1. Cette configuration s'applique généralement lorsqu'un ensemble d'instances de calcul pairs à carte d'interface réseau unique se connecte à net1 et qu'un deuxième ensemble se connecte à net2.
Utiliser la SNAT pour choisir l'interface source
Exigences :
- Nécessite la fonctionnalité
CAP_NET_ADMINpour configurer les règlesiptablesinitiales, mais pas pour exécuter l'application. - Nécessite une évaluation minutieuse lorsqu'elle est combinée à d'autres règles
iptablesou configurations de routage non triviales.
Vue d'ensemble
Si vous ne pouvez pas utiliser d'espaces de noms réseau ni modifier votre application, vous pouvez utiliser SNAT pour sélectionner une interface source. En utilisant un outil tel que iptables, vous pouvez réécrire l'adresse IP source d'un flux pour qu'elle corresponde à l'adresse IP d'une interface spécifique en fonction d'une propriété de l'application émettrice, telle que son cgroup, son utilisateur ou son processeur.
L'exemple suivant utilise des règles basées sur le processeur afin que tout flux provenant d'un thread sur un processeur donné sorte par l'interface gVNIC ou IDPF associée au nœud NUMA de ce processeur :
# --- Begin Configuration ---
OUTPUT_INTERFACE_0="enp0s19" # CHANGEME: NIC0
OUTPUT_INTERFACE_1="enp192s20" # CHANGEME: NIC1
CPUS_0=($(seq 0 55; seq 112 167)) # CHANGEME: CPU IDs for NIC0
GATEWAY_0="10.0.0.1" # CHANGEME: Gateway for NIC0
SNAT_IP_0="10.0.0.2" # CHANGEME: SNAT IP for NIC0
CONNMARK_0="0x1"
RT_TABLE_0="100"
CPUS_1=($(seq 56 111; seq 168 223)) # CHANGEME: CPU IDs for NIC1
GATEWAY_1="10.0.1.1" # CHANGEME: Gateway for NIC1
SNAT_IP_1="10.0.1.2" # CHANGEME: SNAT IP for NIC1
CONNMARK_1="0x2"
RT_TABLE_1="101"
# --- End Configuration ---
# Specify which interface to use for packets in each routing table.
ip route add default via "$GATEWAY_0" dev "$OUTPUT_INTERFACE_0" table "$RT_TABLE_0"
ip route add default via "$GATEWAY_1" dev "$OUTPUT_INTERFACE_1" table "$RT_TABLE_1"
# Route replies to connections from peers through the matching egress interface.
# Add these rules before the fwmark rules so that fwmark takes precedence.
ip rule add from "$SNAT_IP_0" table "$RT_TABLE_0"
ip rule add from "$SNAT_IP_1" table "$RT_TABLE_1"
# Select the routing table based on the packet mark set in OUTPUT.
ip rule add fwmark "$CONNMARK_0" table "$RT_TABLE_0"
ip rule add fwmark "$CONNMARK_1" table "$RT_TABLE_1"
# Relax reverse path filtering so that the kernel doesn't drop legitimate
# replies to the SNAT IP addresses.
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_0".rp_filter=2
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_1".rp_filter=2
# Mark packets and connections with a per-NIC mark based on the source CPU.
# The fwmark rules then select the corresponding routing table for this traffic.
for cpu_id in "${CPUS_0[@]}"; do
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j CONNMARK --set-mark "$CONNMARK_0"
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j MARK --set-mark "$CONNMARK_0"
done
for cpu_id in "${CPUS_1[@]}"; do
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j CONNMARK --set-mark "$CONNMARK_1"
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j MARK --set-mark "$CONNMARK_1"
done
# Restore the connection mark for established connections so that packets use
# the same NIC regardless of other routing rules.
iptables -t mangle -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark
# Rewrite the source address after the packet is routed to the target interface
# so that replies return to the same NIC and pass VPC network validation.
iptables -t nat -A POSTROUTING -m mark --mark "$CONNMARK_0" -j SNAT --to-source "$SNAT_IP_0"
iptables -t nat -A POSTROUTING -m mark --mark "$CONNMARK_1" -j SNAT --to-source "$SNAT_IP_1"
Étapes suivantes
- En savoir plus sur la mise en réseau et les types de machines GPU
- Utiliser une bande passante réseau plus élevée sur les instances de GPU
- Configurer plusieurs interfaces réseau