Sockets como estrategia: por qué las plataformas importan más que las CPU ahora

¿Te fue útil?

Alguien te paginará a las 2:13 a.m. porque “la CPU solo está al 35%” y, sin embargo, la API está agotando tiempos, la base de datos está “lentamente aleatoria” y las latencias de almacenamiento parecen un sismógrafo. Mirarás paneles que juran que todo está bien, mientras los clientes juran que no lo está.

Esta es la trampa moderna del rendimiento: seguimos comprando servidores como si fuera un concurso de belleza de CPU, pero la mayoría de las interrupciones y degradaciones en producción son problemas de plataforma: sockets, canales de memoria, carriles PCIe, topología NUMA y cómo el I/O llega realmente al silicio.

La verdad incómoda: la plataforma es el ordenador

Nos gusta hablar de las CPU porque sus especificaciones son ordenadas: número de núcleos, GHz, tamaños de caché. Las plataformas son desordenadas: número de sockets, dominios NUMA, canales de memoria, generación y reglas de población de DDR, generación y enrutamiento de PCIe, ajustes de BIOS, firmware, IOMMUs, enrutamiento de interrupciones y un zoológico cada vez mayor de aceleradores.

En 2026, la propia CPU rara vez es el reactivo limitante. El cuello de botella del sistema está en los caminos entre la CPU y todo lo demás:

  • Ancho de banda y latencia de memoria (canales, ranks, velocidad y si tus hilos se ejecutan “cerca” de su memoria).
  • Topología de I/O (carriles PCIe, switches, bifurcación, dónde aterrizan NVMe y NICs y cómo comparten uplinks).
  • Interconexión entre sockets (penalizaciones por acceso remoto a memoria y tráfico de coherencia de caché entre sockets).
  • Colocación de interrupciones y colas (paquetes y completions aterrizando en los núcleos equivocados).
  • Potencia y térmica (comportamiento de boost, frecuencias sostenidas y la diferencia entre el TDP de marketing y la realidad).

Comprar “más CPU” puede ser como añadir más cajas registradoras cuando la entrada de la tienda es una puerta estrecha. Puedes contratar todos los cajeros que quieras; los clientes siguen sin poder entrar.

Aquí está el cambio de estrategia: los sockets ya no son solo unidades de cómputo; son decisiones de topología de I/O y memoria. Tu plataforma define la forma de tus cuellos de botella antes de que tu software ejecute una sola instrucción.

Una cita para pegar en una nota

Idea parafraseada (John Ousterhout): “Un sistema es rápido cuando eliminas un gran cuello de botella; muchas pequeñas optimizaciones no importan mucho.”

Ese es todo el juego. Encuentra el gran cuello de botella. Y hoy, ese cuello de botella suele ser la topología de la plataforma, no el rendimiento de instrucciones.

Hechos e historia interesantes que explican el desorden

Algunos puntos de contexto que hacen que “sockets como estrategia” suene menos a conspiración y más a física y economía:

  1. El “Northbridge” solía ser un chip separado. Los controladores de memoria y los root complexes PCIe vivían fuera de la CPU; podías colapsar un servidor entero en un solo enlace del chipset compartido.
  2. Los controladores de memoria integrados lo cambiaron todo. Cuando la memoria se movió al paquete de la CPU, el rendimiento de memoria quedó profundamente ligado a la elección de socket y las reglas de población de DIMM.
  3. NUMA ha sido “real” durante décadas. Los servidores multi-socket siempre han tenido acceso no uniforme a la memoria, pero la penalización se hizo más visible a medida que aumentaron los núcleos y las cargas de trabajo se paralelizaron.
  4. PCIe reemplazó buses compartidos por una razón. La industria abandonó buses paralelos compartidos porque la concurrencia exigía enlaces punto a punto y lanes escalables.
  5. La virtualización convirtió la topología en política de software. Los hypervisors pueden ocultar o exponer NUMA, fijar vCPUs y colocar memoria—a veces brillantemente, a veces desastrosamente.
  6. NVMe convirtió el almacenamiento en “adyacente a la CPU”. El I/O de almacenamiento se movió de colas HBA y firmware a dispositivos PCIe directos con colas profundas, presionando interrupciones, caché y ancho de banda de memoria.
  7. RDMA y redes con bypass de kernel hicieron que la NIC sea parte de la plataforma. Cuando la pila de red se mueve a espacio de usuario o la NIC ofrece offloads, la colocación de colas y la localidad PCIe se convierten en características de rendimiento.
  8. Los modelos de licenciamiento armamentizaron los sockets. Algunos softwares empresariales cobran por socket, por núcleo o por “unidad de capacidad”, haciendo que las decisiones de plataforma sean estratégicas financieramente, no solo técnicas.
  9. Las mitigaciones de seguridad cambiaron el perfil de costo de cierto trabajo de CPU. Bajo ciertas cargas, las llamadas al sistema y los cambios de contexto se encarecieron, aumentando la importancia relativa de minimizar el overhead de I/O y el tráfico entre NUMA.

