5 puntos por GN⁺ 2024-07-29 | 1 comentarios | Compartir por WhatsApp
  • El ajuste de rendimiento de red en Linux consiste en interpretar, con base en los cuellos de botella, el flujo por el que los paquetes pasan por el ring buffer de la NIC, IRQ, NAPI, softIRQ, qdisc, buffers TCP y llegan al socket de la aplicación
  • En la ruta de recepción, la NIC escribe los paquetes en la RAM mediante DMA y genera una HardIRQ; luego el driver programa NAPI para vaciar el ring buffer en NET_RX_SOFTIRQ y entregarlo a las capas IP/TCP y al buffer de recepción del socket
  • ethtool, /proc/net/softnet_stat, ss, netstat y sysctl son el punto de partida para observar y ajustar; los ejes principales son la coalescencia de interrupciones, la afinidad de IRQ, RSS/RPS/RFS/aRFS, netdev_budget, netdev_max_backlog, txqueuelen y los buffers de lectura/escritura de TCP
  • No existe una configuración única que funcione para todos los sistemas: aumentar el ring buffer puede reducir las pérdidas, pero también aumentar la latencia, y la coalescencia de interrupciones puede bajar el uso de CPU y las HardIRQ a cambio de un costo en latencia
  • El procesamiento de paquetes de alto rendimiento puede ampliarse con opciones como PACKET_MMAP, DPDK, PF_RING y XDP/AF_XDP, pero la dependencia de hardware, el consumo de CPU y los requisitos de versión del kernel varían entre el bypass del kernel, zero-copy y cada ruta rápida dentro del kernel

Ruta de recepción en Linux: de la NIC al socket

  • El dispositivo de red genera una IRQ para avisar la llegada de un paquete, y el mapeo de IRQ en Linux se guarda en /proc/interrupts
  • El manejador de IRQ se ejecuta con prioridad muy alta y en algunos casos bloquea la generación de IRQ adicionales, por lo que el driver pospone las tareas largas fuera del contexto de IRQ
  • Para este procesamiento diferido se usa softIRQ; en el manejo de recepción de red se crean, por CPU, el hilo del kernel ksoftirqd/<cpu-number>, softnet_data y poll_list
  • net_dev_init registra NET_RX_SOFTIRQ en el sistema de softIRQ, y su manejador correspondiente es net_rx_action
  • Llegada del paquete y procesamiento con NAPI

    • La NIC escribe en la RAM, mediante DMA, los datos recibidos desde la red en el ring buffer
    • Algunas NIC son NIC multiqueue con varios ring buffers
    • Cuando la NIC genera una HardIRQ, se ejecuta el manejador de IRQ del driver
    • El driver limpia la IRQ de la NIC y llama a napi_schedule para iniciar el bucle de sondeo softIRQ de NAPI
    • napi_schedule agrega la estructura NAPI del driver al poll_list de la CPU actual y establece el bit pendiente de softIRQ
    • Cuando ksoftirqd llama a __do_softirq, se ejecuta net_rx_action, el manejador de NET_RX_SOFTIRQ que estaba pendiente
  • GRO y entrada a la pila de protocolos

    • net_rx_action revisa la lista de sondeo de NAPI y verifica el budget y el tiempo transcurrido para evitar que la softIRQ monopolice la CPU
    • La función poll del driver recolecta paquetes desde el ring buffer de la RAM
    • Los paquetes se entregan a napi_gro_receive
    • GRO (Generic Receive Offloading) es una técnica de offload por software que reensambla paquetes pequeños en paquetes grandes para reducir la cantidad de paquetes que la aplicación debe procesar
    • Si GRO no retiene el paquete, este sube por la pila de protocolos a través de netif_receive_skb
  • Bifurcación según si RPS está habilitado

    • Cuando RPS está deshabilitado:
      • netif_receive_skb entrega los datos a __netif_receive_core
      • __netif_receive_core entrega los datos a tap y a los manejadores de capas de protocolo registrados
    • Cuando RPS está habilitado:
      • netif_receive_skb entrega los datos a enqueue_to_backlog
      • El paquete entra en la cola de entrada por CPU
      • La estructura NAPI de la CPU remota se agrega al poll_list de esa CPU y se encola una IPI para despertar el hilo softIRQ de la CPU remota
      • El ksoftirqd de la CPU remota recolecta paquetes desde la cola de entrada de la CPU con la función de sondeo process_backlog
  • IP, TCP y buffer de recepción del socket

    • Los paquetes se reciben en la capa IPv4 mediante ip_rcv y pasan por netfilter y optimizaciones de enrutamiento
    • Los datos destinados al sistema actual se entregan a capas de protocolo superiores como UDP o TCP
    • En la ruta de recepción TCP, pasan por tcp_v4_rcv, la máquina de estados finitos de TCP y la búsqueda del socket antes de entrar al buffer de recepción
    • El tamaño del buffer de recepción sigue las reglas de tcp_rmem
    • Si tcp_moderate_rcvbuf está habilitado, el kernel ajusta automáticamente el buffer de recepción
    • tcp_rmem contiene los valores mínimo, predeterminado y máximo del buffer de recepción de los sockets TCP
    • Si se usa SO_RCVBUF, se desactiva el ajuste automático del buffer de recepción para ese socket
    • net.core.rmem_max es el límite superior del tamaño del buffer de recepción TCP, y una ventana más grande permite enviar más datos antes de mandar un ACK, lo que puede reducir la latencia y aumentar el throughput

