Conocimiento de NUMA y fijación de CPU para servidores dedicados

16 min de lectura - 16 de junio de 2026

hero section cover
Tabla de contenidos
  • Conocimiento de NUMA y asignación de CPU para servidores dedicados
  • Cómo funciona NUMA en servidores de múltiples sockets
  • Inspección de la topología NUMA en Linux
  • Fijación de CPU y políticas de memoria
  • Elegir una estrategia en función de la carga de trabajo
  • Configuración del BIOS y del kernel que hay que comprobar
Compartir

Cómo inspeccionar la topología NUMA y asignar las cargas de trabajo de Linux a los núcleos y la memoria adecuados. Abarca numactl, taskset, systemd, la configuración de la BIOS y estrategias específicas para cada carga de trabajo.

Conocimiento de NUMA y asignación de CPU para servidores dedicados

En cualquier servidor multisocket, dónde se ejecuta un proceso y dónde reside su memoria son dos cuestiones diferentes, y desincronizarlas es una de las formas más fáciles de perder rendimiento. La gestión de NUMA y la asignación de CPU son las dos herramientas que solucionan esto. Esta entrada explica cómo funciona NUMA, cómo inspeccionarlo en Linux y cómo asignar correctamente las cargas de trabajo para bases de datos, entrenamiento de IA y servicios sensibles a la latencia.

Cómo funciona NUMA en servidores de múltiples sockets

Un nodo NUMA (acceso a memoria no uniforme) es un grupo de núcleos de CPU vinculados a un bloque local de RAM a través de un controlador de memoria dedicado. En un servidor de dos sockets suele haber dos nodos. Cualquier núcleo puede leer cualquier dirección, pero el acceso local es de aproximadamente 80 ns, mientras que un salto entre sockets a través de la UPI de Intel o la Infinity Fabric de AMD es de unos 130–150 ns. En sistemas más grandes con más sockets, el nodo en el peor de los casos puede superar los 250 ns.

El ancho de banda sigue el mismo patrón. Un sistema Sapphire Rapids de dos zócalos puede mantener unos 600 GB/s cuando los núcleos acceden a la memoria local, pero el enlace entre zócalos es una fracción de eso, por lo que el tráfico que lo atraviesa se satura rápidamente. Los procesadores de muchos núcleos hacen que esto sea más granular: el Sub-NUMA Clustering (SNC) de Intel y el Nodes Per Socket (NPS) de AMD dividen cada zócalo en múltiples dominios NUMA, por lo que una caja de «dos zócalos» puede presentar fácilmente cuatro u ocho nodos a Linux.

Sin reconocimiento NUMA, el programador de Linux migrará sin problemas un subproceso entre sockets mientras su conjunto de trabajo permanece en el nodo original. Cada acceso posterior se convierte en uno remoto. El síntoma visible es una alta utilización de la CPU con un rendimiento real bajo, ya que los núcleos pasan su tiempo esperando a la memoria. Los dispositivos de E/S empeoran esto. Una GPU o una NIC está conectada a una raíz PCIe específica, que pertenece a un nodo NUMA. Si el proceso que la alimenta se ejecuta en el otro zócalo, cada transferencia DMA cruza la interconexión.

Inspección de la topología NUMA en Linux

Cuatro herramientas cubren casi todo lo que necesitas:

  • lscpu para obtener un resumen rápido de sockets y nodos.
  • numactl --hardware para los totales de memoria de los nodos y la matriz de distancias entre nodos.
  • numastat para contadores de aciertos/fallos por proceso.
  • lstopo (de hwloc) para la jerarquía de caché y la localidad de los dispositivos PCIe.

Empieza con numactl --hardware. Enumera cada nodo, los núcleos y la memoria que le pertenecen, y la matriz de distancias. Un valor de 10 es local, 20+ es remoto. Si ves un solo nodo en un equipo con varios sockets, tu BIOS tiene habilitado el entrelazado de nodos y está ocultando la topología; soluciona eso primero (ver más abajo).

Para un proceso específico, numastat -p <PID> desglosa dónde se asigna realmente su memoria. Hay cuatro contadores importantes:

  • numa_hit: memoria asignada en el nodo previsto. Es deseable que este valor sea alto.
  • numa_miss: el nodo previsto estaba lleno, la asignación se desbordó a otro lugar.
  • numa_foreign: otro nodo intentó asignar memoria localmente y no pudo, lo que indica presión de memoria.
  • other_node: páginas asignadas en un nodo distinto al que ejecuta el proceso. Los valores altos aquí son el clásico indicio de una mala fijación.

Para cargas de trabajo de GPU o NIC, ejecuta lstopo-no-graphics y compruebe a qué nodo NUMA está conectado cada dispositivo PCIe. Si los núcleos que controlan el dispositivo se encuentran en el otro nodo, eso es lo primero que hay que solucionar.

Fijación de CPU y políticas de memoria

La fijación de CPU (o afinidad de CPU) vincula un proceso a núcleos específicos para que el programador no pueda migrarlo. Por sí solo, eso no es suficiente, ya que Linux utiliza una política de memoria de primer contacto de forma predeterminada: las páginas se asignan en el nodo que las escribe primero. Si un subproceso se inicia en el nodo equivocado antes de ser fijado, su memoria permanece allí. Es necesario controlar tanto la ubicación como la asignación de forma conjunta.

Hay tres herramientas que cubren los casos más comunes:

HerramientaControlesSe utiliza para
tasksetSolo núcleos de CPUEnlace rápido y puntual de un proceso existente
numactlNúcleos de CPU y memoriaInicio de cargas de trabajo con localidad estricta
systemdNúcleos de CPU y memoria, persistenteServicios que necesitan fijación entre reinicios