Esto no es trivia. Explican por qué “simplemente compra una CPU más rápida” es cada vez menos la palanca correcta.

Qué te aporta (y te cuesta) un “socket”

El recuento de sockets es una decisión de topología

Un socket es un paquete físico de CPU, sí. Pero operativamente también es un conjunto de controladores de memoria, root complexes PCIe y endpoints de fabric. Añadir un segundo socket puede añadir más capacidad y ancho de banda de memoria, y más conectividad I/O—dependiendo de la plataforma. También añade la posibilidad de acceso remoto a memoria y overhead de coordinación entre sockets.

En un sistema de un solo socket, la ruta feliz es simple:

  • Toda la memoria es “local”.
  • La mayoría de dispositivos PCIe están a un salto de distancia.
  • Los errores del planificador se penalizan menos.

En un sistema de doble socket, tienes que ganarte el rendimiento:

  • Tus hilos deberían ejecutarse en el socket que posee sus asignaciones de memoria.
  • Tu NIC y tus NVMe deberían estar en el mismo socket que los núcleos más ocupados que las gestionan.
  • Tu carga debe escalar limpiamente entre nodos NUMA o estar fijada y aislada.

Realidad seca: mucho software no “escala entre sockets”. Escala entre núcleos hasta que el tráfico entre sockets se convierte en el impuesto que no presupuestaste.

Canales de memoria: el gobernador silencioso del rendimiento

El recuento de núcleos vende servidores. Los canales de memoria los alimentan.

Una plataforma con más canales de memoria por socket puede alimentar más núcleos antes de que se queden sin datos. En cargas intensivas en memoria (analítica, capas de caché, algunas bases de datos, montones JVM bajo presión, índices grandes en memoria), el ancho de banda de memoria suele ser el techo. Puedes comprar una CPU con más núcleos y ver que el rendimiento se estanca porque los núcleos esperan por memoria.

Poblar DIMMs de forma incorrecta puede hacerte perder ancho de banda. Muchas plataformas necesitan población balanceada entre canales. Mezclar velocidades o ranks puede hacer que todo el conjunto reduzca la frecuencia. Por eso la selección de plataforma incluye preguntas “aburridas” como: cuántos canales, qué tipos de DIMM y qué reglas de población.

Carriles PCIe: el presupuesto de I/O que no puedes exceder

Cada unidad NVMe, NIC, GPU, DPU y HBA consume carriles PCIe y/o comparte uplinks detrás de switches. Tu plataforma podría tener espacio físico para ocho NVMe, pero eléctricamente pueden compartir menos uplinks de lo que asumes.

Esta es una sorpresa común en producción: el servidor tiene bahías suficientes, pero no suficientes lanes. Entonces aprendes lo que realmente significa “x4 al backplane vía un uplink del switch” en pico.

Broma 1/2: planificar carriles PCIe es como organizar un armario—lo ignoras el tiempo suficiente y acabarás de pie en la oscuridad sosteniendo cables que no recuerdas haber comprado.

NUMA: no es un error, es un impuesto de la realidad

NUMA no es una característica que activas. Es lo que ocurre cuando la memoria está físicamente más cerca de algunos núcleos que de otros.

Las penalizaciones NUMA aparecen como:

  • Latencias en la cola más altas cuando un hilo caliente toca memoria remota.
  • Menor rendimiento cuando cachés e interconexión se saturan.
  • Gráficas de “pero la CPU no está ocupada” porque los núcleos están en espera, no programados.

Para las pilas de almacenamiento y red, NUMA interactúa con interrupciones, DMA y colocación de colas. Una NIC en el socket 0 que entrega interrupciones a núcleos en el socket 1 es una regresión de rendimiento que no puedes parchear con optimismo.

Sockets como estrategia corporativa (sí, en serio)

En entornos corporativos, los sockets también son:

  • perillas de licenciamiento (licencias por socket incentivan menos sockets más grandes; por núcleo incentivan otra elección).
  • perillas operativas (menos sockets simplifica la planificación de capacidad y reduce la variación “aleatoria” de rendimiento por NUMA).
  • perillas de riesgo (madurez de la plataforma, estabilidad del firmware y cadena de suministro para piezas de reemplazo).

Cuando estandarizas en una plataforma, te comprometes con sus rarezas: valores por defecto del BIOS, exposición NUMA, mapeo PCIe y ritmo de actualizaciones de firmware. Ese compromiso dura más que cualquier generación de CPU.

Modos de fallo: cómo las plataformas crean “lentitud misteriosa”

1) La mentira de “la CPU está inactiva”: núcleos bloqueados y esperas ocultas