Ruta de transmisión en Linux: de la aplicación a la NIC

  • La ruta de transmisión es más simple que la de recepción, pero intervienen qdisc, el buffer de escritura TCP, DMA e IRQ
  • Cuando la aplicación envía un mensaje con una llamada como sendmsg, la ruta de transmisión TCP asigna un skb_buff
  • Los paquetes entran en el buffer de escritura del socket, cuyo tamaño sigue tcp_wmem
    • tcp_wmem contiene los valores mínimo, predeterminado y máximo del buffer de transmisión de los sockets TCP
    • El kernel ajusta dinámicamente el tamaño del buffer de transmisión TCP entre el mínimo y el máximo
    • Si se usa SO_SNDBUF, se desactiva el ajuste automático del buffer de transmisión para ese socket
    • net.core.wmem_max es el límite superior del tamaño del buffer de transmisión TCP
  • Se crean el encabezado TCP y el encabezado IP, y luego de pasar por LOCAL_OUT, el enrutamiento, POST_ROUTING y la fragmentación, dev_queue_xmit invoca la función de transmisión L2
  • La qdisc de salida usa la longitud txqueuelen y el algoritmo default_qdisc
  • El driver coloca los paquetes en el ring buffer TX y ejecuta NET_TX_SOFTIRQ después del timeout tx-usecs o tras tx-frames
  • La NIC toma los paquetes desde la RAM mediante DMA y los transmite; al completarse la transmisión, genera una HardIRQ
  • El driver procesa esta IRQ y programa el sistema de sondeo NAPI para liberar la RAM

Herramientas de observación y puntos básicos de verificación

  • /proc/net/softnet_stat

    • Cada línea de /proc/net/softnet_stat representa un núcleo de CPU y comienza desde CPU0
    • Las estadísticas de cada columna se muestran en hexadecimal
    • La 1.ª columna es la cantidad de tramas recibidas por el manejador de interrupciones
    • La 2.ª columna es la cantidad de tramas descartadas por exceder netdev_max_backlog
    • La 3.ª columna es la cantidad de veces que ksoftirqd agotó netdev_budget o el tiempo de CPU mientras aún quedaba trabajo por procesar
    • El resto de las columnas puede variar según la versión de Linux
  • /proc/net/sockstat y ss

    • En /proc/net/sockstat se revisa el campo mem
    • Este valor se calcula sumando sk_buff->truesize de todos los sockets
    • ss es una herramienta para volcar estadísticas de sockets, y puede mostrar información similar a netstat junto con más detalles de TCP y del estado
    • ss -tm se usa para revisar el uso de memoria de los sockets TCP
    • rmem_alloc: memoria asignada a los paquetes recibidos
    • rcv_buf: memoria total que puede asignarse a los paquetes recibidos
    • wmem_alloc: memoria usada por los paquetes transmitidos que ya fueron entregados a la capa 3
    • snd_buf: memoria total que puede asignarse a los paquetes transmitidos
    • wmem_queued: memoria asignada a los paquetes transmitidos que aún no han sido entregados a la capa 3
    • sock_drop: cantidad de paquetes descartados antes de ser demultiplexados hacia el socket
  • netstat y sysctl

    • netstat es una herramienta de línea de comandos que muestra conexiones de red abiertas y estadísticas de la pila de protocolos, y obtiene la información del sistema de archivos /proc/net/
    • /proc/net/dev: información de dispositivos
    • /proc/net/tcp: información de sockets TCP
    • /proc/net/unix: información de sockets de dominio Unix
    • sysctl es el comando para cambiar configuraciones del sistema y de red en lugar de escribir valores directamente en el sistema de archivos /proc
    • sysctl -w variable=value se usa para cambios temporales, y los cambios permanentes se aplican editando /etc/sysctl.conf y luego ejecutando sysctl -p