numactl admite cuatro políticas de memoria:

  • --membind=N: asignar solo en el nodo N; si está lleno, fallar.
  • --preferred=N: dar preferencia al nodo N, recurrir a otros si es necesario.
  • --interleave=all: rotación entre nodos para una distribución uniforme del ancho de banda.
  • --localalloc: asignar en el nodo en el que se encuentre la CPU en ejecución.

Fijar una carga de trabajo a un nodo

En primer lugar, identifica qué núcleos pertenecen a tu nodo de destino:

numactl --hardware

A continuación, inicie la aplicación vinculada a ese nodo tanto para los núcleos como para la memoria:

numactl --cpunodebind=0 --membind=0 ./your_application

Para un proceso que ya se está ejecutando, ajuste la afinidad de la CPU con taskset:

taskset -cp 0-7 <PID>

Para que se mantenga tras un reinicio, configúrela en la unidad systemd:

[Service]
CPUAffinity=0-7
NUMAPolicy=bind
NUMAMask=0

Vuelve a cargar y reinicia:

sudo systemctl daemon-reload && sudo systemctl restart <service>

Cuando realices la asignación manualmente, desactiva el equilibrador automático del kernel para que no interfiera con tu asignación:

sysctl -w kernel.numa_balancing=0

Añádelo a /etc/sysctl.conf para que sea permanente. A continuación, compruébalo con numastat -p <PID> durante un par de minutos de carga de trabajo real. Si other_node se mantiene cerca de cero, la asignación está surtiendo efecto.

Elegir una estrategia en función de la carga de trabajo

La política adecuada depende de si su carga de trabajo se beneficia más de una baja latencia o del ancho de banda agregado en todos los nodos.

Carga de trabajoPolíticaPor qué
Bases de datos (PostgreSQL, MySQL, SQL Server)--cpunodebind + --membindBúferes compartidos de gran tamaño, rutas de consulta sensibles a la latencia
Caché en memoria (Redis, Memcached)Enlace de un solo nodoTodo es acceso a la RAM, la latencia remota se nota de inmediato
Entrenamiento e inferencia de IA/MLEnlace al nodo NUMA de la GPUEvita que las transferencias de tensores crucen las raíces PCIe
Análisis (Spark, Elasticsearch)--interleave=allLos conjuntos de trabajo grandes necesitan ancho de banda en todos los nodos
API sensibles a la latencia, operaciones bursátilesAfinidad estricta de pines + IRQLa previsibilidad es más importante que el rendimiento máximo
Alto consumo de red (RoCEv2, InfiniBand)Pin al nodo NUMA de la NIC, núcleos dedicados para IRQMantiene el procesamiento de interrupciones a nivel local y alejado de los subprocesos de las aplicaciones

Para cargas de trabajo de GPU específicamente, ejecuta lstopo para averiguar en qué nodo NUMA se encuentra la GPU y, a continuación, inicie el proceso de entrenamiento o inferencia con numactl --cpunodebind=N --membind=N para ese mismo N. Esta es una de las mejoras más fáciles de conseguir en un servidor GPU de múltiples sockets, ya que la ubicación predeterminada del programador suele ser errónea.

Para cargas de trabajo HPC y MPI que abarcan ambos sockets, fija cada rango a un único nodo con localalloc en lugar de intercalarlo todo. Cada rango obtiene memoria local y el paralelismo se produce a nivel de rango.

Una nota práctica: si asignas un rango a un único nodo, deja entre 2 y 4 GB de margen en él. Un nodo que se utilice casi al máximo activa la recuperación de memoria, lo que te cuesta la latencia que intentabas ahorrar.

Configuración del BIOS y del kernel que hay que comprobar

La precisión de los resultados de la herramienta depende de la topología que exponga el firmware. Algunos ajustes que hay que confirmar:

  • Intercalación de nodos: desactivarla. Cuando está activada, la BIOS presenta toda la memoria como un único conjunto plano y oculta NUMA por completo al sistema operativo. numactl --hardware Mostrará un solo nodo en un equipo con varios sockets si este es el caso.
  • Agrupación Sub-NUMA (Intel) o Nodos por socket (AMD): actívela en procesadores de muchos núcleos cuando desee una localización más precisa. Confírmelo lscpu después de reiniciar.
  • vm.zone_reclaim_mode: configúralo en 0 para la mayoría de los servidores de producción. Un valor distinto de cero recupera agresivamente la memoria local en lugar de asignarla de forma remota, lo que puede expulsar caché de páginas útil.
  • kernel.numa_balancing: déjelo activado para cargas de trabajo de uso general; desactívelo cuando realice la fijación manualmente. El equilibrador automático migrará páginas y subprocesos de formas que entren en conflicto con su política.

Si está ejecutando el ajuste NUMA en hardware físico donde controla la BIOS, los parámetros del kernel y la afinidad de IRQ, puede aplicar todo lo anterior sin tener que sortear las abstracciones del hipervisor. Esa es la razón principal por la que este tipo de trabajo es más fácil en hardware dedicado que en máquinas virtuales en la nube.

Para servidores dedicados multisocket con acceso root completo, consulta los servidores dedicados de FDC.

Blog

Destacados de la semana

Más artículos
Perfiles ajustados para la optimización de la carga de trabajo de servidores Linux

Perfiles ajustados para la optimización de la carga de trabajo de servidores Linux

Cómo elegir, aplicar y personalizar perfiles ajustados para GPU, bases de datos y servidores Linux de gran ancho de banda, con ejemplos y consejos de implementación de Ansible.

16 min de lectura - 9 de junio de 2026

Linux OOM Killer Tuning for VPS: Una Guía Práctica

12 min de lectura - 8 de junio de 2026

Más artículos