La utilización de CPU mide tiempo programado, no progreso útil. Un núcleo puede estar “ocupado” o “inactivo” mientras tu carga espera por memoria, I/O, locks o acceso NUMA remoto. Las plataformas influyen en estas esperas:

  • El acceso remoto a memoria aumenta la latencia de carga y el overhead de coherencia.
  • El ancho de banda de memoria insuficiente crea stalls en muchos núcleos simultáneamente.
  • La contención de PCIe incrementa la latencia de completado de I/O y eleva la latencia en cola.

2) Dispositivos I/O peleando por el mismo root complex

Si tu NIC y tus dispositivos NVMe están detrás del mismo uplink de switch PCIe, comparten ancho de banda y pueden contender en las colas de completions. Esto se hace visible cuando los patrones de tráfico coinciden: grandes ráfagas de replicación más lecturas NVMe intensas; ventanas de backup más picos de ingestión; un nodo Kubernetes haciendo todo a la vez porque “tiene núcleos”.

3) Tormentas de interrupciones en los núcleos equivocados

La red y NVMe dependen de interrupciones y/o polling. Si las interrupciones aterrizan en un pequeño conjunto de núcleos, o peor, en núcleos lejos del nodo NUMA del dispositivo, obtienes:

  • Alta actividad de softirq o ksoftirqd.
  • Pérdida de paquetes y retransmisiones bajo carga.
  • Aumento de latencia sin “obvia saturación de CPU”.

4) Fallos de escalado en doble socket que parecen errores de aplicación

Algunas cargas escalan de 1 a N núcleos bien dentro de un socket y luego se topan con un muro entre sockets. Síntomas:

  • El rendimiento se estanca en aproximadamente “lo que rinde un socket”.
  • La latencia en cola empeora al añadir hilos.
  • Las métricas de contención de locks suben, pero los locks no son la causa real—es el rebote de líneas de caché remoto.

5) Ampliaciones de capacidad de memoria que silenciosamente reducen el rendimiento

Añadir DIMMs puede forzar velocidades más bajas o modos de intercalado distintos. Esto no es teoría; es una regresión común en producción. Las ampliaciones de memoria deben tratarse como cambios de rendimiento, no solo de capacidad.

6) “Mismo modelo de CPU” no significa misma plataforma

Diferentes modelos de servidor enrutan PCIe de forma distinta, vienen con valores BIOS distintos y exponen comportamientos NUMA distintos. Si asumes que puedes mover una carga entre servidores “equivalentes” y obtener el mismo rendimiento, aprenderás sobre topología en el peor momento posible.

Guía rápida de diagnóstico (primero/segundo/tercero)

Esta es la guía que desearía que más equipos usaran antes de adivinar, reiniciar o abrir un ticket de “la CPU está lenta”.

Primero: decide si estás limitado por cómputo, memoria o I/O

  • Revisa load average frente a tareas ejecutables, CPU steal y iowait.
  • Revisa proxies de presión de ancho de banda de memoria (fallos de caché, stalls) y swapping.
  • Revisa latencia de almacenamiento y profundidades de cola; revisa pérdidas de red y retransmisiones.

Segundo: mapea la topología (NUMA + PCIe) y verifica si coincide con la colocación de la carga

  • Identifica nodos NUMA y listas de CPU.
  • Mapea NICs y dispositivos NVMe a nodos NUMA.
  • Revisa dónde aterrizan las interrupciones y dónde se ejecutan tus procesos.

Tercero: valida que la plataforma no te esté estrangulando

  • Revisa el comportamiento de frecuencia de CPU bajo carga.
  • Revisa límites de potencia, throttling térmico y ajustes de firmware (C-states, P-states, límites turbo).
  • Confirma que la memoria corre a la velocidad esperada y con la configuración de canales correcta.

Si haces estas tres etapas, normalmente encuentras el cuello de botella en menos de 30 minutos. Si las omites, puedes pasarte tres días “optimizando” la capa equivocada.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas son tareas ejecutables en Linux que uso para diagnosticar cuellos de botella de plataforma. Cada una incluye: comando, salida representativa, qué significa y la decisión que impulsa.

Task 1: Identify sockets, NUMA nodes, and core topology

cr0x@server:~$ lscpu
Architecture:                         x86_64
CPU(s):                               64
Thread(s) per core:                   2
Core(s) per socket:                   16
Socket(s):                            2
NUMA node(s):                         2
NUMA node0 CPU(s):                    0-15,32-47
NUMA node1 CPU(s):                    16-31,48-63

Qué significa: Dual-socket, dos nodos NUMA. Las CPUs están divididas; los hyperthreads se intercalan.

Decisión: Si es sensible a latencia, considera fijar las cargas dentro de un solo nodo NUMA o asegurar que las asignaciones de memoria sigan la ubicación de CPU.

Task 2: Check per-NUMA memory distribution and whether one node is starving

cr0x@server:~$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 0 size: 257540 MB
node 0 free: 11844 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 1 size: 257676 MB
node 1 free: 182990 MB

Qué significa: El nodo 0 está casi lleno mientras el nodo 1 está mayormente libre. Ese es un escenario clásico de asignaciones de memoria remota y latencia en cola.