Buffers de anillo del NIC y ajuste de interrupciones

  • Buffers de anillo del NIC

    • El buffer de anillo RX es un buffer circular FIFO de tamaño fijo ubicado en RAM
    • El buffer de anillo en sí no contiene los datos de los paquetes, sino descriptores que apuntan al skb que entró a la RAM por DMA
    • Si se observan drops u overruns, se puede aumentar el tamaño de la cola, aunque como efecto secundario puede aumentar la latencia
    • En muchos casos, solo aumentar el tamaño del buffer de recepción puede evitar la pérdida de paquetes y darle al kernel un poco más de tiempo para vaciar el buffer
    • La verificación y el cambio se realizan con ethtool
    • ethtool -g eth3: revisar el tamaño actual de los anillos RX/TX y los valores máximos
    • ethtool -G eth3 rx 8192 tx 8192: aumentar los buffers RX/TX al valor máximo
    • Se monitorea con ethtool -S eth3 y contadores como err, drop, over, miss, timeout, reset, collis
  • Coalescencia de interrupciones de hardware

    • El NIC puede acumular referencias de paquetes en el buffer de anillo RX hasta cumplir la condición de timeout rx-usecs o rx-frames, y luego generar una HardIRQ; a esto se le llama Interrupt coalescence
    • Si interrumpe demasiado pronto, el kernel interrumpe con frecuencia el trabajo en ejecución y el rendimiento del sistema empeora
    • Si interrumpe demasiado tarde, puede no vaciar el tráfico del NIC con la suficiente rapidez, lo que puede causar sobrescritura y pérdida de tráfico
    • Ajustar la coalescencia de interrupciones puede reducir el uso de CPU y las HardIRQ, y aumentar el throughput, pero puede tener un costo en latencia
    • Los parámetros de coalescencia se revisan con ethtool -c eth3 y pueden cambiarse, por ejemplo, con ethtool -C eth3 adaptive-rx off rx-usecs 0 rx-frames 0
    • En modo adaptativo, la tarjeta estima dinámicamente la configuración de coalescing según el patrón de tráfico y el patrón de recepción del kernel

