En este documento, se describen los patrones de configuración y las prácticas recomendadas para usar las dos interfaces de red (NIC) de LAN del host para el almacenamiento y la administración en instancias de Compute Engine.
Descripción general
Algunas series de máquinas optimizadas para aceleradores, incluidas A5X, A4X Max, A4X, A4 y
A3 Ultra, tienen dos interfaces de red LAN de host para el almacenamiento y la administración que
se conectan a redes de nube privada virtual (VPC) normales. Estas máquinas también tienen
interfaces de red MRDMA que deben conectarse a una red de VPC de acceso remoto directo a memoria
sobre Ethernet convergente (RoCE).
Este documento se enfoca en configurar las interfaces de LAN del host (gVNIC o
IDPF) en redes de VPC normales, no en interfaces de red de RDMA.
Las interfaces de LAN del host son unidades de procesamiento de infraestructura (IPU) Titanium que se conectan a zócalos de CPU independientes y nodos de acceso a la memoria no uniforme (NUMA). Dentro de la instancia de procesamiento, estas IPU aparecen como
NIC virtuales de Google (gVNIC) o interfaces de red de función de ruta de acceso de datos de infraestructura (IDPF).
Estas interfaces proporcionan ancho de banda de red para las actividades de almacenamiento y administración,
como la creación de puntos de control, la carga de datos de entrenamiento y la carga de modelos.
La topología de NUMA de la máquina, incluida la topología de las interfaces de red,
es visible para el sistema operativo (SO) invitado.
Usa los siguientes parámetros de configuración, sin importar el patrón que elijas para las NIC de varios hosts:
- Configuración de red:
Configura cada interfaz de gVNIC o IDPF para usar una red de VPC independiente.
Para configurar la VPC, completa los siguientes pasos:
- Configura una unidad de transmisión máxima (MTU) grande para
cada red de VPC, como
8896(la MTU máxima admitida). - Si los paquetes de datos entrantes descartados en el lado del receptor ralentizan el rendimiento de entrada
de tu carga de trabajo, verifica si hay paquetes descartados con
la utilidad
ethtool. Para optimizar la asignación de datos de la caché de páginas, de modo que cada trama de capa 2 entrante quepa en dos búferes de 4 KB, ajusta el tamaño máximo de segmento (MSS) de TCP, la MTU de la interfaz o la MTU de la VPC.
- Configura una unidad de transmisión máxima (MTU) grande para
cada red de VPC, como
- Configuración de la aplicación:
- Alinea tu aplicación con NUMA usando núcleos de CPU, asignaciones de memoria y
una interfaz de red del mismo nodo de NUMA. Si ejecutas una
instancia dedicada de la aplicación para un nodo de NUMA o una interfaz de red específicos, vincula los recursos de CPU y memoria de la aplicación
a ese nodo de NUMA con una herramienta como
numactl.
- Alinea tu aplicación con NUMA usando núcleos de CPU, asignaciones de memoria y
una interfaz de red del mismo nodo de NUMA. Si ejecutas una
instancia dedicada de la aplicación para un nodo de NUMA o una interfaz de red específicos, vincula los recursos de CPU y memoria de la aplicación
a ese nodo de NUMA con una herramienta como
- Configuración del sistema operativo:
- Habilita la descarga de segmentación de TCP (TSO) y la descarga de recepción grande (LRO).
- Para cada interfaz de gVNIC o IDPF, configura la afinidad de multiprocesamiento
simétrico (SMP) para enrutar las solicitudes de interrupción (IRQ) al
mismo nodo NUMA que la interfaz y distribuir las interrupciones entre los núcleos
de CPU. Si usas una imagen de Linux proporcionada por Google, el
agente invitado de Compute Engine ejecuta la secuencia de comandos
google_set_multiqueueen el inicio para aplicar esta configuración de forma automática. Si usas una imagen personalizada, instala el entorno de invitado. Si la secuencia de comandos no se ejecuta automáticamente, ejecuta el comandosudo /usr/bin/google_set_multiqueue. - Evalúa la configuración de Receive Flow Steering (RFS), Receive Packet Steering (RPS) y Transmit Packet Steering (XPS) para determinar si benefician tu carga de trabajo.
- Para las instancias A4X Max y A4X, NVIDIA recomienda que inhabilites la programación automática de NUMA.
- No uses la vinculación del kernel de Linux con las interfaces gVNIC o IDPF en estas máquinas, ya que no se admite la vinculación del kernel.
Patrones para usar varias NIC de host
En la siguiente tabla, se describen los patrones generales para usar varias NIC de host en Cloud de Confiance by S3NS:
| Patrón | Diseño de proceso admitido | Ruta de Deployment: Compute Engine | Ruta de Deployment: Google Kubernetes Engine | Ruta de Deployment: Slurm | Notas |
|---|---|---|---|---|---|
| Cambia una aplicación para usar una interfaz específica | Procesa el fragmento por interfaz | Sí | Sí | Sí | Requiere cambios de código en la aplicación. |
| Cambia una aplicación para usar ambas interfaces | Proceso de interfaz doble | Sí | Sí | Sí | Requiere cambios de código en la aplicación. |
| Usa un espacio de nombres de red dedicado para aplicaciones específicas | Procesa el fragmento por interfaz | Sí | Sí (solo contenedores con privilegios) | No | Ninguno |
| Asigna todo el tráfico de un contenedor a una sola interfaz | Todo el tráfico de contenedores se asigna a una interfaz | Sí | Sí | No | Ninguno |
| Usa el intercambio de tráfico entre VPC y permite que el sistema balancee las cargas de las sesiones entre las interfaces | Proceso de interfaz doble | Sí | Sí | Sí | Es difícil o imposible alinear con NUMA. Requiere el kernel de Linux 6.16 o una versión posterior. |
| Fragmenta el tráfico entre redes |
|
Sí | Sí | Sí | Es posible que se requieran cambios en el código para la alineación de NUMA si ejecutas un proceso de interfaz doble. |
| Usa la traducción de direcciones de red de origen (SNAT) para elegir la interfaz de origen |
|
Sí | Sí (la configuración requiere privilegios de administrador) | Sí (la configuración requiere privilegios de administrador) | Puede ser difícil de configurar. |
Notas
- Para los patrones Usa el intercambio de tráfico entre VPC y permite que el sistema balancee las cargas de las sesiones entre las interfaces y Fragmenta el tráfico entre redes: Por lo general, no se recomiendan estas opciones, pero pueden ser útiles para cargas de trabajo limitadas en plataformas x86 (A4 y A3 Ultra).
Cambia una aplicación para que use una interfaz específica
Requisitos:
- Requiere cambios de código en tu aplicación.
- Requiere permisos para uno o más de los siguientes métodos:
bind(): Requiere permisos especiales solo si usas un puerto de origen con privilegios.SO_BINDTODEVICE: Requiere el permisoCAP_NET_RAW.
- Es posible que debas modificar la tabla de enrutamiento del kernel para establecer rutas y evitar el enrutamiento asimétrico.
Descripción general de alto nivel
Para configurar tu aplicación de modo que use una interfaz de red específica, completa los siguientes pasos:
- Agrega la vinculación de una interfaz de red al código fuente de tu aplicación con
una de las siguientes opciones:
- Usa la llamada al sistema
bind()para vincular un socket a una dirección IP de origen específica. - Usa la opción de socket
SO_BINDTODEVICEpara vincular un socket a una interfaz de red específica.
- Usa la llamada al sistema
- Modifica la tabla de enrutamiento del kernel según sea necesario para asegurarte de que exista una ruta desde la interfaz de red de origen hasta la dirección de destino. Para evitar el enrutamiento asimétrico, configura la política de enrutamiento como se describe en Configura el enrutamiento para una interfaz de red adicional.
- Opcional: Ejecuta tu aplicación en la memoria y las CPU que comparten el mismo
nodo de NUMA que la interfaz de red que elegiste con el comando
numactl.
Después de completar estos pasos, tu aplicación usará la interfaz de red especificada.
Cambia una aplicación para que use ambas interfaces
Requisitos:
- Requiere cambios de código en tu aplicación.
- Requiere permisos para uno o más de los siguientes métodos:
bind(): Requiere permisos especiales solo si usas un puerto de origen con privilegios.SO_BINDTODEVICE: Requiere el permisoCAP_NET_RAW.
- Es posible que debas modificar la tabla de enrutamiento del kernel para establecer rutas y evitar el enrutamiento asimétrico.
Descripción general de alto nivel
Para configurar tu aplicación de modo que use ambas interfaces de red, completa los siguientes pasos:
- Agrega una vinculación para cada interfaz de red al código fuente de tu aplicación con
una de las siguientes opciones:
- Usa la llamada al sistema
bind()para vincular cada socket a la dirección IP de origen de la interfaz de red correspondiente. - Usa la opción de socket
SO_BINDTODEVICEpara vincular cada socket a una interfaz de red específica.
- Usa la llamada al sistema
- Si tu aplicación actúa como cliente, crea un socket del cliente independiente para cada interfaz de red de origen.
- Modifica la tabla de enrutamiento del kernel según sea necesario para asegurarte de que exista una ruta desde cada interfaz de red de origen hasta la dirección de destino. Para evitar el enrutamiento asimétrico, configura la política de enrutamiento como se describe en Configura el enrutamiento para una interfaz de red adicional.
- Divide la actividad de red en subprocesos que se ejecuten en el mismo nodo NUMA que
la interfaz gVNIC o IDPF correspondiente, por ejemplo, llamando a
pthread_setaffinity_np. Debido a que la aplicación usa recursos en varios nodos NUMA, evita usarnumactlo asegúrate de que el comandonumactlincluya los nodos NUMA de todas las interfaces de red que usa tu aplicación.
Usa un espacio de nombres de red dedicado para aplicaciones específicas
Requisitos:
- Requiere la capacidad
CAP_SYS_ADMIN. - No es compatible con Autopilot de GKE.
- Si usas GKE, debes usar un contenedor con privilegios.
En esta sección, se describen los patrones que puedes usar para crear un espacio de nombres de red para una interfaz de red secundaria. El mejor patrón para tu carga de trabajo depende de tu situación. Los enfoques que usan un interruptor virtual o IPvlan funcionan mejor cuando varias aplicaciones necesitan compartir la interfaz secundaria desde diferentes espacios de nombres de red.
Mueve la interfaz secundaria a un espacio de nombres de red dedicado
Con este patrón, creas un espacio de nombres de red, mueves la interfaz secundaria de gVNIC o IDPF al espacio de nombres nuevo y, luego, ejecutas la aplicación desde ese espacio de nombres. Este patrón es más fácil de configurar y ajustar en comparación con un interruptor virtual, pero las aplicaciones fuera del nuevo espacio de nombres de red no pueden acceder a la interfaz de red secundaria.
Para mover la interfaz eth1 a un espacio de nombres de red llamado app-net y ejecutar un
comando en ese espacio de nombres, ejecuta los siguientes comandos:
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
Reemplaza lo siguiente:
ETH1_IP: Es la dirección IP interna de la interfazeth1.PREFIX: Es la longitud del prefijo de la subred para la interfazeth1.GATEWAY_IP: Es la dirección IP de la puerta de enlace predeterminada para la subredeth1.COMMAND: Es el comando que se ejecutará dentro del espacio de nombres de redapp-net.
Cuando ejecutas estos comandos, COMMAND se ejecuta dentro del espacio de nombres de red app-net
y usa la interfaz eth1.
Las aplicaciones que se ejecutan dentro del espacio de nombres de red nuevo usan la interfaz secundaria de gVNIC o
IDPF. También puedes usar el comando numactl para ejecutar tu aplicación
con la memoria y las CPU en el mismo nodo NUMA que la interfaz de red
que elegiste.
Usa un switch virtual y un espacio de nombres de red para una interfaz secundaria
Con este patrón, configuras un interruptor virtual para acceder a la interfaz secundaria de gVNIC o IDPF desde un espacio de nombres de red:
- Abre una conexión SSH a la instancia de procesamiento. Para obtener más información, consulta Conéctate a VMs de Linux.
- Crea un par de dispositivos
Ethernet virtual (
veth) con el comandoip link add, por ejemplo,ip link add veth0 type veth peer name veth1. Ajusta la MTU en cada dispositivo para que coincida con la MTU de la interfaz secundaria con el comando
ip link set:ip link set dev veth0 mtu MTU ip link set dev veth1 mtu MTU
Reemplaza
MTUpor la MTU de la interfaz secundaria, por ejemplo,8896.Habilita el reenvío de paquetes IPv4:
sysctl -w net.ipv4.ip_forward=1
Mueve un extremo del par
vetha un espacio de nombres de red nuevo y deja el otro extremo en el espacio de nombres raíz.Asigna el tráfico del dispositivo
vetha la interfaz secundaria. Para configurar esta asignación, crea un rango de alias de IP para la interfaz secundaria de la instancia de procesamiento y asigna una dirección IP de este rango a la interfaz secundaria en el espacio de nombres.Ejecuta la aplicación desde el nuevo espacio de nombres de red. Puedes usar el comando
numactlpara ejecutar tu aplicación con la memoria y las CPU en el mismo nodo NUMA que la interfaz de red elegida.
Como alternativa, según el SO invitado y la configuración de la carga de trabajo, puedes vincular una interfaz
IPvlan
a la interfaz secundaria de gVNIC o IDPF en lugar de crear dispositivos
veth.
Asigna todo el tráfico de un contenedor a una sola interfaz
Requisitos:
- La aplicación debe ejecutarse dentro de un contenedor que use un espacio de nombres de red para las herramientas de redes de contenedores, como GKE, Docker o Podman. No puedes usar la red del host.
Los entornos de ejecución de contenedores, como GKE, Docker y Podman, usan un espacio de nombres de red dedicado para cada contenedor con el objetivo de aislar su tráfico. Puedes modificar este espacio de nombres de red, ya sea directamente o con las herramientas del entorno de ejecución del contenedor, para asignar el tráfico a una interfaz de red diferente.
GKE requiere la interfaz principal para la comunicación interna de Kubernetes. Sin embargo, puedes cambiar la ruta predeterminada en el Pod para usar la interfaz secundaria, como se muestra en el siguiente manifiesto de Pod de GKE:
metadata:
# ...
annotations:
networking.gke.io/default-interface: 'eth1'
networking.gke.io/interfaces: |
[
{"interfaceName":"eth0","network":"default"},
{"interfaceName":"eth1","network":"secondary-network"}
]
Este enfoque no garantiza la alineación de NUMA entre la interfaz de red predeterminada y las CPU o la memoria asignadas.
Usa el intercambio de tráfico entre VPC y permite que el sistema balancee las cargas de las sesiones entre las interfaces.
Requisitos:
- Debes establecer el intercambio de tráfico entre redes de VPC entre las redes de VPC de las NIC de host principal y secundaria.
- Debes usar la versión de kernel 6.16 o posterior de Linux para balancear las cargas de las sesiones de TCP en las interfaces de origen cuando envíes tráfico a una sola dirección IP y puerto de destino.
- Tu carga de trabajo debe tolerar las transferencias de memoria entre sockets sin perder sus objetivos de rendimiento.
Descripción general de alto nivel
Si no puedes fragmentar fácilmente las conexiones de red dentro de una aplicación o entre instancias de aplicación, y tu carga de trabajo se ejecuta en instancias de procesamiento A4 o A3 Ultra que no son sensibles a las transferencias entre NUMA o entre sockets, puedes tratar las dos interfaces como fungibles.
Para configurar este comportamiento, habilita el parámetro sysctl fib_multipath_hash_policy
y agrega una ruta de acceso de múltiples rutas:
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}
Reemplaza lo siguiente:
DESTINATION_NETWORK: el rango de direcciones IP internas de destino.SUBNET_MASK: Es la longitud del prefijo de la subred para la red de destino.
Fragmenta el tráfico entre redes
Requisitos:
nic0ynic1en la instancia de procesamiento deben conectarse a redes de VPC y subredes independientes, y las direcciones IP de destino deben fragmentarse en las dos redes de VPC.
Descripción general de alto nivel
De forma predeterminada, el kernel de Linux crea rutas para la subred nic0 y la subred nic1
que enrutan el tráfico por dirección IP de destino a través de la interfaz de red
correspondiente.
Por ejemplo, supongamos que nic0 usa la red de VPC net1 con la subred
subnet-a y nic1 usa la red de VPC net2 con la subred
subnet-b. De forma predeterminada, el tráfico a las direcciones IP de intercambio de tráfico en subnet-a usa nic0,
y el tráfico a las direcciones IP de intercambio de tráfico en subnet-b usa nic1. Esta configuración
suele aplicarse cuando un conjunto de instancias de procesamiento de NIC única de par se conecta a
net1 y un segundo conjunto se conecta a net2.
Usa SNAT para elegir la interfaz de origen
Requisitos:
- Requiere la capacidad
CAP_NET_ADMINpara configurar las reglas iniciales deiptables, pero no para ejecutar la aplicación. - Requiere una evaluación cuidadosa cuando se combina con otras reglas de
iptableso parámetros de configuración de enrutamiento no triviales.
Descripción general de alto nivel
Si no puedes usar espacios de nombres de red ni modificar tu aplicación, puedes usar
SNAT para seleccionar una interfaz de origen. Con una herramienta como iptables, puedes
reescribir la dirección IP de origen de un flujo para que coincida con la dirección IP de una interfaz específica
en función de una propiedad de la aplicación de envío, como su cgroup,
usuario o CPU.
En el siguiente ejemplo, se usan reglas basadas en CPU para que cualquier flujo que se origine en un subproceso de una CPU determinada salga a través de la interfaz de gVNIC o IDPF conectada al nodo NUMA de esa 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"