Decisión: Fija la carga al nodo 1, reequilibra servicios o aplica políticas de memoria (por ejemplo, bind/membind/interleave) según el comportamiento de la carga.

Task 3: See if the kernel is spending time waiting on I/O

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 892312  91340 8123432   0    0   120   340 4200 9800 18  4 76  2  0
 3  1      0 882104  91340 8126120   0    0  2140  1210 6100 12000 16  5 60 19  0
 2  1      0 879220  91340 8127001   0    0  1980  1400 5900 11700 15  5 62 18  0

Qué significa: “wa” (iowait) sube a ~19%, y aparecen procesos bloqueados (“b”). Probablemente ruta de almacenamiento o saturación.

Decisión: Pasa a latencia por dispositivo (iostat), revisa profundidades de cola y mapea topología NVMe/NIC.

Task 4: Identify storage latency and queue pressure

cr0x@server:~$ iostat -x 1 3
Device            r/s   w/s   rkB/s   wkB/s  await  svctm  %util
nvme0n1         4200  1100  82000   34000   3.20   0.18  92.5
nvme1n1         4100  1200  80000   36000   3.40   0.19  94.1

Qué significa: Alta utilización y await creciente indican que te acercas a la saturación. svctm bajo sugiere que el dispositivo está bien; el problema es el encolamiento.

Decisión: Reduce concurrencia, reparte I/O entre dispositivos, verifica si ambos comparten uplink PCIe o mueve la carga a unidades/controladores adicionales.

Task 5: Validate NVMe devices and their PCIe link width/speed

cr0x@server:~$ sudo nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
/dev/nvme0n1     S6X...               Samsung SSD 980 PRO 2TB                  1         2.00  TB /   2.00  TB      512   B +  0 B   5B2QGXA7
/dev/nvme1n1     S6Y...               Samsung SSD 980 PRO 2TB                  1         2.00  TB /   2.00  TB      512   B +  0 B   5B2QGXA7
cr0x@server:~$ sudo lspci -s 5e:00.0 -vv | egrep -i "LnkCap|LnkSta"
LnkCap: Port #0, Speed 16GT/s, Width x4
LnkSta: Speed 8GT/s, Width x4

Qué significa: El dispositivo soporta PCIe Gen4 (16GT/s) pero está funcionando en Gen3 (8GT/s). Eso es un problema de plataforma/firmware/slot, no un “NVMe lento”.

Decisión: Revisa ajustes BIOS de generación PCIe, compatibilidad de riser, cableado de ranura y si un switch/backplane fuerza Gen3.

Task 6: Map PCIe devices to NUMA nodes