IRQ affinity y balanceo de carga entre CPU

  • IRQ affinity

    • Las IRQ tienen una propiedad smp_affinity que define qué núcleos de CPU pueden ejecutar la ISR de esa IRQ
    • Alinear la afinidad de interrupciones y la afinidad de los hilos de la aplicación con núcleos de CPU específicos puede mejorar el rendimiento de la aplicación gracias al uso compartido de líneas de caché
    • De forma predeterminada, lo controla el daemon irqbalance
    • Antes de hacer ajustes manuales, se debe detener irqbalance
    • /proc/irq/<IRQ_NUMBER>/smp_affinity almacena una máscara de bits en hexadecimal que representa los núcleos de CPU
    • En un servidor de 4 núcleos, el valor predeterminado f significa que la IRQ puede procesarse en cualquier CPU
    • echo 1 > /proc/irq/32/smp_affinity hace que solo se use CPU0
    • En sistemas con más de 32 núcleos, se separan grupos de 32 bits con comas
    • La IRQ affinity solo puede mejorar el rendimiento en configuraciones muy específicas y con cargas de trabajo predefinidas, y puede ser un arma de doble filo
  • RSS

    • En NIC rápidos, si los paquetes se reciben con una sola cola y una sola CPU, un único núcleo puede terminar asumiendo toda la responsabilidad del procesamiento de datos mientras los demás quedan inactivos
    • RSS (Receive-side scaling) es una tecnología del NIC que distribuye el tráfico entre varias colas de recepción y transmisión
    • El NIC calcula un hash basado en la IP de origen/destino y en los puertos de origen/destino TCP/UDP, asigna los paquetes del mismo flujo a una sola cola y distribuye los flujos de forma uniforme entre las colas
    • RSS ofrece las ventajas del procesamiento de recepción en paralelo en entornos de multiprocesamiento
    • Según la documentación del kernel de Linux, RSS debe activarse cuando la latencia es importante o cuando el procesamiento de interrupciones de recepción es un cuello de botella, y en redes de baja latencia es óptimo asignar tantas colas como CPUs tenga el sistema
  • RPS, RFS, aRFS

    • RPS (Receive Packet Steering) es casi una implementación por software de RSS
    • Mientras que RSS elige la cola y la CPU que ejecutarán el manejador de interrupciones de hardware, RPS elige la CPU que realizará el procesamiento del protocolo por encima del manejador de interrupciones
    • Requiere CONFIG_RPS y viene activado por defecto en SMP
    • La configuración se hace con el bitmap de CPU en /sys/class/net/<dev>/queues/rx-<n>/rps_cpus
    • Si hay RSS, puede ser innecesario, pero puede ser útil cuando hay más CPUs que colas
    • RFS (Receive Flow Steering) amplía RPS hasta la localidad de la aplicación
    • RPS distribuye paquetes según el flujo, pero no considera en qué CPU se está ejecutando la aplicación en espacio de usuario
    • RFS mantiene rps_sock_flow_table, una tabla global de flujo a CPU
    • El tamaño de la tabla puede ajustarse con net.core.rps_sock_flow_entries
    • La rps_dev_flow_table por cola se usa para reducir problemas de desorden en el orden de los paquetes restantes cuando el scheduler mueve la aplicación a una nueva CPU
    • aRFS (Accelerated RFS) es un mecanismo de balanceo de carga con aceleración por hardware para RFS
    • Envía los paquetes directamente a la CPU más cercana al hilo que consume los datos, por lo que puede ofrecer mejor rendimiento que RFS
    • Requiere ndo_rx_flow_steer, filtrado ntuple y CONFIG_RFS_ACCEL del NIC
    • El mapeo entre CPU y colas se deriva automáticamente de la IRQ affinity de cada cola de recepción, por lo que no se necesita configuración adicional

ajuste de softIRQ, qdisc y buffers TCP

  • presupuesto de softIRQ

    • La rutina de polling de NAPI está limitada por netdev_budget_usecs, netdev_budget y dev_weight para evitar que softIRQ monopolice la CPU
    • El valor predeterminado de net.core.netdev_budget es 300, lo que significa que el proceso softIRQ vacía 300 mensajes desde la NIC antes de ceder la CPU
    • net.core.netdev_budget_usecs es la cantidad máxima de microsegundos de un ciclo de polling de NAPI
    • net.core.dev_weight es la cantidad máxima de paquetes por CPU que el kernel puede procesar en una interrupción NAPI
    • Si en /proc/net/softnet_stat aumentan columnas distintas de la 1.ª, puede ser necesario cambiar el budget, aunque aumentos pequeños pueden ser normales
  • qdisc de ingress y netdev_max_backlog

    • netdev_max_backlog es una cola interna del kernel donde se almacena el tráfico recibido desde la NIC antes de que lo procese la pila de protocolos como IP/TCP
    • Hay una backlog queue por cada núcleo de CPU
    • Si la interfaz recibe paquetes más rápido de lo que el kernel puede procesar, la cola del lado INPUT se llena hasta netdev_max_backlog y, si se excede, se descartan paquetes
    • El valor predeterminado es 1000, y puede no ser suficiente para varias interfaces de 1Gbps o una sola interfaz de 10Gbps
    • La 2.ª columna de /proc/net/softnet_stat es un contador que aumenta por overflow de la backlog queue
    • El valor se cambia con sysctl -w net.core.netdev_max_backlog <value>
  • qdisc de egress, txqueuelen, default_qdisc

    • txqueuelen configura la cantidad de paquetes permitidos en la cola de transmisión del kernel del dispositivo de interfaz de red
    • El valor predeterminado puede ser 1000 según el driver de la interfaz
    • Se cambia con ifconfig <interface> txqueuelen value, y en ip -s link se revisan RX/TX dropped
    • default_qdisc es la queuing discipline predeterminada que se usará en los dispositivos de red
    • En lugar de pfifo_fast, se pueden indicar alternativas como sfq, codel y fq_codel
    • En tc -s qdisc ls dev <interface> se revisan métricas como dropped, overlimits y requeues
  • buffers TCP de lectura/escritura y cola de conexiones

    • tcp_rmem y tcp_wmem definen respectivamente el valor mínimo, el valor predeterminado y el valor máximo de los buffers TCP de recepción y envío
    • El cambio se realiza así
      • sysctl -w net.ipv4.tcp_rmem="min default max"
      • sysctl -w net.ipv4.tcp_wmem="min default max"
    • El estado de uso de los buffers se consulta con /proc/net/sockstat
    • La accept queue y la SYN queue están afectadas por net.core.somaxconn y net.ipv4.tcp_max_syn_backlog
    • net.core.somaxconn es el límite superior del parámetro backlog de listen(), y si se cambia este valor, la aplicación también debe ajustarse a un valor compatible
    • net.ipv4.tcp_syncookies activa o desactiva las SYN cookies, útiles para protegerse contra ataques SYN flood
    • net.ipv4.tcp_congestion_control configura el algoritmo de congestion control que se usará en nuevas conexiones

