Questo documento descrive i pattern di configurazione e le best practice per l'utilizzo delle due interfacce di rete (NIC) LAN host per l'archiviazione e la gestione sulle istanze Compute Engine.
Panoramica
Alcune serie di macchine ottimizzate per l'acceleratore, tra cui A5X, A4X Max, A4X, A4 e
A3 Ultra, dispongono di due interfacce di rete LAN host per l'archiviazione e la gestione che
si collegano alle normali reti Virtual Private Cloud (VPC). Queste macchine hanno anche
MRDMA interfacce di rete che devono essere collegate a una rete VPC Remote Direct Memory Access
over Converged Ethernet (RoCE).
Questo documento si concentra sulla configurazione delle interfacce LAN host (gVNIC o IDPF) su reti VPC standard, non su interfacce di rete RDMA.
Le interfacce LAN host sono unità di elaborazione dell'infrastruttura (IPU) Titanium che si connettono a socket della CPU e nodi di accesso alla memoria non uniforme (NUMA) separati. All'interno dell'istanza di computing, queste IPU vengono visualizzate come
Google Virtual NIC (gVNIC) o interfacce di rete Infrastructure Data Path Function (IDPF).
Queste interfacce forniscono la larghezza di banda di rete per le attività di archiviazione e gestione, come il checkpoint, il caricamento dei dati di addestramento e il caricamento dei modelli.
La topologia NUMA della macchina, inclusa la topologia delle interfacce di rete,
è visibile al sistema operativo (OS) guest.
Utilizza le seguenti configurazioni indipendentemente dal pattern scelto per più NIC host:
- Impostazioni di rete:
configura ogni interfaccia gVNIC o IDPF in modo che utilizzi una rete VPC separata.
Per la configurazione del VPC, completa le seguenti configurazioni:
- Configura un'unità massima di trasmissione (MTU) elevata per ogni rete VPC, ad esempio
8896(l'MTU massima supportata). - Se i pacchetti di dati in entrata ignorati sul lato ricevitore rallentano le prestazioni in entrata per il tuo workload, verifica la presenza di pacchetti ignorati utilizzando l'utilità
ethtool. Per ottimizzare l'allocazione dei dati dalla cache della pagina in modo che ogni frame di livello 2 in entrata rientri in due buffer da 4 KB, regola la dimensione massima del segmento (MSS) TCP, l'MTU dell'interfaccia o l'MTU del VPC.
- Configura un'unità massima di trasmissione (MTU) elevata per ogni rete VPC, ad esempio
- Impostazioni dell'applicazione:
- Allinea la tua applicazione a NUMA utilizzando i core della CPU, le allocazioni della memoria e
un'interfaccia di rete dello stesso nodo NUMA. Se esegui un'istanza dedicata dell'applicazione per un nodo NUMA o un'interfaccia di rete specifica, associa le risorse di CPU e memoria dell'applicazione a quel nodo NUMA utilizzando uno strumento come
numactl.
- Allinea la tua applicazione a NUMA utilizzando i core della CPU, le allocazioni della memoria e
un'interfaccia di rete dello stesso nodo NUMA. Se esegui un'istanza dedicata dell'applicazione per un nodo NUMA o un'interfaccia di rete specifica, associa le risorse di CPU e memoria dell'applicazione a quel nodo NUMA utilizzando uno strumento come
- Impostazioni del sistema operativo:
- Abilita il trasferimento della segmentazione TCP (TSO) e il trasferimento della ricezione di grandi dimensioni (LRO).
- Per ogni interfaccia gVNIC o IDPF, configura l'affinità di multiprocessing simmetrico (SMP) per instradare le richieste di interruzione (IRQ) allo stesso nodo NUMA dell'interfaccia e distribuire le interruzioni tra i core della CPU. Se utilizzi un'immagine Linux fornita da Google, l'agente guest di Compute Engine esegue lo script
google_set_multiqueueall'avvio per applicare automaticamente questa configurazione. Se utilizzi un'immagine personalizzata, installa l'ambiente guest. Se lo script non viene eseguito automaticamente, esegui il comandosudo /usr/bin/google_set_multiqueue. - Valuta le impostazioni di Receive Flow Steering (RFS), Receive Packet Steering (RPS) e Transmit Packet Steering (XPS) per determinare se sono utili per il tuo workload.
- Per le istanze A4X Max e A4X, NVIDIA consiglia di disattivare la pianificazione NUMA automatica.
- Non utilizzare il bonding del kernel Linux con le interfacce gVNIC o IDPF su queste macchine, perché il bonding del kernel non è supportato.
Pattern per l'utilizzo di più NIC host
La tabella seguente illustra i pattern generali per l'utilizzo di più NIC host suGoogle Cloud:
| Pattern | Layout di processo supportato | Percorso di deployment: Compute Engine | Percorso di deployment: Google Kubernetes Engine | Percorso di deployment: Slurm | Note |
|---|---|---|---|---|---|
| Modifica un'applicazione per utilizzare un'interfaccia specifica | Shard di processo per interfaccia | Sì | Sì | Sì | Richiede modifiche al codice dell'applicazione. |
| Modifica un'applicazione per utilizzare entrambe le interfacce | Processo a doppia interfaccia | Sì | Sì | Sì | Richiede modifiche al codice dell'applicazione. |
| Utilizza uno spazio dei nomi di rete dedicato per applicazioni specifiche | Shard di processo per interfaccia | Sì | Sì (solo container con privilegi) | No | Nessuno |
| Mappa il traffico di un intero container a una singola interfaccia | Tutto il traffico dei container mappato a un'interfaccia | Sì | Sì | No | Nessuno |
| Utilizza il peering VPC e consenti al sistema di bilanciare il carico delle sessioni tra le interfacce | Processo a doppia interfaccia | Sì | Sì | Sì | Difficile o impossibile da allineare a NUMA. Richiede il kernel Linux 6.16 o versioni successive. |
| Suddividi il traffico tra le reti |
|
Sì | Sì | Sì | Potrebbe richiedere modifiche al codice per l'allineamento NUMA se esegui un processo con doppia interfaccia. |
| Utilizza la Network Address Translation dell'origine (SNAT) per scegliere l'interfaccia di origine |
|
Sì | Sì (la configurazione richiede privilegi amministrativi) | Sì (la configurazione richiede privilegi amministrativi) | La configurazione può essere complessa. |
Note
- Per i pattern Utilizza il peering VPC e consenti al sistema di bilanciare il carico delle sessioni tra le interfacce e Suddividi il traffico tra le reti: queste opzioni non sono generalmente consigliate, ma potrebbero essere utili per workload limitati su piattaforme x86 (A4 e A3 Ultra).
Modifica un'applicazione per utilizzare un'interfaccia specifica
Requisiti:
- Richiede modifiche al codice dell'applicazione.
- Richiede le autorizzazioni per uno o più dei seguenti metodi:
bind(): richiede autorizzazioni speciali solo se utilizzi una porta di origine con privilegi.SO_BINDTODEVICE: richiede l'autorizzazioneCAP_NET_RAW.
- Potrebbe essere necessario modificare la tabella di routing del kernel per stabilire le route e impedire il routing asimmetrico.
Panoramica generale
Per configurare l'applicazione in modo che utilizzi un'interfaccia di rete specifica, completa i seguenti passaggi:
- Aggiungi l'associazione per un'interfaccia di rete al codice sorgente della tua applicazione utilizzando una delle seguenti opzioni:
- Utilizza la chiamata di sistema
bind()per associare un socket a un indirizzo IP di origine specifico. - Utilizza l'opzione socket
SO_BINDTODEVICEper associare un socket a un'interfaccia di rete specifica.
- Utilizza la chiamata di sistema
- Modifica la tabella di routing del kernel in base alle esigenze per assicurarti che esista una route dall'interfaccia di rete di origine all'indirizzo di destinazione. Per evitare il routing asimmetrico, configura il routing delle policy come descritto in Configura il routing per un'interfaccia di rete aggiuntiva.
- (Facoltativo) Esegui l'applicazione sulla memoria e sulle CPU che condividono lo stesso nodo NUMA dell'interfaccia di rete scelta utilizzando il comando
numactl.
Dopo aver completato questi passaggi, l'applicazione utilizza l'interfaccia di rete specificata.
Modifica un'applicazione per utilizzare entrambe le interfacce
Requisiti:
- Richiede modifiche al codice dell'applicazione.
- Richiede le autorizzazioni per uno o più dei seguenti metodi:
bind(): richiede autorizzazioni speciali solo se utilizzi una porta di origine con privilegi.SO_BINDTODEVICE: richiede l'autorizzazioneCAP_NET_RAW.
- Potrebbe essere necessario modificare la tabella di routing del kernel per stabilire le route e impedire il routing asimmetrico.
Panoramica generale
Per configurare l'applicazione in modo che utilizzi entrambe le interfacce di rete, completa i seguenti passaggi:
- Aggiungi un'associazione per ogni interfaccia di rete al codice sorgente della tua applicazione utilizzando una delle seguenti opzioni:
- Utilizza la chiamata di sistema
bind()per associare ogni socket all'indirizzo IP di origine dell'interfaccia di rete corrispondente. - Utilizza l'opzione socket
SO_BINDTODEVICEper associare ogni socket a un'interfaccia di rete specifica.
- Utilizza la chiamata di sistema
- Se la tua applicazione agisce come client, crea un socket client separato per ogni interfaccia di rete di origine.
- Modifica la tabella di routing del kernel in base alle esigenze per assicurarti che esista una route da ogni interfaccia di rete di origine all'indirizzo di destinazione. Per evitare il routing asimmetrico, configura il routing delle policy come descritto in Configura il routing per un'interfaccia di rete aggiuntiva.
- Suddividi l'attività di rete in thread eseguiti sullo stesso nodo NUMA dell'interfaccia gVNIC o IDPF corrispondente, ad esempio chiamando
pthread_setaffinity_np. Poiché l'applicazione utilizza risorse su più nodi NUMA, evita di utilizzarenumactlo assicurati che il comandonumactlincluda i nodi NUMA di tutte le interfacce di rete utilizzate dall'applicazione.
Utilizza uno spazio dei nomi di rete dedicato per applicazioni specifiche
Requisiti:
- Richiede la funzionalità
CAP_SYS_ADMIN. - Non è compatibile con GKE Autopilot.
- Se utilizzi GKE, devi utilizzare un container con privilegi.
Questa sezione descrive i pattern che puoi utilizzare per creare uno spazio dei nomi di rete per un'interfaccia di rete secondaria. Il pattern migliore per il tuo workload dipende dal tuo scenario. Gli approcci che utilizzano uno switch virtuale o IPvlan funzionano meglio quando più applicazioni devono condividere l'interfaccia secondaria da spazi dei nomi di rete diversi.
Sposta l'interfaccia secondaria in uno spazio dei nomi di rete dedicato
Con questo pattern, crei uno spazio dei nomi di rete, sposti l'interfaccia gVNIC o IDPF secondaria nel nuovo spazio dei nomi, quindi esegui l'applicazione da quello spazio dei nomi. Questo pattern è più semplice da configurare e ottimizzare rispetto a uno switch virtuale, ma le applicazioni esterne al nuovo spazio dei nomi di rete non possono accedere all'interfaccia di rete secondaria.
Per spostare l'interfaccia eth1 in uno spazio dei nomi di rete denominato app-net ed eseguire un comando in questo spazio dei nomi, esegui questi comandi:
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
Sostituisci quanto segue:
ETH1_IP: l'indirizzo IP interno dell'interfacciaeth1.PREFIX: la lunghezza del prefisso della subnet per l'interfacciaeth1.GATEWAY_IP: l'indirizzo IP del gateway predefinito per la subneteth1.COMMAND: il comando da eseguire all'interno dello spazio dei nomi di reteapp-net.
Quando esegui questi comandi, COMMAND viene eseguito all'interno dello spazio dei nomi di rete app-net e utilizza l'interfaccia eth1.
Le applicazioni in esecuzione all'interno del nuovo spazio dei nomi di rete utilizzano l'interfaccia gVNIC o IDPF secondaria. Puoi anche utilizzare il comando numactl per eseguire l'applicazione
utilizzando la memoria e le CPU sullo stesso nodo NUMA dell'interfaccia di rete
scelta.
Utilizza uno switch virtuale e uno spazio dei nomi di rete per un'interfaccia secondaria
Con questo pattern, configuri uno switch virtuale per accedere all'interfaccia gVNIC o IDPF secondaria da uno spazio dei nomi di rete:
- Apri una connessione SSH all'istanza di computing. Per saperne di più, consulta Connettiti alle VM Linux.
- Crea una coppia di dispositivi Virtual Ethernet (
veth) utilizzando il comandoip link add, ad esempioip link add veth0 type veth peer name veth1. Regola l'MTU su ogni dispositivo in modo che corrisponda all'MTU dell'interfaccia secondaria utilizzando il comando
ip link set:ip link set dev veth0 mtu MTU ip link set dev veth1 mtu MTU
Sostituisci
MTUcon la MTU dell'interfaccia secondaria, ad esempio8896.Abilita l'IP forwarding IPv4:
sysctl -w net.ipv4.ip_forward=1
Sposta un'estremità della coppia
vethin un nuovo spazio dei nomi di rete e lascia l'altra estremità nello spazio dei nomi principale.Mappa il traffico dal dispositivo
vethall'interfaccia secondaria. Per configurare questa mappatura, crea un intervallo IP alias per l'interfaccia secondaria dell'istanza di computing e assegna un indirizzo IP di questo intervallo all'interfaccia secondaria nello spazio dei nomi.Esegui l'applicazione dal nuovo spazio dei nomi di rete. Puoi utilizzare il comando
numactlper eseguire l'applicazione utilizzando la memoria e le CPU sullo stesso nodo NUMA dell'interfaccia di rete scelta.
In alternativa, a seconda del sistema operativo guest e della configurazione del workload, puoi collegare un'interfaccia IPvlan all'interfaccia gVNIC o IDPF secondaria anziché creare dispositivi veth.
Mappa il traffico di un intero container a una singola interfaccia
Requisiti:
- L'applicazione deve essere eseguita all'interno di un container che utilizza uno spazio dei nomi di rete per il networking dei container, ad esempio GKE, Docker o Podman. Non puoi utilizzare la rete host.
I runtime dei container come GKE, Docker e Podman utilizzano uno spazio dei nomi di rete dedicato per ogni container per isolare il traffico. Puoi modificare questo spazio dei nomi di rete, direttamente o utilizzando gli strumenti del runtime del container, per mappare il traffico a un'interfaccia di rete diversa.
GKE richiede l'interfaccia principale per la comunicazione interna di Kubernetes. Tuttavia, puoi modificare la route predefinita nel pod in modo che utilizzi l'interfaccia secondaria, come mostrato nel seguente manifest del pod GKE:
metadata:
# ...
annotations:
networking.gke.io/default-interface: 'eth1'
networking.gke.io/interfaces: |
[
{"interfaceName":"eth0","network":"default"},
{"interfaceName":"eth1","network":"secondary-network"}
]
Questo approccio non garantisce l'allineamento NUMA tra l'interfaccia di rete predefinita e le CPU o la memoria assegnate.
Utilizza il peering VPC e consenti al sistema di bilanciare il carico delle sessioni tra le interfacce
Requisiti:
- Devi stabilire il peering di rete VPC tra le reti VPC delle NIC host principali e secondarie.
- Per bilanciare il carico delle sessioni TCP tra le interfacce di origine quando invii traffico a un singolo indirizzo IP e a una singola porta di destinazione, devi utilizzare la versione kernel Linux 6.16 o successive.
- Il tuo workload deve tollerare i trasferimenti di memoria tra socket senza mancare i target di rendimento.
Panoramica generale
Se non riesci a eseguire facilmente lo sharding delle connessioni di rete all'interno di un'applicazione o tra istanze di applicazioni e il tuo workload viene eseguito su istanze di computing A4 o A3 Ultra che non sono sensibili ai trasferimenti tra NUMA o tra socket, puoi considerare le due interfacce come fungibili.
Per configurare questo comportamento, attiva il parametro sysctl fib_multipath_hash_policy e aggiungi un percorso multipath:
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}
Sostituisci quanto segue:
DESTINATION_NETWORK: l'intervallo di indirizzi IP interni di destinazione.SUBNET_MASK: la lunghezza del prefisso della subnet per la rete di destinazione.
Suddividi il traffico tra le reti
Requisiti:
nic0enic1nell'istanza di computing devono connettersi a reti VPC e subnet separate e gli indirizzi IP di destinazione devono essere suddivisi in shard tra le due reti VPC.
Panoramica generale
Per impostazione predefinita, il kernel Linux crea route per la subnet nic0 e la subnet nic1 che instradano il traffico in base all'indirizzo IP di destinazione tramite l'interfaccia di rete corrispondente.
Ad esempio, supponiamo che nic0 utilizzi la rete VPC net1 con la subnet subnet-a e che nic1 utilizzi la rete VPC net2 con la subnet subnet-b. Per impostazione predefinita, il traffico verso gli indirizzi IP peer in subnet-a utilizza nic0,
mentre il traffico verso gli indirizzi IP peer in subnet-b utilizza nic1. Questa configurazione
viene comunemente applicata quando un insieme di istanze di computing con NIC singola in peering si connette a
net1 e un secondo insieme si connette a net2.
Utilizza SNAT per scegliere l'interfaccia di origine
Requisiti:
- Richiede la funzionalità
CAP_NET_ADMINper configurare le regoleiptablesiniziali, anche se non per eseguire l'applicazione. - Richiede un'attenta valutazione se combinata con altre regole
iptableso configurazioni di routing non banali.
Panoramica generale
Se non puoi utilizzare gli spazi dei nomi di rete o modificare l'applicazione, puoi utilizzare SNAT per selezionare un'interfaccia di origine. Utilizzando uno strumento come iptables, puoi riscrivere l'indirizzo IP di origine di un flusso in modo che corrisponda all'indirizzo IP di un'interfaccia specifica in base a una proprietà dell'applicazione di invio, ad esempio cgroup, utente o CPU.
L'esempio seguente utilizza regole basate sulla CPU in modo che qualsiasi flusso proveniente da un thread su una determinata CPU esca tramite l'interfaccia gVNIC o IDPF collegata al nodo NUMA di quella CPU:
# --- 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"
Passaggi successivi
- Scopri di più sul networking e sui tipi di macchine GPU
- Utilizza una larghezza di banda di rete più elevata sulle istanze GPU
- Configura più interfacce di rete