cr0x@server:~$ for d in /sys/bus/pci/devices/*; do \
  dev=$(basename "$d"); \
  numa=$(cat "$d/numa_node" 2>/dev/null); \
  class=$(cat "$d/class" 2>/dev/null); \
  if [ "$numa" != "-1" ]; then echo "$dev numa=$numa class=$class"; fi; \
done | head
0000:3b:00.0 numa=0 class=0x010802
0000:3c:00.0 numa=0 class=0x020000
0000:af:00.0 numa=1 class=0x010802
0000:b0:00.0 numa=1 class=0x020000

Qué significa: Tienes NVMe y NICs conectados a ambos nodos NUMA. Bien—si colocas las cargas en consecuencia.

Decisión: Coloca servicios intensivos en almacenamiento cerca de su NVMe y servicios de red cerca de su NIC, o mantén un host “single-NUMA” para apps críticas de latencia.

Task 7: Check where your process is running (CPU affinity)

cr0x@server:~$ ps -o pid,psr,comm -p 21488
  PID PSR COMMAND
21488  52 postgres

Qué significa: El proceso está actualmente en la CPU 52, que (según lscpu) está en el nodo NUMA 1.

Decisión: Verifica sus asignaciones de memoria y sus dispositivos I/O también estén en el nodo 1. Si no, fíjalo o mueve dispositivos/IRQs.

Task 8: Check process NUMA memory placement

cr0x@server:~$ sudo numastat -p 21488
Per-node process memory usage (in MBs) for PID 21488 (postgres)
Node 0          18240.50
Node 1           2201.75
Total           20442.25

Qué significa: El proceso se ejecuta en el nodo 1 pero la mayor parte de la memoria vive en el nodo 0. Eso es acceso a memoria remota y un impuesto de latencia.

Decisión: Reinicia con política NUMA adecuada (bind CPU + memoria), ajusta la colocación del servicio o usa interleaving para cargas orientadas a throughput.

Task 9: Inspect interrupt distribution and hotspots

cr0x@server:~$ cat /proc/interrupts | egrep "nvme|mlx|eth" | head
  142:  1982341   10234      0      0  IR-PCI-MSI 524288-edge  nvme0q0
  143:  2059933   10111      0      0  IR-PCI-MSI 524289-edge  nvme0q1
  192:   982341  110993  809221  774112 IR-PCI-MSI 1048576-edge  mlx5_comp0
  193:   100112  989231  802331  790002 IR-PCI-MSI 1048577-edge  mlx5_comp1

Qué significa: Las colas NVMe están golpeando mayormente al grupo CPU0/CPU1 (primeras columnas). Las completions de NIC están distribuidas más uniformemente.

Decisión: Ajusta la afinidad IRQ para colas NVMe/NIC y distribuye la carga alineándola al NUMA. Si las IRQs se acumulan en pocas CPUs, tendrás contención de softirq y picos de latencia.

Task 10: Confirm CPU frequency and throttling behavior

cr0x@server:~$ sudo turbostat --Summary --quiet --show Busy%,Bzy_MHz,TSC_MHz,PkgTmp,PkgWatt -i 2 -n 2
Busy%   Bzy_MHz  TSC_MHz  PkgTmp  PkgWatt
42.31   2498     2500     86      205.4
44.02   2299     2500     89      205.0

Qué significa: La frecuencia ocupada cae mientras la temperatura del paquete sube. Puedes estar limitado por potencia/térmica, lo que parece “la CPU se volvió más lenta”.

Decisión: Revisa límites de potencia, refrigeración, perfil de energía del BIOS y límites de boost sostenido. No “optimices código” hasta que la plataforma sea estable.

Task 11: Detect network drops and retransmits (platform can cause this)

cr0x@server:~$ ip -s link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    RX:  bytes  packets  errors  dropped  missed  mcast
    9812331123  9923123  0       18422    0       223
    TX:  bytes  packets  errors  dropped  carrier collsns
    8123341123  8123311  0       0        0       0

Qué significa: Dropped en RX. Eso puede ser sobrecarga del ring buffer/cola, problemas de IRQ/colocación de CPU o contención PCIe—no solo “la red”.

Decisión: Revisa RSS/número de colas, afinidad IRQ, estadísticas del driver de la NIC y si la NIC comparte ancho de PCIe con NVMe intensos.

Task 12: Confirm NIC queue and RSS distribution

cr0x@server:~$ ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             32
TX:             32
Other:          0
Combined:       0
Current hardware settings:
RX:             8
TX:             8
Other:          0
Combined:       0

Qué significa: La NIC puede usar 32 colas pero estás usando 8. Si tienes muchos núcleos y tráfico intenso, 8 puede ser un cuello de botella.

Decisión: Aumenta las colas (con cuidado), luego alinea IRQs a CPUs NUMA locales. Más colas sin afinidad puede empeorar la situación.

Task 13: Inspect block layer queue settings (NVMe)

cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
128

Qué significa: La profundidad de la cola del bloque puede estar limitando el paralelismo para una carga orientada a throughput—o puede estar deliberadamente baja por latencia.

Decisión: Para throughputs por lotes, considera aumentarla. Para cargas sensibles a latencia, mantenla conservadora y arregla la topología primero.

Task 14: Determine if you are swapping or reclaiming aggressively

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           503Gi       412Gi        11Gi       1.2Gi        80Gi        63Gi
Swap:           16Gi       2.0Gi        14Gi

Qué significa: Uso de swap. No siempre es fatal, pero si eres sensible a latencia, es una bandera roja; además interactúa con el desbalance NUMA.

Decisión: Identifica qué servicio está consumiendo memoria, corrige fugas, limita caches o mueve la carga. El swapping suele ser un problema de dimensionamiento de plataforma, no de configuración fina.

Task 15: Check for cross-NUMA traffic hints via scheduler domains

cr0x@server:~$ cat /proc/sys/kernel/numa_balancing
1

Qué significa: El balanceo NUMA automático está habilitado. Puede ayudar a cargas de propósito general pero puede perjudicar cargas de latencia predecible moviendo páginas.

Decisión: Para sistemas críticos de latencia con pinning explícito, considera deshabilitarlo y gestionar la colocación deliberadamente. Para cargas mixtas o servidores generales, déjalo activado y mide.

Tres mini-historias corporativas desde las trincheras

Mini-historia 1: El incidente causado por una suposición equivocada

Un equipo migró un tier API de alto tráfico desde una plataforma dual-socket antigua a una plataforma dual-socket “más nueva y más rápida”. Mismo proveedor de CPU, relojes más altos, más núcleos. Parecía una victoria clara. Las pruebas de carga pasaron. La ventana de cambio fue tranquila. Luego llegó el lunes.

La latencia en cola se disparó. No la latencia media—solo el percentil 99. El grafo de dependencias de la API se iluminó como un despliegue navideño: timeouts a Redis, paradas esporádicas de la base de datos y pérdidas intermitentes de paquetes en el balanceador. El uso de CPU nunca superó el 50%, lo que hizo sospechar a todos de la capa de aplicación. La gente empezó a culpar a un “despliegue reciente”, que no tenía nada que ver.

La suposición equivocada fue sutil: “Dual-socket es dual-socket”. En los servidores nuevos, la NIC y el NVMe de arranque estaban en el socket 0, pero los pods más ocupados del runtime de contenedores se programaban en ambos sockets. Las interrupciones se gestionaban mayormente por CPUs en el socket 0, mientras que la mitad del procesamiento de la pila de red ocurría en el socket 1. Paquetes cruzaban sockets, las asignaciones de memoria rebotaban y una pequeña contención se convirtió en una fábrica de latencia en cola.

Una vez que fijaron los pods con carga de red al nodo NUMA de la NIC, alinearon la afinidad de IRQ y evitaron que el planificador dispersara hilos calientes entre sockets, el problema desapareció. El hardware no era más lento. La plataforma era diferente y el sistema pagaba un impuesto de topología en cada petición.

Lección: nunca trates “mismo número de sockets y núcleos” como “mismo rendimiento”. Trata el mapeo de la plataforma como un prerrequisito de despliegue, como reglas de firewall o certificados TLS.

Mini-historia 2: La optimización que salió mal

Un equipo de almacenamiento quería más throughput de nodos NVMe que ejecutaban una carga de búsqueda intensiva. Alguien notó que el uso de CPU era moderado y concluyó que el sistema estaba “subutilizado”. El plan: aumentar concurrencia. Incrementar profundidades de cola de I/O, aumentar contadores de workers de la aplicación y subir colas de NIC “para empatar con el conteo de núcleos”.

Funcionó para el benchmark. Siempre funciona. Bajo carga sintética constante, el throughput mejoró.

Entonces llegó el tráfico de producción: ráfagas, patrones mixtos de lectura/escritura, fallos de caché y compactaciones periódicas en background. Las latencias en cola se duplicaron. La plataforma entró en un régimen donde interrupciones y completions competían por caché y ancho de banda de memoria. Las mayores profundidades de cola amplificaron el encolamiento, convirtiendo microráfagas en paradas visibles por el usuario.

La parte engañosa fue la observabilidad. La latencia media no parecía horrible. La CPU no estaba saturada. Pero la ruta de completado ahora era caótica: más colas significaban más interrupciones, más rebotes de líneas de caché y más charla entre NUMA porque los workers adicionales no estaban fijados. La “optimización” había aumentado la contención más de lo que aumentó el trabajo útil.

La solución no fue revertir todo. Mantuvieron un aumento moderado del paralelismo y luego hicieron lo aburrido: alinearon las colas con CPUs NUMA locales, limitaron profundidades de cola para proteger la latencia y separaron la compactación en un conjunto de CPU dedicado. El throughput se mantuvo bien. La latencia en cola dejó de asustar al on-call.

Lección: más paralelismo no es lo mismo que más rendimiento. En plataformas modernas, el paralelismo puede ser un ataque de denegación de servicio contra tu propia jerarquía de memoria.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Un grupo de infraestructura estandarizó una plataforma de servidor para su flota de bases de datos. No solo el modelo de CPU—SKU de plataforma, ajustes de BIOS, versiones de firmware, patrón de población de DIMM, uso de ranuras PCIe y un mapeo documentado de dispositivos NIC/NVMe a nodos NUMA. Era tan aburrido que casi parecía ceremonial.

Seis meses después, un proveedor envió un lote de placas madre de reemplazo durante una escasez de suministro. Las placas de reemplazo eran “equivalentes” pero venían con valores BIOS distintos y un enrutamiento PCIe ligeramente diferente. Algunos hosts empezaron a mostrar lag intermitente de replicación y picos ocasionales de latencia de escritura.

Porque el equipo tenía una línea base de plataforma, lo detectaron rápido. Compararon los hosts problemáticos contra la referencia conocida buena: colocación de dispositivos por nodo NUMA, velocidad de enlace PCIe, distribución de IRQ y perfil de energía del BIOS. Las diferencias saltaron a la vista. Corregieron ajustes del BIOS, movieron una NIC a la ranura prevista y re-aplicaron su política de afinidad IRQ. Problema resuelto antes de convertirse en un informe de incidente.

La práctica que los salvó no fue magia. Fue tratar la configuración de plataforma como código: una línea base, un diff y un estado conocido bueno que puedes restaurar. La mayoría de equipos no hace esto porque no es glamoroso. La mayoría de equipos también pasa más tiempo apagando incendios.

Lección: La estandarización se siente lenta hasta que la necesitas. Entonces es más rápida que los héroes.

Errores comunes: síntomas → causa raíz → solución

1) Síntoma: CPU < 50%, pero la latencia es terrible

Causa raíz: Stalls de memoria, acceso NUMA remoto o encolamiento de I/O. La utilización de CPU no muestra ciclos bloqueados.

Solución: Revisa la colocación NUMA de memoria (numastat), latencia de almacenamiento (iostat -x) y distribución de IRQ. Fija servicios calientes a un nodo NUMA y alinea dispositivos.

2) Síntoma: El rendimiento empeoró después de añadir RAM

Causa raíz: La población de DIMM forzó velocidad de memoria inferior o canales desequilibrados; la latencia/ancho de banda cambió.

Solución: Verifica la velocidad de memoria en BIOS/firmware, asegura población balanceada de canales, evita mezclar tipos de DIMM. Trata las ampliaciones de memoria como cambios de rendimiento y vuelve a probar.

3) Síntoma: Throughput NVMe inferior al esperado en unidades “Gen4”

Causa raíz: Enlace entrenado a Gen3 o x2; ranura, riser o limitación del backplane.

Solución: Confirma con lspci -vv el estado del enlace; ajusta ajustes BIOS PCIe; mueve el dispositivo a una ranura conectada a la CPU.

4) Síntoma: Pérdidas de red durante periodos intensos de almacenamiento

Causa raíz: NIC y NVMe comparten uplink/root complex PCIe; el tráfico de completions compite; las IRQs aterrizan en núcleos sobrecargados.

Solución: Mapea la topología PCIe, mueve un dispositivo al otro socket/root complex si es posible; ajusta afinidad IRQ; aumenta colas solo después de tener la colocación correcta.

5) Síntoma: Servidor dual-socket más lento que uno single-socket para el mismo servicio

Causa raíz: Tráfico entre sockets y rebote de líneas de caché; el planificador dispersa hilos; las asignaciones remotas dominan.

Solución: Restringe el servicio a un socket; asigna la memoria local; separa vecinos ruidosos; reconsidera si realmente necesitabas dual-socket.

6) Síntoma: Efectos de “vecino ruidoso” en microservicios a pesar de suficientes núcleos

Causa raíz: Recursos de plataforma compartidos: contención de LLC, saturación de ancho de banda de memoria, uplinks PCIe compartidos, presión de IRQ.

Solución: Usa cpusets y colocación consciente de NUMA; reserva hosts para cargas intensivas en ancho de banda de memoria; separa pods con mucho I/O en hosts con layout PCIe limpio.

7) Síntoma: Los benchmarks se ven bien; la latencia en cola en producción es mala

Causa raíz: Los benchmarks son steady-state; la producción es con ráfagas. El encolamiento + interrupciones + GC/compaction amplifican las ráfagas.

Solución: Prueba con patrones de ráfagas, limita profundidades de cola, aisla trabajo en background y prefiere colocación predecible sobre máxima concurrencia.

Broma 2/2: Si tu plan es “agrega hilos hasta que sea rápido”, felicidades—has reinventado el thundering herd, ahora con PCIe.

Listas de verificación / plan paso a paso

Lista de selección de plataforma (antes de comprar o estandarizar)

  1. Define el cuello de botella que esperas: ancho de banda de memoria, pps de red, latencia de almacenamiento, rendimiento GPU o mixto.
  2. Elige intencionalmente el número de sockets: socket único para latencia predecible; dual-socket cuando realmente necesitas más memoria/I/O y tu software es NUMA-aware.
  3. Valida necesidades de canales de memoria: ancho de banda requerido, reglas de población de DIMM y velocidad esperada a plena población.
  4. Cuenta los carriles PCIe como dinero: NICs, NVMe, GPUs/DPUs, HBAs; asume que eventualmente usarás cada lane que compres.
  5. Pide el mapa de ranuras PCIe: qué ranuras se conectan a qué CPU/root complex; dónde van los uplinks del backplane.
  6. Planifica interrupciones y colas: suficientes núcleos cerca de la NIC/NVMe; evita forzar todo el I/O en un socket.
  7. Considera el impacto de licencias: por-socket/por-núcleo cambia la elección óptima de sockets.
  8. Estandariza BIOS y firmware: perfil de energía, C-states, generación PCIe, SR-IOV y exposición NUMA.

Lista de despliegue (antes de que llegue una carga)

  1. Registra salidas de lscpu y numactl --hardware como línea base del host.
  2. Mapea NIC/NVMe a nodos NUMA vía /sys/bus/pci/devices/*/numa_node.
  3. Confirma anchos y velocidades de enlace PCIe para dispositivos críticos.
  4. Define política de afinidad IRQ (o confirma que los valores por defecto de tu distro coinciden con tu intención).
  5. Decide la colocación: un nodo NUMA por servicio (latencia) vs interleave (throughput).
  6. Prueba con cargas que incluyan ráfagas y tareas en background (compaction, backups).