NUMA y rendimiento de red

  • NUMA (Non-uniform memory access) es una arquitectura de memoria en la que el procesador puede acceder más rápido a la memoria local que a la memoria no local
  • En el procesamiento de red, como la CPU debe acceder a la memoria del ring buffer, la localidad NUMA puede afectar el rendimiento de red
  • NUMA divide CPU, memoria y dispositivos en varios nodos, y funciona como varias computadoras pequeñas con interconnect rápida y un sistema operativo común
  • En sistemas NUMA, el objetivo del tuning es concentrar las interrupciones de un dispositivo en los núcleos de CPU del único nodo al que pertenece ese dispositivo
  • Sin embargo, los sistemas NUMA pueden interactuar mal con aplicaciones en tiempo real y generar latencias inesperadas en eventos
  • Los nodos NUMA se revisan en /sys/devices/system/node/node*
  • La localidad del dispositivo se revisa en /sys/class/net/<interface>/device/numa_node
    • -1 indica que la plataforma de hardware no es realmente NUMA, o que el kernel está emulando NUMA, o que el dispositivo no tiene localidad NUMA
  • El kernel de Linux soporta NUMA desde la versión 2.5, y las distribuciones basadas en RedHat y Debian ofrecen numactl y numad
  • numad monitorea la topología del sistema y el uso de recursos, e intenta ubicar procesos con suficiente carga de memoria y CPU en una localidad NUMA eficiente

