Las fallas más extrañas en computación de alto rendimiento no son causadas por rayos cósmicos ni por condiciones de carrera exóticas.
Son provocadas por supuestos ordinarios que se convierten en armas cuando escalas a decenas de miles de núcleos,
millones de archivos y redes diseñadas como una catedral.
Si tu código funciona bien en 64 núcleos y luego se convierte en una calabaza en 4.096, no tienes un “problema de rendimiento”.
Tienes un error de escalado. Y los errores de escalado rara vez son glamorosos. A menudo son aburridos. Por eso sobreviven.
Cómo se ven los errores de escalado en supercomputadoras reales
Un error de escalado es lo que ocurre cuando algo que está “bien” a pequeña escala se vuelve matemática,
física u organizativamente imposible a gran escala.
No más lento. Imposible.
En 8 nodos, una barrera descuidada es un error de redondeo. En 8.192 nodos, esa barrera se convierte en un impuesto que pagas en cada iteración,
y el cobrador es una tormenta de paquetes. En 8 nodos, abrir 10.000 archivos durante el arranque es “suficientemente rápido”.
En 8.192 nodos, es un ataque de denegación de servicio distribuido contra tu servidor de metadatos.
La parte difícil es que el sistema a menudo parece “saludable” desde fuera. Las CPUs están ocupadas, el trabajo no ha fallado, los enlaces de red están arriba,
y el almacenamiento está “solo” al 40% de capacidad. Mientras tanto, tu tiempo de reloj se duplica cuando agregas más nodos.
Eso no es un misterio. Es física, teoría de colas y la suposición inocente de un desarrollador sobre “solo un MPI_Allreduce más”.
Aquí está el titular: las supercomputadoras fallan de las mismas maneras que fallan las flotas normales.
Solo que lo hacen a una escala absurda, con un acoplamiento más estrecho y usuarios que miden el tiempo en horas-nodo y rencores.
Los errores de escalado a menudo son “tontos” porque son de tamaño humano
- Rutas de control O(N) que deberían haber sido O(1) se convierten en un precipicio. Un “reunir información de depuración” all-to-all se transforma en un funeral all-to-all.
- Recursos compartidos únicos (un bloqueo, un líder de rango, un destino de metadatos, un hilo del nodo cabeza) se convierten en cuellos de botella.
- Configuraciones por defecto (buffers TCP, hugepages, límites del planificador, conteos de striping en Lustre) se eligieron para cargas “razonables”, no para tu caos.
- Brechas de observabilidad convierten el rendimiento en superstición. Sin temporización por rango, discutes sobre fantasmas.
Broma #1: Un trabajo de 10.000 núcleos es simplemente un trabajo normal con más oportunidades de equivocarse.
Una cita para mantener en la pared
“La esperanza no es una estrategia.” — General Gordon R. Sullivan
Si ejecutas HPC en producción, puedes ser optimista sobre la ciencia. No puedes ser optimista sobre la latencia de cola,
los sistemas de archivos compartidos o la probabilidad de que un nodo entre 5.000 haga algo extraño hoy.
Hechos e historia que realmente importan
La historia de la supercomputación está llena de números brillantes de FLOPS. Las lecciones operativas están en las notas al pie.
Algunos hechos concretos y puntos de contexto que cambian cómo piensas sobre el escalado:
- La ley de Amdahl (1967) no dejó de ser cierta porque empezamos a comprar GPUs. Las fracciones seriales siguen matando la aceleración a escala.
- La ley de Gustafson (finales de los 80) explica por qué el “weak scaling” puede verse muy bien incluso cuando el “strong scaling” se desmorona. No confundas ambos.
- MPI existe desde los años 90; los patrones de comunicación están bien estudiados. Muchos “nuevos” errores de escalado son errores viejos con contenedores.
- Sistemas de archivos paralelos como Lustre popularizaron la separación de metadatos y datos; la mayoría de las ralentizaciones catastróficas hoy son patologías de metadatos, no límites de ancho de banda crudo.
- InfiniBand y RDMA hicieron posibles colectivas de baja latencia, pero también facilitaron saturar la red con tormentas colectivas.
- Los sistemas de la era exascale han apostado por nodos heterogéneos (CPUs + GPUs). Eso desplaza los cuellos de botella: la localidad PCIe/NVLink y el staging en host son asesinos silenciosos frecuentes.
- Checkpoint/restart se volvió obligatorio operativamente a medida que crecieron los tamaños de trabajo; no puedes tratar las fallas como “eventos raros” cuando ejecutas 20.000 componentes durante horas.
- El escalado de metadatos del sistema de archivos se volvió una preocupación de primera clase cuando los flujos de trabajo cambiaron de unos pocos archivos gigantes a millones de archivos pequeños (piense en fragmentos de características de ML, ejecuciones de ensamblaje y registros por rango).
- Los planificadores (PBS, Slurm, etc.) convirtieron las supercomputadoras en sistemas compartidos de producción. Eso introdujo la “física de colas”: backfill, fragmentación y salud de nodos se vuelven variables de rendimiento.
Modos principales de fallo: cómputo, red, almacenamiento, planificador
1) Cómputo: el rango más lento marca el ritmo
En HPC fuertemente acoplado, el rendimiento lo dicta la cola. Un rango sufre una tormenta de fallos de página, o un socket funciona a menor frecuencia,
y todo el trabajo espera en el siguiente punto de sincronización. Por eso el “uso medio de CPU” es una mentira que te dices para sentirte mejor.
Observa:
- Errores de localidad NUMA: memoria asignada en el socket equivocado, ancho de banda remoto, bloqueos impredecibles.
- Sobre-adscripción de hilos: valores por defecto de OpenMP que se multiplican entre rangos MPI y colapsan las cachés de CPU.
- Reducción de frecuencia: límites de potencia, termorregulación o downclock inducido por AVX que cambian los tiempos por nodo.
2) Red: a las colectivas no les importan tus sentimientos
La mayoría de los colapsos de escalado “misteriosos” son sobrecargas de comunicación que crecieron más rápido que tu cómputo.
Las colectivas (Allreduce, Alltoall, Barrier) son necesarias; también son la forma más fácil de convertir una red sofisticada en un estacionamiento.
Observa:
- Patrones all-to-all en FFTs, transposiciones y algunos flujos de trabajo de ML. Son sensibles a la topología y la congestión.
- Rangos desequilibrados que convierten colectivas en bloqueos repetidos.
- Ajustes de MTU, crédito o colas que ayudaron microbenchmarks pero desestabilizaron el tráfico real.
3) Almacenamiento: el ancho de banda raramente es lo primero que falla
Los errores de escalado en almacenamiento suelen ser contención de metadatos disfrazada de “E/S lenta”.
Se manifiesta como: trabajos que se cuelgan al inicio, o “open() es lento”, o “stat() tarda una eternidad”, o el sistema de archivos parece bien pero la aplicación está atascada.
Observa:
- Millones de archivos pequeños al inicio/final de trabajo (registros por rango, salidas por tarea, archivos temporales).
- Tormentas de checkpoint donde muchos rangos escriben simultáneamente, saturando un subconjunto de OSTs debido a un striping pobre.
- Desajustes de caché en el cliente: caché demasiado agresiva causando contención e invalidaciones, o muy poca causando viajes de ida y vuelta de metadatos.
4) Planificador y operaciones: tu trabajo es un huésped en un hotel concurrido
El escalado no está solo dentro del trabajo. Está en el clúster.
Las políticas del planificador, la salud de los nodos y los servicios compartidos (auth, DNS, registros de contenedores, servidores de licencias) se vuelven parte de tu perfil de rendimiento.
Observa:
- Colocación de trabajos: nodos dispersos por islas o switches leaf, aumentando el recuento de saltos y la contención.
- Ruido de fondo: agentes de monitorización, actualizaciones de kernel, registros descontrolados o un trabajo vecino que está haciendo E/S “creativa”.
- Fragilidad del plano de control: Slurmctld sobrecargado, scripts prolog/epilog lentos o demoras de autenticación a escala.
Guía rápida de diagnóstico (encuentra el cuello de botella rápido)
No obtienes puntos extra por diagnosticar despacio. Cuando un trabajo grande está quemando horas-nodo, triajeas como un SRE:
determina si estás limitado por cómputo, red o E/S, y luego reduce hasta el limitador específico.
Primero: confirma qué significa “mal” y aísla la escala
- Reproduce en dos tamaños: uno que escala “bien” y otro que no (por ejemplo, 256 rangos vs 4096). Si el problema no varía con la escala, no es un error de escalado.
- Decide tu métrica: tiempo por iteración, tiempo hasta checkpoint, tiempo hasta solución o eficiencia del trabajo. Elige una. No lo pases por alto.
- Busca cambios de fase: arranque, estado estable de cómputo, fases de comunicación, checkpoints de E/S, finalización. Los fallos de escalado a menudo se esconden en fases cortas.
Segundo: determina el estado de espera dominante
- CPU ocupada pero IPC bajo sugiere memoria/NUMA o reducción de velocidad por vectores.
- Alto tiempo en llamadas MPI sugiere red/colectivas o desequilibrio.
- Alto tiempo en open/stat/fsync sugiere patologías de metadatos.
- Muchos rangos inactivos en barreras sugiere desequilibrio de carga o un nodo lento.
Tercero: encuentra el patrón “una cosa lenta”
A escala, un nodo enfermo puede frenar todo un trabajo.
No promedies. Identifica outliers por rango y por host.
- Encuentra los rangos más lentos (temporización de la app o perfilado MPI).
- Mapea rangos a hosts (planificador o mpirun mapping).
- Revisa la salud local del nodo: errores de memoria, frecuencia de CPU, contadores de NIC, errores del cliente de sistema de archivos.
Cuarto: verifica que los servicios compartidos no sean el cuello de botella oculto
Los timeouts de DNS, la lentitud de LDAP, las descargas de registros de contenedores y los checkouts de licencias pueden parecer “colgamiento de la aplicación”
cuando se multiplican por miles de nodos. El clúster puede estar “caído” sin estar “caído”.
Broma #2: Nada crea trabajo en equipo como 4.000 nodos esperando una única consulta DNS.
Tareas prácticas: comandos, salidas, decisiones (12+)
Estas son tareas operativas realistas que puedes ejecutar durante un incidente o una investigación de rendimiento.
Cada una incluye: un comando, qué significa la salida típica y qué decisión tomas a partir de ello.
Ajusta rutas y nombres de dispositivos a tu entorno.
Task 1: Confirmar colocación del trabajo y lista de nodos (Slurm)
cr0x@server:~$ scontrol show job 842193
JobId=842193 JobName=climate_step
UserId=ana(14021) GroupId=hpc(14000) MCS_label=N/A
Priority=12233 Nice=0 Account=research QOS=normal
JobState=RUNNING Reason=None Dependency=(null)
RunTime=00:18:42 TimeLimit=02:00:00 TimeMin=N/A
NodeList=cn[1203-1234,1301-1366]
NumNodes=98 NumCPUs=6272 NumTasks=6272 CPUs/Task=1
TRES=cpu=6272,mem=1500G,node=98
MinCPUsNode=64 MinMemoryNode=15000M MinTmpDiskNode=0
Qué significa: NodeList muestra si obtuviste un bloque compacto o una asignación dispersa. Rangos mixtos pueden indicar múltiples islas de red.
Decisión: Si el rendimiento es sensible a la topología, solicita nodos contiguos (constraints/partitions) o usa opciones del planificador conscientes de la topología.
Task 2: Verificar eficiencia del trabajo y encontrar desperdicio obvio (contabilidad Slurm)
cr0x@server:~$ sacct -j 842193 --format=JobID,Elapsed,AllocCPUS,CPUTime,MaxRSS,AveCPU,State
JobID Elapsed AllocCPUS CPUTime MaxRSS AveCPU State
842193 00:18:42 6272 19-11:05:24 2100Mc 00:08.2 RUNNING
842193.batch 00:18:42 64 00:19:10 320Mc 00:18.9 RUNNING
Qué significa: AveCPU baja en relación con Elapsed sugiere mucha espera (MPI, E/S, desequilibrio). MaxRSS ayuda a detectar margen de memoria o riesgo de paginación.
Decisión: Si AveCPU está muy por debajo de lo esperado, perfila tiempo MPI o E/S; si MaxRSS está cerca de los límites de memoria por nodo, espera paginación y rangos lentos.
Task 3: Encontrar frecuencia de CPU por nodo y pistas de throttling
cr0x@server:~$ sudo turbostat --quiet --Summary --interval 5 --num_iterations 1
Avg_MHz Busy% Bzy_MHz TSC_MHz IRQ SMI PkgTmp PkgWatt CorWatt
1890 78.3 2415 2300 8120 0 84.0 265.4 202.1
Qué significa: Si Bzy_MHz es bajo bajo carga o PkgTmp es alto, puedes estar sufriendo throttling. Busy% cerca de 100% pero MHz bajos es sospechoso.
Decisión: Si hay throttling, revisa límites de potencia/problemas térmicos; considera reducir el impacto de código AVX o ajustar políticas de gestión de energía.
Task 4: Detectar rápidamente mala colocación NUMA
cr0x@server:~$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0-31
node 0 size: 256000 MB
node 0 free: 182340 MB
node 1 cpus: 32-63
node 1 size: 256000 MB
node 1 free: 190112 MB
node distances:
node 0 1
0: 10 21
1: 21 10
Qué significa: La distancia indica la penalidad de acceso remoto. Si procesos corren en node 0 pero asignan memoria en node 1, pagas en ancho de banda y latencia.
Decisión: Ata los rangos/hilos y memoria de forma consistente (por ejemplo, Slurm –cpu-bind, numactl u OpenMP affinity). Valida con rendimiento por rango.
Task 5: Identificar presión de runqueue de CPU y iowait en un nodo
cr0x@server:~$ mpstat -P ALL 1 3
Linux 5.15.0 (cn1203) 01/22/2026 _x86_64_ (64 CPU)
12:10:11 PM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
12:10:12 PM all 61.2 0.0 6.1 18.9 0.0 1.2 0.0 12.6
12:10:12 PM 0 55.0 0.0 5.0 29.0 0.0 1.0 0.0 10.0
Qué significa: Alto %iowait indica que la CPU está bloqueada esperando E/S. No es “disk busy”, sino “tu proceso está bloqueado”.
Decisión: Si iowait sube durante checkpoints, investiga el rendimiento del sistema de archivos y la configuración de striping; si durante cómputo, busca paginación o llamadas de metadatos del sistema de archivos.
Task 6: Confirmar si estás haciendo swap (un generador clásico de rangos lentos)
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
12 0 0 182340 4212 81234 0 0 0 12 5200 8100 62 6 13 19
10 2 8192 10240 3900 22000 120 240 1024 2048 6100 9900 41 7 8 44
Qué significa: Si si/so (swap-in/out) no es cero bajo carga es mala noticia. Incluso “un poco de swap” a escala crea rezagados.
Decisión: Reduce la huella de memoria, incrementa la solicitud de memoria por nodo, arregla fugas o ajusta el tamaño del problema. Si solo un nodo hace swap, sospecha de un DIMM malo o límites de cgroup mal configurados.
Task 7: Comprobar desequilibrio de rangos MPI con un archivo de tiempos simple
cr0x@server:~$ awk '{sum+=$2; if($2>max){max=$2; rmax=$1} if(min==0||$2
Qué significa: Una amplia dispersión max/min grita desequilibrio o nodo lento. El rango máximo es tu objetivo de investigación.
Decisión: Mapea el rango lento a un host; revisa salud del nodo, colocación NUMA y errores de NIC/almacenamiento en ese host.
Task 8: Mapear rangos a nodos (estilo Slurm + mpirun)
cr0x@server:~$ srun -j 842193 -N 1 -n 1 hostname
cn1203
Qué significa: Valida que puedes dirigirte a nodos específicos desde la asignación. Usarás esto para interrogar outliers.
Decisión: Si los rangos lentos se mapean a un nodo o a un grupo de switch, probablemente tengas un problema de hardware o topología, no de algoritmo.
Task 9: Revisar contadores de puertos InfiniBand por errores y congestión
cr0x@server:~$ ibstat
CA 'mlx5_0'
CA type: MT4123
Number of ports: 1
Port 1:
State: Active
Physical state: LinkUp
Rate: 200
Base lid: 1043
SM lid: 1
Link layer: InfiniBand
cr0x@server:~$ perfquery -x -r 1 | egrep 'PortXmitWait|PortRcvErrors|PortXmitDiscards'
PortXmitWait....................: 000000000000a1f2
PortRcvErrors...................: 0000000000000000
PortXmitDiscards................: 0000000000000003
Qué significa: PortXmitWait sugiere congestión (esperando para transmitir). Discards indican drops; no es normal en estado estable.
Decisión: Si los contadores de congestión suben durante fases lentas, mira la colocación/topología del trabajo y los algoritmos de colectivas; si errores/discards suben en un nodo, sospecha cable/NIC/puerto de switch.
Task 10: Verificar utilización de enlaces y pérdidas en redes Ethernet de gestión o almacenamiento
cr0x@server:~$ ip -s link show dev eno1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
RX: bytes packets errors dropped missed mcast
9876543210 8123456 0 120 0 10022
TX: bytes packets errors dropped carrier collsns
8765432109 7345678 0 42 0 0
Qué significa: Paquetes descartados a escala pueden aparecer como “lentitud aleatoria”, especialmente para servicios del plano de control y homes basados en NFS.
Decisión: Si las pérdidas aumentan, revisa buffers de anillos de NIC, drivers/firmware y colas de switch; considera mover tráfico ruidoso fuera de enlaces de gestión compartidos.
Task 11: Identificar puntos calientes de metadatos en un cliente Lustre
cr0x@server:~$ lctl get_param -n llite.*.stats | egrep 'open|close|statfs|getattr' | head
open 1209341 samples [usec] 1 10 25 100 250 1000 2000 5000 10000 50000
close 1209340 samples [usec] 1 10 25 100 250 1000 2000 5000 10000 50000
getattr 883201 samples [usec] 1 10 25 100 250 1000 2000 5000 10000 50000
statfs 12012 samples [usec] 1 10 25 100 250 1000 2000 5000 10000 50000
Qué significa: Grandes cuentas de open/getattr sugieren que la app está machacando metadatos. Los buckets de latencia (si se expanden) muestran si estas llamadas son lentas.
Decisión: Si los metadatos están calientes, reduce el número de archivos, usa agregación por nodo, evita registros por rango y considera hashing de directorios/striping soportado por tu sistema de archivos.
Task 12: Verificar señales de saturación y salud de OST/MDT (lado servidor Lustre)
cr0x@server:~$ lctl get_param -n obdfilter.*.kbytesavail | head
obdfilter.fs-OST0000.kbytesavail=912345678
obdfilter.fs-OST0001.kbytesavail=905123456
obdfilter.fs-OST0002.kbytesavail=887654321
cr0x@server:~$ lctl get_param -n mdt.*.md_stats | head
mdt.fs-MDT0000.md_stats:
open 39123890
close 39123888
getattr 82012311
setattr 1023311
Qué significa: Desequilibrio de capacidad puede crear hotspots no intencionados. Operaciones MDT altas se correlacionan con “arranque lento” y “finalización colgada”.
Decisión: Si un OST está mucho más lleno, reequilibra o ajusta striping; si las operaciones MDT son extremas durante tormentas de trabajo, afina el comportamiento del cliente y arregla los patrones de archivos de la aplicación.
Task 13: Observar E/S por proceso con pidstat
cr0x@server:~$ pidstat -d -p 21344 1 3
Linux 5.15.0 (cn1203) 01/22/2026 _x86_64_ (64 CPU)
12:12:01 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:12:02 PM 14021 21344 0.00 51200.00 0.00 87 climate_step
12:12:03 PM 14021 21344 0.00 48000.00 0.00 91 climate_step
Qué significa: Alta tasa de escritura más iodelay indica que el proceso está bloqueado en E/S. Si muchos rangos muestran esto simultáneamente, es un cuello de botella del sistema de archivos.
Decisión: Coordina tiempos de checkpoint, incrementa striping, reduce frecuencia o usa buffers locales por nodo si están disponibles.
Task 14: Detectar patología de “pequeñas E/S” con iostat
cr0x@server:~$ iostat -dxm 1 2
Linux 5.15.0 (cn1203) 01/22/2026 _x86_64_ (64 CPU)
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await svctm %util
nvme0n1 0.0 3200.0 0.0 48.0 30.7 9.4 3.1 0.2 64.0
Qué significa: Muchas IOPS con avgrq-sz pequeño significa escrituras pequeñas. Await crece cuando la cola se forma. %util muestra saturación del dispositivo.
Decisión: Si es local al nodo, arregla buffering y batching; si es un montaje compartido, el patrón probablemente se amplifica a escala—agrega escrituras y alinea los tamaños de E/S.
Task 15: Encontrar hotspots de syscalls (open/stat/fsync) con resumen de strace
cr0x@server:~$ strace -c -p 21344 -f -q -e trace=openat,statx,futex,fsync,close -t -o /tmp/strace.out
strace: Process 21344 attached
^Cstrace: Process 21344 detached
cr0x@server:~$ tail -n 8 /tmp/strace.out
% time seconds usecs/call calls errors syscall
62.14 1.840231 92 20007 102 openat
18.77 0.555880 71 7821 0 statx
11.02 0.326112 40 8099 0 futex
8.07 0.239055 310 771 0 fsync
Qué significa: Si openat/statx dominan, tienes intensidad de metadatos. Si futex domina, puedes tener contención de locks. Si fsync domina, pagas costos de durabilidad.
Decisión: Para metadatos, reduce operaciones de archivos y usa menos archivos; para contención de futex, refactoriza threading o reduce locks compartidos; para fsync, agrupa sincronizaciones o usa puntos de durabilidad menos frecuentes.
Task 16: Revisar logs de kernel y cliente de sistema de archivos por errores “blandos”
cr0x@server:~$ dmesg -T | tail -n 12
[Thu Jan 22 12:06:41 2026] Lustre: llite fs-ffff8c2b3c2c8800: server not responding, reconnecting
[Thu Jan 22 12:06:43 2026] Lustre: llite fs-ffff8c2b3c2c8800: Connection restored
[Thu Jan 22 12:08:10 2026] mlx5_core 0000:41:00.0: CQE error: syndrome 0x2 vendor syndrome 0x0
[Thu Jan 22 12:08:10 2026] mlx5_core 0000:41:00.0: Dumping QP 0x1a2b
Qué significa: Re-conexiones transitorias y errores CQ de NIC pueden crear rangos lentos sin una falla dura. Estos son los errores “tontos” que arruinan las gráficas de escalado.
Decisión: Si solo un subconjunto de nodos muestra esto, drénalos del planificador y abre un ticket de hardware; si es generalizado, sospecha un incidente de red/sistema de archivos.
Tres mini-historias del mundo corporativo (anonimizadas)
Mini-historia 1: La suposición equivocada (y el impuesto de MPI_Barrier)
Un grupo de investigación llevó una nueva simulación a un clúster HPC corporativo—código serio, ciencia seria, presupuesto serio.
Los desarrolladores habían validado la corrección en una partición modesta y pidieron “tantos nodos como puedan”
para cumplir un plazo.
La ejecución inicial escaló maravillosamente hasta unos cientos de rangos. Más allá de eso, el rendimiento se fue por la borda.
El trabajo no falló; simplemente dejó de acelerarse. Los usuarios culparon “la red”.
El equipo de red culpó “el código”. Todos estaban medio en lo correcto, que es el peor tipo de razón.
El perfilado mostró una fracción asombrosa de tiempo en MPI_Barrier. Eso no es automáticamente un crimen,
pero nunca es un cumplido. El verdadero culpable fue una suposición: un bloque de “timing de depuración” que recogía
métricas por rango en cada iteración y serializaba la salida a través del rango 0. Se suponía que era temporal.
Se había vuelto permanente por inercia.
A pequeña escala, el costo de la barrera se ocultaba bajo el cómputo. A gran escala, la barrera se convirtió en un punto de sincronización global
que amplificó desequilibrios menores en grandes paradas. El rango 0 luego hacía trabajo extra formateando
y escribiendo registros. La “depuración temporal” se transformó en un generador de desequilibrio de carga.
La solución fue casi ofensivamente simple: recoger tiempos cada N iteraciones, agregar jerárquicamente (nivel nodo y luego global),
y escribir un registro compacto por checkpoint en vez de por iteración. El escalado se recuperó.
No porque la red se volviera más rápida, sino porque el código dejó de exigir que la red se comportara como magia.
Mini-historia 2: La optimización que salió mal (striping por gloria, contención por realidad)
Un equipo de plataforma intentó ayudar a una carga analítica que escribía grandes archivos de checkpoint.
Alguien sugirió aumentar el striping de Lustre a través de muchos OSTs para “obtener más ancho de banda”.
Funcionó en un microbenchmark pequeño. Lo desplegaron ampliamente mediante un módulo que fijaba el striping por defecto
para todo el directorio del proyecto.
Entonces llegó la producción. La carga no escribía un gran archivo secuencial por trabajo.
Escribía muchos archivos medianos y hacía operaciones frecuentes de metadatos. Striping amplio incrementó la cantidad de
coordinación que el sistema de archivos tenía que hacer. También aumentó la probabilidad de que al menos un OST estuviera ocupado,
convirtiendo la latencia de cola en un factor dominante.
El síntoma más doloroso: los trabajos se volvieron impredecibles. Algunos corrían bien, otros avanzaban a paso de tortuga.
Los usuarios hicieron lo que siempre hacen: reenvían. Esto multiplicó la carga y el clúster pareció embrujado.
El diagnóstico vino de correlacionar periodos lentos con el desequilibrio de carga de los OST y operaciones de metadatos elevadas.
“Más stripes” aumentó el fanout cruzado entre OSTs y la contención, lo que dañó cuando el patrón de acceso no era
E/S secuencial grande. La optimización resolvió un problema de laboratorio y creó uno de producción.
Revirtieron el striping por defecto, establecieron orientación sensata por carga de trabajo y añadieron una medida de seguridad:
trabajos que usaban la plantilla de directorio del proyecto tenían una comprobación previa para validar tamaños de archivo y recomendar conteos de stripe.
El sistema de archivos no se volvió más rápido; volvió a ser predecible. Predecible gana a rápido en sistemas compartidos.
Mini-historia 3: La práctica aburrida que salvó el día (drenar nodos malos)
Una carga de larga ejecución comenzó a fallar intermitentemente, pero solo a gran escala.
Parecía un bug de aplicación: colgamientos aleatorios, timeouts MPI ocasionales y ralentizaciones que desaparecían al re-ejecutar.
El dashboard de salud del clúster estaba verde. Por supuesto que lo estaba.
El equipo de operaciones tenía una práctica aburrida: rastreaban “nodos sospechosos” basados en contadores de bajo nivel,
no solo en fallas duras. Un nodo que registraba errores recurrentes de CQ de NIC o reconexiones de sistema de archivos entraba en una lista de vigilancia.
Tras un umbral, se drenaba del planificador y se probaba offline.
Durante el incidente, mapearon los rangos MPI más lentos a hosts y encontraron un patrón:
un pequeño conjunto de nodos repetidamente alojaba rezagados. Esos nodos no tenían errores dramáticos—solo advertencias pequeñas y frecuentes.
Suficiente para ralentizar un rango. Suficiente para frenar a miles.
Drenaron los nodos, re-ejecutaron la carga y el “bug de la aplicación” desapareció.
Más tarde se reemplazó hardware. El equipo de ciencia obtuvo sus resultados a tiempo.
La práctica no fue ingeniosa. Fue disciplinada.
Errores comunes: síntomas → causa raíz → solución
Las fallas de escalado se repiten porque se parecen desde lejos. Aquí están los clásicos, escritos en el
formato que realmente necesitas durante un incendio.
1) Síntoma: agregar nodos hace que el trabajo sea más lento
Causa raíz: Estás haciendo strong-scaling más allá del punto donde la comunicación y sincronización dominan; o introdujiste una ruta serializada global (I/O por rango 0, barreras, locks).
Solución: Reduce colectivas globales, solapa comunicación con cómputo, usa reducciones jerárquicas y mide tiempo en llamadas MPI. Para en la rodilla de la curva.
2) Síntoma: el trabajo “se cuelga” al inicio o al final
Causa raíz: Tormenta de metadatos: miles de rangos haciendo stat/open/unlink en el mismo directorio, o contención en entornos Python/ módulos compartidos.
Solución: Prepara el software localmente, usa caches compartidos por nodo, evita creación de archivos por rango, empaqueta salidas y distribuye árboles de directorio. Trata los metadatos como recurso escaso.
3) Síntoma: paradas periódicas de varios minutos durante cómputo en estado estable
Causa raíz: Ráfagas de checkpoint o eventos de recuperación del sistema de archivos en segundo plano; o vecinos ruidosos saturando OSTs/MDTs compartidos.
Solución: Escalonar checkpoints, usar burst buffers, afinar striping según tamaño de archivo y coordinar ventanas de checkpoint a nivel de clúster para trabajos gigantes.
4) Síntoma: solo algunas ejecuciones son lentas; re-ejecutarlas “lo arregla”
Causa raíz: Problemas de cola: un único nodo degradado, errores en puerto de switch, colocación desequilibrada o un OST más caliente que otros.
Solución: Identifica rangos/hosts outliers; drena nodos sospechosos; aplica colocación consciente de topología; reequilibra destinos del sistema de archivos.
5) Síntoma: alta utilización de CPU pero poco progreso
Causa raíz: Spin-waiting, contención de locks o polling agresivo en la pila MPI; a veces una variable de entorno mal puesta provoca polling agresivo.
Solución: Perfila con perf y resúmenes de strace; ajusta settings de progreso MPI; reduce compartición de locks; revisa pinning de hilos.
6) Síntoma: alto iowait en nodos de cómputo durante la fase de “cómputo”
Causa raíz: E/S oculta: paginación, logging, llamadas de metadatos o lectura repetida de archivos de configuración compartidos.
Solución: Elimina swap, bufferiza logs, cachea configuraciones en memoria y reduce llamadas al sistema de archivos en el bucle caliente.
7) Síntoma: la red parece bien, pero el tiempo MPI es enorme
Causa raíz: Desajuste en el algoritmo de colectiva, congestión por topología o tamaños de mensaje que activan protocolos desfavorables.
Solución: Usa perfilado MPI para encontrar la llamada; prueba algoritmos de colectiva alternativos (si tu MPI lo soporta); usa colocación consciente de topología; reduce la frecuencia de all-to-all.
Listas de verificación / plan paso a paso
Checklist A: Cuando un trabajo grande escala mal (primera hora)
- Obtén dos puntos de datos: una ejecución “buena” y una “mala” con la misma entrada y build.
- Confirma la colocación de nodos y si la asignación está fragmentada.
- Desglose del tiempo: cómputo vs MPI vs E/S vs “otro”. Si no puedes desglosarlo, añade instrumentación mínima.
- Encuentra los rangos más lentos y mapea a hosts.
- Revisa esos hosts por throttling, swap, errores de NIC, reconexiones del sistema de archivos.
- Busca tormentas de metadatos: cuentas de open/stat/unlink, registros por rango, archivos temporales.
- Revisa dependencias de servicios compartidos: DNS/LDAP, descargas de contenedores, servidores de licencia.
- Haz un cambio a la vez. Los errores de escalado aman las variables confusas.
Checklist B: Sanidad de almacenamiento para cargas HPC
- Mide el conteo de archivos y el layout de directorios antes de ejecutar a escala.
- Empareja el conteo de stripe al tamaño de archivo y patrón de acceso (streaming vs I/O pequeño aleatorio).
- Evita creación de archivos por rango en directorios compartidos.
- Escribe menos archivos y más grandes; agrupa operaciones de metadatos.
- Escalona checkpoints; no dejes que 10.000 rangos hagan fsync a la vez salvo que disfrutes del caos.
- Monitorea operaciones MDT y utilización de OST, no solo “ancho de banda total”.
Checklist C: Sanidad de red y MPI
- Mide tiempo en llamadas MPI (no solo tiempo total de ejecución).
- Identifica hotspots de colectivas (Allreduce, Alltoall) y su frecuencia.
- Revisa contadores de la red por congestión y errores; aísla a nodos vs sistémico.
- Asegura que el pinning de rangos/hilos sea correcto; errores NUMA pueden hacerse pasar por problemas de red.
- Usa colocación consciente de topología para trabajos grandes; evita abarcar islas salvo que debas.
Checklist D: Operaciones aburridas que previenen “lentitud misteriosa”
- Drena nodos con errores corregibles recurrentes o advertencias de NIC, no solo fallas duras.
- Mantén firmware y drivers consistentes en la flota; la heterogeneidad engendra heisenbugs.
- Fija y aplica valores por defecto sensatos para módulos de entorno (conteos de hilos, pinning, librerías de I/O).
- Ejecuta microbenchmarks regulares y automáticos para red y sistema de archivos para establecer líneas base.
Preguntas frecuentes
1) ¿Por qué empeora el rendimiento cuando agrego nodos?
Porque estás pagando un costo de coordinación creciente (comunicación, sincronización, contención de metadatos) que supera tus ahorros de cómputo.
El strong scaling tiene un límite; encuéntralo y deja de fingir que no existe.
2) ¿Cómo sé si estoy limitado por la red o solo desequilibrado?
Si el tiempo MPI es alto y unos pocos rangos son consistentemente más lentos, a menudo es desequilibrio o un nodo lento.
Si todos los rangos pasan tiempo similar en colectivas y los contadores de la red muestran congestión, es la red/topología.
3) ¿Es el sistema de archivos paralelo “lento” o mi aplicación hace algo tonto?
Cuenta operaciones de metadatos y E/S pequeñas. Si creas millones de archivos, stat-eas las mismas rutas repetidamente
o escribes fragmentos pequeños con fsync, harás que cualquier sistema de archivos parezca lento.
4) ¿Cuál es la forma más rápida de detectar una tormenta de metadatos?
Busca cuentas masivas de open/stat/getattr y quejas de usuarios sobre retrasos en arranque/finalización.
En Lustre, estadísticas de cliente y md_stats de MDT son tu sistema de alerta temprana.
5) ¿Por qué las colectivas MPI se vuelven un precipicio a escala?
Muchas colectivas tienen costos que crecen con el número de rangos, el tamaño de mensaje y la topología.
También son sensibles a la latencia de cola: un participante lento ralentiza toda la operación.
6) ¿Deberíamos siempre aumentar el striping de Lustre para obtener más ancho de banda?
No. Striping amplio puede ayudar I/O secuencial grande, pero puede fallar para muchos archivos medianos, patrones mixtos de acceso
o cuando amplifica la contención y la latencia de cola. Mide y ajusta al workload.
7) ¿Cuál es el “error tonto” más común que ves en aplicaciones HPC?
Registros por rango y archivos temporales por rango en un directorio compartido, especialmente en arranque y apagado.
Es el equivalente operacional a que todos intenten salir por una única puerta.
8) ¿Cómo lidiar con problemas que “solo fallan a escala”?
Trátalo como un incidente SRE: reproduce en dos tamaños, aísla fases, identifica rangos/hosts outliers y correlaciona con contadores del sistema.
Luego elimina una variable a la vez hasta que el precipicio desaparezca.
9) ¿Qué es más importante: rendimiento pico o predictibilidad?
En sistemas compartidos de producción, la predictibilidad gana. Un trabajo un poco más lento pero estable ahorra más horas-nodo que un trabajo “rápido”
que ocasionalmente explota en reintentos y reenvíos.
Conclusión: próximos pasos prácticos
Las supercomputadoras no fallan de formas exóticas. Fallan en versiones ampliadas de errores cotidianos:
una vía serializada, una tormenta de operaciones de sistema de archivos pequeñas, un nodo enfermo arrastrando una colectiva, una característica de depuración “temporal”
que se vuelve un impuesto permanente.
Próximos pasos que realmente mueven la aguja:
- Instrumenta tu aplicación con temporización por fase y por rango para que puedas ver desequilibrio y esperas.
- Adopta la guía rápida de diagnóstico y prácticala en días sin incidentes, cuando puedas pensar.
- Arregla los patrones de archivos antes de intentar arreglar sistemas de archivos: menos archivos, menos stats, menos fsyncs, agregación más inteligente.
- Haz explícita la topología y la colocación para trabajos grandes; no lo dejes a la ruleta del planificador.
- Drena nodos sospechosos agresivamente; una NIC defectuosa puede convertir “escalado” en “sufrimiento”.
Llevar problemas de escalado a la luna es impresionante. Hacerlo con corrección aburrida es como mantienes las luces encendidas.