Lista de incidentes (qué hacer bajo presión)

  1. Comprueba si el cuello de botella es I/O, memoria o throttling de frecuencia de CPU antes de tocar la configuración de la app.
  2. Confirma si la latencia en cola se correlaciona con desbalance NUMA, pérdidas o encolamiento de almacenamiento.
  3. Si es multi-socket: restringe la carga a un socket como mitigación (no como solución final).
  4. Reduce concurrencia si el encolamiento es el problema; no “subas hilos” hacia una tormenta.
  5. Captura snapshots antes/después de topología y distribución de IRQ para evitar soluciones placebo.

Preguntas frecuentes

1) ¿Son mejores ahora los servidores de socket único?

Para muchos servicios sensibles a la latencia, sí: NUMA más simple, menos sorpresas entre sockets y, a menudo, suficientes núcleos. Dual-socket es excelente cuando realmente necesitas más capacidad de memoria, ancho de banda o lanes I/O y tu software está correctamente colocado.

2) Si la utilización de CPU es baja, ¿por qué mi servicio va lento?

Porque la utilización no mide ciclos bloqueados. Puedes estar bloqueado en almacenamiento, esperando memoria o rebotando líneas de caché entre sockets. Diagnostica encolamiento y colocación antes de culpar a la aplicación.