Opciones para un procesamiento de paquetes más rápido

  • AF_PACKET v4 y PACKET_MMAP

    • AF_PACKET v4 es una interfaz rápida de paquetes de Linux que elimina las system calls de la ruta de datos y usa copy-mode de forma predeterminada
    • Con PACKET_ZEROCOPY se puede usar el modo true zero-copy, que mapea el DMA packet buffer al espacio de usuario
    • La ruta típica de file read seguido de socket send requiere cambios de contexto entre user mode y kernel mode, además de múltiples copias de datos
    • zero-copy mejora el rendimiento al eliminar copias de datos redundantes
    • PACKET_MMAP es una API de Linux para packet sniffing rápido
    • Proporciona un ring buffer mmapped compartido entre el espacio de usuario y el kernel
    • Reduce las system calls y las copias entre espacio de usuario y kernel en los paquetes de envío y recepción
  • DPDK

    • DPDK (Data Plane Development Kit) es un framework de bibliotecas en espacio de usuario y drivers para procesamiento rápido de paquetes
    • Su objetivo es intercambiar paquetes de red a native speed entre la NIC y las aplicaciones de usuario
    • Está orientado a NIC de 10Gb o 40Gb, donde la velocidad es el criterio más importante
    • Se enfoca en el forwarding de paquetes, no en la pila de red
    • Cuando DPDK controla la NIC, todo el tráfico evita el kernel y esa NIC deja de ser visible para el kernel
    • Los puertos se desvinculan del driver del kernel de Linux y quedan gestionados por controladores como vfio_pci, igb_uio y uio_pci_generic
    • Después, la comunicación entre la aplicación y la NIC queda a cargo de DPDK PMD
    • DPDK requiere configurar hugepages para asignar grandes chunks de memoria
    • Componentes principales:
      • EAL: interfaz genérica que oculta las diferencias de entorno
      • librte_ring: API FIFO lockless de múltiples productores y múltiples consumidores
      • librte_mempool: asignación de pools de objetos de memoria
      • librte_mbuf: creación y manipulación de buffers que contienen paquetes de red
      • librte_timer: servicio de temporizadores para ejecutar funciones asíncronas
      • PMD: driver en el que la CPU hace polling continuo de la NIC en lugar de usar interrupciones
    • Limitaciones:
      • Tiene una fuerte dependencia del hardware
      • Requiere dedicar cores de CPU para ejecutar PMD y usa 100% de CPU
  • PF_RING

    • PF_RING es un módulo del kernel de Linux y un framework de user space para procesar paquetes a alta velocidad y ofrecer una API consistente a las aplicaciones de procesamiento de paquetes
    • PF_RING hace polling de los paquetes de la NIC usando Linux NAPI
    • NAPI copia los paquetes desde la NIC al circular buffer de PF_RING, y la aplicación en espacio de usuario lee los paquetes desde el ring
    • Esta estructura tiene dos pollers, la aplicación y NAPI, por lo que el polling consume ciclos de CPU
    • Su ventaja es que puede distribuir simultáneamente los paquetes entrantes en varios rings
    • Gracias a su estructura modular, se pueden usar componentes adicionales como ZC module, FPGA-based card module, Stack module, Timeline module y Sysdig module
    • PF_RING redujo el costo de packet capture y userland forwarding, pero tiene límites de rendimiento máximo por su estructura de dos actores, donde el kernel copia de la NIC al ring y userland lee del ring para procesar
    • PF_RING incluye soporte para adaptador AF_XDP desde la versión 7.5
  • XDP y AF_XDP

    • XDP (eXpress Data Path) es una implementación de eBPF que intercepta paquetes en una etapa temprana de la ruta de datos de red de Linux
    • XDP procesa directamente la página del paquete RX dentro de la función RX del device driver, antes de la asignación de SKB
    • eBPF es bytecode sandboxed definido por el usuario que se ejecuta en el kernel
    • Usa 11 registros de 64 bits y una pila de 512 bytes
    • Puede compilarse a eBPF desde C, Lua, Go, P4, Rust y otros lenguajes mediante el backend de LLVM
    • Ofrece verifier y JIT compiler dentro del kernel, y soporta funciones como map, tail call y helper
    • Casos de uso de XDP:
      • pre-stack filtering para mitigación de DoS
      • forwarding y load balancing
      • técnicas de batching como GRO
      • flow sampling y monitoring
      • procesamiento ULP
    • XDP no es kernel bypass, sino un fast path dentro de la pila del kernel, y no reemplaza la pila TCP/IP
    • No requiere hardware dedicado, pero sí requisitos como NIC multi-queue, TX/RX checksum offload, RSS y TSO
    • Ventajas de XDP frente a DPDK:
      • se puede elegir entre busy polling o networking basado en interrupciones
      • no requiere huge pages
      • no tiene requisitos de hardware especiales
      • no es obligatorio dedicar CPUs exclusivas
      • no hace falta reinyectar paquetes al kernel desde aplicaciones userspace de terceros
      • no requiere un nuevo modelo de seguridad para acceder al hardware de red
      • no requiere código/licenciamiento de terceros
    • AF_XDP es un nuevo tipo de socket introducido en Linux 4.18
    • Sin evitar por completo el kernel, permite construir una estructura similar a DPDK o AF_PACKET aprovechando funciones del kernel
    • Un programa XDP puede redirigir frames mediante eBPF a un memory buffer en espacio de usuario
    • La transferencia DMA usa memoria de espacio de usuario para soportar zero-copy
    • Puede lograr mejoras de rendimiento de 3 a 20 veces frente a AF_PACKET
    • Limitaciones:
      • es un proyecto relativamente joven
      • para soporte completo se requiere Linux kernel 5.4 o superior