3) ¿Cuál es la forma más rápida de detectar un problema NUMA?

Compara la ubicación de CPU frente a la ubicación de memoria para el proceso. Si el proceso corre en el nodo 1 pero la mayor parte de su memoria está en el nodo 0, probablemente encontraste tu latencia en cola. Usa ps junto con numastat -p.

4) ¿Debo desactivar el balanceo automático NUMA?

A veces. Si fijas explícitamente CPU y memoria para latencia predecible, el balanceo NUMA puede jugar en contra al migrar páginas. Para cargas mixtas o servidores de uso general, puede ayudar. Mide; no lo copies sin entender.

5) ¿Más colas de NIC siempre mejora el rendimiento?

No. Más colas pueden aumentar interrupciones y churn de caché, y pueden repartir trabajo entre sockets si no gestionas afinidad. Aumenta colas solo tras confirmar que la afinidad IRQ y la colocación de CPU son sensatas.

6) ¿Cómo sé si mi NVMe está limitado eléctricamente por la plataforma?

Revisa ancho y velocidad de enlace PCIe con lspci -vv. Si LnkCap muestra Gen4 x4 pero LnkSta muestra Gen3 o más estrecho, estás dejando rendimiento sobre la mesa por limitaciones de ranura/backplane/BIOS.

7) ¿Por qué los benchmarks se ven bien pero la producción va mal?