1 comentarios

 
GN⁺ 2024-07-29
Opiniones en Hacker News
  • Me habría resultado muy útil si lo hubiera visto hace apenas unas semanas.
    Quería hacer cifrado de enlaces L2 entre centros de datos y pedí cotizaciones de appliances de hardware a varios proveedores, pero me parecieron demasiado caros, así que intenté hacerlo por mi cuenta.
    Con hardware de propósito general configuré Ethernet frames sobre una red superpuesta de WireGuard para alcanzar 10Gbps y, tras unos diez días de trabajo, lo implementé por alrededor de un 70% menos que la propuesta más barata y cerca de un 95% menos que la más cara, aunque hizo falta leer mucha documentación detallada y experimentar bastante.
    Quiero usar el contenido de este artículo para validar si mi comprensión es correcta y, a simple vista, parece prometedor y bastante completo.

    • Me da curiosidad: ¿para qué caso de uso era que un túnel L3 no alcanzaba?
    • Si puedes compartir el código, me gustaría verlo. Me intriga mucho cómo hiciste esa implementación.
  • Si hay tantos valores ajustables, me pregunto si no valdría la pena crear software de ajuste automático.
    Parece viable un enfoque parecido al descenso de gradiente: elegir al azar un parámetro de una lista permitida, subirlo o bajarlo un poco dentro del rango permitido, medir el rendimiento durante un tiempo y revertirlo si empeora, o seguir ajustándolo si mejora.

  • Es interesante, pero como ingeniero de software casi no tengo oportunidad de ejecutar en la práctica los comandos que aparecen en el artículo.
    La mayoría de los sistemas corren en contenedores que son versiones reducidas de algún Linux, no tengo acceso por shell a los sistemas de producción, y los entornos de desarrollo o QA difieren tanto de producción en aspectos como la carga que reproducir bugs normalmente no ayuda mucho.
    Al final, la oportunidad de ejecutar los comandos del artículo se reduce a cuando toco mis sistemas personales, y parece algo útil si trabajas como ingeniero de plataforma.

    • Es muy probable que la mayoría de las funciones de bajo nivel de todos modos no funcionen o no sirvan. La implementación de interfaces de red en contenedores normalmente te hace lidiar con pares veth, porque hace todo tipo de procesamientos raros en espacio de usuario.
      Una de las cosas que no me gustan mucho de Kubernetes es su modelo de networking. Asume que solo hay una tarjeta de red y que las aplicaciones son lo bastante simples como para no necesitar conocer las capas inferiores.
      Todo el modelo de networking parece tener bastante margen para una gran revisión al estilo de la década de 2020, con el fin de simplificarlo y mejorarlo.
    • Si tienes un entorno de staging lo más parecido posible a producción, puede ayudar según el caso, porque puedes experimentar y analizar en un entorno similar a producción al que sí tienes acceso.
  • Se dice que net.core.wmem_max es el límite superior del tamaño del buffer de envío TCP, y también existe net.ipv4.tcp_wmem, así que tengo dos dudas:

    1. por qué no hay un valor equivalente para IPv6; 2. en qué se diferencia de net.core.wmem_max.
    • net.core.wmem_max es, tal como indica su nombre, el valor máximo.
      net.ipv4.tcp_wmem es una terna con tres valores —mínimo, predeterminado y máximo—, y el máximo que se especifica ahí no puede superar el net.core.wmem_max anterior.
      TCP debería ser el mismo protocolo tanto si se transporta sobre IPv4 como sobre IPv6.
      Ej.: https://docs.redhat.com/en/documentation/red_hat_data_grid/7...
  • Lo que falta un poco aquí es la depuración y el ajuste para throughput superior a 100Gbps.
    Cuando sirves HTTP a esa escala, normalmente el primer cuello de botella es el ancho de banda de memoria, por lo que muchas veces terminas necesitando kTLS.
    Herramientas como AMD μProf son muy útiles para depurar, y el profiling continuo basado en eBPF también ayuda a entender exactamente qué ocurre en el kernel y en espacio de usuario.

  • Se ve bastante genial. En mi carrera hasta ahora, cada vez que necesitaba rendimiento, normalmente empecé por bypass del kernel.