Los benchmarks son controlados. La producción tiene ráfagas, cargas mixtas, trabajo background, GC y vecinos ruidosos. Eso amplifica el encolamiento y los errores de topología. Siempre prueba con patrones de ráfagas y trabajo background real.

8) ¿Es dual-socket siempre peor para bases de datos?

No. Las bases de datos pueden escalar bien en dual-socket cuando se configuran con conciencia NUMA, colocación de memoria adecuada y I/O local. El modo de fallo es “dejar todo por defecto”, donde hilos, memoria e interrupciones vagan libremente.

9) ¿Cómo se relacionan los sockets con el diseño de almacenamiento específicamente?

Las rutas de almacenamiento usan DMA y colas de completions. Si tus NVMe están en un socket y tus hilos de almacenamiento corren en el otro, pagarás accesos remotos y saltos de fabric en cada I/O. Alinea la pila: dispositivo, IRQs y hilos en el mismo nodo NUMA.

10) ¿Cuál es un hábito de plataforma que reduce incidentes?

Establece una línea base de tu topología y firmware como haces con la configuración del SO. Cuando algo “cambia misteriosamente”, puedes diffear la realidad contra lo conocido bueno en lugar de depurar folklore.

Próximos pasos que puedes hacer esta semana

Si quieres menos misterios de rendimiento y menos debates a las 2 a.m. sobre gráficos de CPU, haz esto en orden:

  1. Inventaría la topología en tu flota: sockets, nodos NUMA y localidad NUMA de dispositivos. Guárdalo con el registro del host.
  2. Elige una política de colocación por defecto: single-NUMA para capas de latencia; interleave para capas de throughput. Hazlo intencional, no accidental.
  3. Estandariza ajustes de BIOS/firmware para perfiles de energía y generación PCIe. “Valores de fábrica” no son una estrategia de fiabilidad.
  4. Crea un runbook de incidentes usando la guía rápida de diagnóstico arriba. Pon los comandos en él. Hazlo ejecutable bajo presión.
  5. Realiza un experimento controlado: fija un servicio crítico a un socket y mide la latencia en cola. Si mejora, aprendiste algo accionable sobre tu plataforma.

El titular no es “las CPU no importan”. Sí importan. Pero la jugada ganadora ahora es tratar al socket—y a la plataforma que lo rodea—como la unidad de estrategia. Compra topología a propósito. Opérala con intención.

← Anterior
Ubuntu 24.04: Cuando GRO/LRO/TSO rompen cosas — cómo probar y desactivar con seguridad
Siguiente →
MySQL vs SQLite: el caso de la «velocidad gratis» — cuando una BD en fichero vence a un servidor

Deja un comentario