Gestión de fallos en clústeres de IA: qué se rompe de verdad y cómo recuperarse

El entrenamiento distribuido es la única carga de trabajo en la que los fallos de hardware no son una molestia esporádica: son un impuesto operativo que se paga de forma continua. El informe publicado por Meta sobre Llama 3.1 405B recoge 419 interrupciones inesperadas en 54 días sobre un clúster de 16,384 GPU: un suceso cada tres horas, con los fallos de GPU y HBM como responsables de aproximadamente la mitad. Esa es la experiencia en régimen permanente de hacer trabajar duro a miles de GPU.

La mayoría de clientes de Kentino nunca verá cifras así. Los ajustes finos de un solo nodo con 8 GPU son estadísticamente tranquilos. Pero los modos de fallo, las herramientas de diagnóstico y los patrones de recuperación son los mismos. Este artículo es el catálogo honesto: qué falla, cómo se detecta, qué hacer al respecto y dónde merece realmente la pena el esfuerzo de ingeniería a nuestra escala.

Los modos de fallo reales

Importan dos categorías: los sucesos de hardware (GPU, fuente de alimentación, NIC o disco hacen algo físico) y los de software (CUDA, NCCL, el framework o el sistema operativo reaccionan mal ante un transitorio). A continuación, en orden aproximado de frecuencia con que muerden en una estación de trabajo multi-GPU o un clúster pequeño.

Errores XID de GPU

Los registros del kernel (dmesg, journalctl -k) son la fuente de verdad. NVIDIA emite una línea XID ante cualquier fallo de GPU. Los que se ven de verdad:

XID Significado Qué significa en realidad
13 Excepción del motor gráfico Error de la aplicación, acceso ilegal a memoria — normalmente OOM de CUDA
31 Fallo de página en la memoria de la GPU Error de la aplicación o del driver, a veces VRAM defectuosa
43 Procesamiento detenido Problema del lado de la aplicación, la GPU está bien
48 Error ECC de doble bit Hardware. La celda de memoria está perdida, la GPU debería retirarse
63 Retirada de páginas ECC / remapeo de filas pendiente Hardware degradándose. Programe la sustitución
74 Error de NVLink Fallo de cable, riser o placa
79 La GPU ha desaparecido del bus Alimentación, PCIe, riser o apagado térmico
92 Alta tasa de errores ECC de un solo bit Hardware degradándose
94 Error ECC contenido (clase Hopper) Se mata una sola carga de trabajo, la GPU sigue funcionando
119 Tiempo de espera agotado en RPC de GSP Problema de driver o firmware, a menudo se resuelve reiniciando

Dos apuntes desde la experiencia:

  • El XID 79 es por el que los clientes llaman en pánico. «La GPU ha desaparecido.» En un montaje de 4× u 8× con risers, el XID 79 es casi siempre un problema del riser PCIe, un conector de alimentación que se ha aflojado con los ciclos térmicos o un apagado térmico, no una GPU muerta. Reasiente, recablea y vuelva a probar antes de tramitar un RMA.
  • Los XID 48 y 63 sí son reales. Los defectos ECC se acumulan a lo largo de los meses en tarjetas muy usadas. La GPU retira páginas automáticamente hasta que se queda sin filas de reserva. A partir de ahí la tarjeta no es segura para entrenar; la mayoría de operadores la sustituye.

Falta de memoria CUDA a mitad de ejecución

Es el fallo de entrenamiento más común en nuestro hardware y casi siempre es culpa del operador, no del equipo. Patrón típico: el entrenamiento va bien durante 200 pasos y entonces falla con CUDA error: out of memory. La causa suele ser:

  1. La memoria de activaciones crece con la longitud de secuencia — las muestras más largas, ya avanzada la época, revientan el presupuesto.
  2. Un proceso vecino en la misma GPU. nvidia-smi muestra dos PID; uno debía haberse matado y no se mató.
  3. Fragmentación de memoria. El asignador con caché de PyTorch rechaza un bloque contiguo grande incluso con memoria libre suficiente. Solución: PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True.

Duplicar la GPU no ayuda. La respuesta correcta es reducir el tamaño de micro-lote, activar el checkpointing de gradientes o fragmentar el optimizador (véase K02).

Tiempos de espera de NCCL y fallos de red

Las colectivas de NCCL (all_reduce, all_gather, reduce_scatter) son síncronas entre todos los rangos. Si un rango se atasca —NIC defectuosa, switch congestionado, hipo del planificador del kernel, una GPU lenta—, todos los demás esperan en la siguiente colectiva y el trabajo entero se bloquea. Sin gestión asíncrona de errores el atasco es silencioso; el trabajo parece «colgado» hasta que salta el vigilante (por defecto, 30 minutos).

La solución es una variable de entorno:

export TORCH_NCCL_ASYNC_ERROR_HANDLING=1
export TORCH_NCCL_TRACE_BUFFER_SIZE=20000  # para el análisis posterior

PyTorch aborta entonces con SIGABRT ante una colectiva que ha agotado su tiempo. Combinado con torchelastic, el trabajo se reinicia desde el último punto de control. Nota: la antigua NCCL_ASYNC_ERROR_HANDLING está obsoleta.

Desconexión de nodos y fallos de fuente de alimentación

En clústeres multinodo, un nodo puede caerse por un reinicio de la NIC, un parpadeo del puerto del switch, un kernel panic, la intervención del OOM-killer o un corte eléctrico. La detección es la misma que en el tiempo de espera de NCCL. En montajes de un solo nodo con 8 GPU —la mayoría de nuestros clientes— esta categoría no aplica.

Una fuente de alimentación muerta es un fallo duro. En un servidor de 8 GPU con fuentes ATX duales en configuración de raíles separados, el fallo de una fuente no equivale a redundancia. La fuente A alimenta las GPU 0–3 y la fuente B las GPU 4–7. Si pierde la fuente B, cuatro GPU desaparecen con un XID 79 en milisegundos. La recuperación exige sustitución física. La redundancia de verdad requiere unidades CRPS en 1+1 con intercambio en caliente, lo que es un montaje de clase servidor, no una estación de trabajo con GPU de consumo.

Fallos de escritura en el almacenamiento durante el punto de control

Menos frecuente, pero doloroso. El trabajo lleva diez horas, llega a un punto de control y la escritura falla porque el servidor NFS está lleno, el NVMe local ha superado su presupuesto de DWPD y entra en modo de solo lectura, se ha alcanzado un límite de inodos o han cambiado los permisos. El daño es proporcional al intervalo entre puntos de control; si solo lo detecta en el siguiente intento, puede perder una hora o más.

Fugas ECC lentas

El asesino silencioso. Una GPU empieza a emitir XID 92 (ECC de un solo bit) una vez por semana, luego a diario, luego cada hora. Cada suceso queda «contenido» y el trabajo continúa, pero la precisión se desvía y la pérdida de entrenamiento desarrolla un sesgo lento al alza. Para cuando alguien se da cuenta, hay cientos de páginas retiradas y la tarjeta va camino del XID 48. Por eso la sección de monitorización importa más que la de recuperación.

Detección: qué vigilar

Tres capas: a nivel de kernel (líneas XID en dmesg), a nivel de fabricante de GPU (exportador DCGM hacia Prometheus, dcgmi diag para comprobaciones activas) y a nivel de framework (vigilante de PyTorch, búfer de trazas de NCCL, alertas de pérdida y rendimiento).

Las alertas que importan:

  • Cualquier línea XID 48 / 63 / 79 / 92 en dmesg → aviso inmediato
  • Temperatura de GPU > 85 °C durante más de 5 minutos → aviso inmediato
  • Contador volátil de errores ECC en aumento → ticket, no aviso
  • DCGM dcgm_thermal_violation distinto de cero → problema de refrigeración, revise el flujo de aire
  • La pérdida de entrenamiento no baja durante >100 pasos → merece una mirada

Ejemplos reales de registros de fallo

Esto es lo que se ve en journalctl -k cuando salta un XID 79 (RTX 5090, cable riser aflojado por ciclos térmicos):

Apr 22 03:14:17 kentino-ai-04 kernel: NVRM: Xid (PCI:0000:c1:00): 79, pid='<unknown>', name=<unknown>, GPU has fallen off the bus.
Apr 22 03:14:17 kentino-ai-04 kernel: NVRM: GPU 0000:c1:00.0: GPU is on Board .
Apr 22 03:14:17 kentino-ai-04 kernel: NVRM: A GPU crash dump has been created. If possible, please run
Apr 22 03:14:17 kentino-ai-04 kernel: NVRM: nvidia-bug-report.sh as root to collect this data before
Apr 22 03:14:17 kentino-ai-04 kernel: NVRM: the NVIDIA kernel module is unloaded.

Así se ve un tiempo de espera agotado de NCCL, abreviado:

[E ProcessGroupNCCL.cpp:475] [Rank 3] Watchdog caught collective operation timeout:
WorkNCCL(SeqNum=842, OpType=ALLREDUCE, NumelIn=268435456, NumelOut=268435456,
Timeout(ms)=1800000) ran for 1800321 milliseconds before timing out.
[E ProcessGroupNCCL.cpp:489] [Rank 3] Some NCCL operations have failed or timed out.
terminate called after throwing an instance of 'std::runtime_error'

Lo informa el rango 3, pero el rango 3 casi nunca es el problema real. El rango lento es el que no llegó. El búfer de trazas de NCCL vuelca qué rangos estaban bloqueados y en qué llamada: así se encuentra al verdadero culpable.

Patrones de recuperación

Haga puntos de control con la frecuencia suficiente para que reiniciar salga barato

Para un ajuste fino de 7B en 8× RTX 5090 con puntos de control en NVMe local: ~14 GB escritos a ~3 GB/s ≈ 5 s por punto de control; cada 30 minutos supone un 0.3 % de sobrecarga y, en el peor caso, se pierden 15 minutos. Para un punto de control FSDP fragmentado de 70B en la misma máquina: ~140 GB repartidos en paralelo entre 8 GPU, con una sobrecarga similar. Es barato, hágalo.

Un punto de control completo de preentrenamiento de Llama-70B sobre almacenamiento en red ocupa ~520 GB y puede llevar más de 20 minutos; ahí es donde las casas de escala Meta introducen puntos de control asíncronos por niveles (escritura local rápida, vaciado lento al almacenamiento duradero). A escala Kentino: punto de control cada 15–30 minutos en NVMe local y sincronización con el NAS al terminar la ejecución. Cualquier cosa más elaborada es sobreingeniería.

Reinicio automático con torchelastic

torchrun admite entrenamiento elástico de serie:

torchrun \
    --nnodes=1:1 \
    --nproc-per-node=8 \
    --max-restarts=3 \
    --rdzv-backend=c10d \
    --rdzv-endpoint=localhost:29500 \
    train.py --checkpoint-dir /mnt/nvme/ckpt

Con TORCH_NCCL_ASYNC_ERROR_HANDLING=1, la cadena es: la colectiva de NCCL se cuelga → el vigilante de PyTorch lanza el error → el proceso aborta con SIGABRT → torchelastic mata los rangos hermanos y reinicia desde latest_checkpoint.pt. La secuencia completa suele llevar entre 60 y 120 segundos. Los parpadeos transitorios se superan sin más. Un fallo permanente (una GPU que se ha ido con XID 79) consume el presupuesto de --max-restarts y entonces entra una persona en el bucle.

La práctica operativa

La mayor palanca sobre el coste de los fallos no es el código de recuperación: es lo que se hace antes de lanzar el trabajo.

Comprobaciones previas

Antes de lanzar cualquier cosa que vaya a durar más de un par de horas, ejecute la secuencia de validación:

# 1. Prueba de esfuerzo por GPU — detecta problemas térmicos/ECC silenciosos
gpu-burn 600                        # 10 minutos por GPU a plena carga

# 2. Diagnóstico DCGM — encuentra fallos de hardware latentes
sudo dcgmi diag -r 3                # nivel 3 = exhaustivo, ~15 min

# 3. Prueba de tejido NCCL — valida el ancho de banda entre GPU de la máquina
mpirun -np 8 ./build/all_reduce_perf -b 8 -e 1G -f 2 -g 1

# 4. Ensayo en seco de PyTorch — un paso, lote completo, todos los rangos
torchrun --nproc-per-node=8 dryrun.py
Comprobación Qué detecta
gpu-burn Estrangulamiento térmico, errores ECC silenciosos que solo aparecen bajo carga
dcgmi diag Regresiones en el ancho del enlace PCIe, problemas de alimentación, errores de memoria, NVLink
nccl-tests Riser defectuoso, carril PCIe lento, puente NVLink roto, switch mal configurado
ensayo en seco OOM, errores de código, bloqueos del cargador de datos, tokenizador equivocado

En un servidor limpio de 8× RTX 5090, all_reduce_perf debería situarse entre 50 y 80 GB/s de ancho de banda de bus según la topología PCIe. Quedarse muy por debajo indica un problema de riser o de topología: resuélvalo antes de entrenar. Ejecutamos gpu-burn durante una hora completa como parte del control de calidad previo al envío en cada equipo que sale de Kentino.

Vigile las fugas lentas

Las bases de código reales acumulan memoria: un enganche de registro retiene una referencia a un tensor, una ruta de excepción se olvida de limpiar un búfer, un planificador de tasa de aprendizaje filtra un cierre. El resultado es un OOM en el paso 5000 de una ejecución de 10000. La mitigación más barata: imprimir torch.cuda.memory_allocated() cada N pasos en el registro de entrenamiento. Si crece, no debería.

La realidad estadística a escala Kentino

Aquí es donde importa ser honesto sobre el tamaño. Las tasas de fallo escalan con las horas-GPU; los clústeres grandes fallan constantemente porque tienen muchas GPU funcionando muchas horas.

Configuración Horas-GPU/mes Sucesos de hardware esperados/mes
Estación de trabajo única, 4 GPU 2,880 ~0.05 — es decir, uno cada 1–2 años
Servidor único, 8 GPU 5,760 ~0.1 — una vez al año con uso intensivo
Clúster pequeño, 32 GPU 23,040 ~0.5 — uno cada 2 meses
Clúster pequeño, 32 GPU 24/7 Ciclo de trabajo completo ~1 al mes
Hiperescala, 16,384 GPU ~12M 232 al mes (Meta Llama 3)

Estimaciones calibradas con los datos de Meta (un fallo por cada ~50,000 horas-GPU observadas). Las cifras reales varían según el modelo de GPU: las 4090 y 5090 de consumo con risers fallan más a menudo que las L40S de centro de datos en su chasis nativo, sobre todo por desgaste del PCIe y del conector de alimentación.

Conclusión: a escala de un solo nodo con 8 GPU, espere un suceso de hardware por año de uso intensivo, no por semana. La mayoría de ajustes finos terminan sin ver ninguno. Los clientes que sí los ven entrenan de forma continua, y el modo de fallo dominante es el lado del riser y la fuente de alimentación, no el silicio de la GPU.

Coste de un reinicio

El coste de un reinicio es el tiempo de entrenamiento perdido más el tiempo de ingeniería dedicado al diagnóstico. En un equipo de 8× RTX 5090 a, digamos, 300 €/día amortizados, media hora extra cuesta 6 €. El tiempo del ingeniero para diagnosticar, reasentar un cable y relanzar es de una a tres horas. La pérdida de cómputo es un error de redondeo; el coste es la mano de obra. Por eso la inversión acertada es la monitorización y las comprobaciones previas, no una infraestructura de recuperación exótica.

La mayor parte del material sobre gestión de fallos que hay en internet está escrito para el nivel de hiperescala. A tamaño Kentino, casi todo es sobreingeniería. El 80/20 es: vigilar los registros del kernel, hacer puntos de control en NVMe local, fijar TORCH_NCCL_ASYNC_ERROR_HANDLING=1 y ejecutar gpu-burn antes de los trabajos grandes.

Qué hacer a continuación

Si opera una máquina multi-GPU a escala Kentino, estas son las acciones concretas:

  1. Monte el exportador DCGM y una alerta mínima en Prometheus sobre errores ECC y violaciones térmicas. Medio día de trabajo; detecta el 80 % de los problemas de hardware que se arrastran lentamente.
  2. Añada hoy mismo TORCH_NCCL_ASYNC_ERROR_HANDLING=1 y --max-restarts=3 a su script de lanzamiento. Esfuerzo cero, evita el cuelgue nocturno.
  3. Elija el intervalo de punto de control según la duración del trabajo. Menos de 2 horas: no se moleste. De 2 a 24 horas: cada 30 minutos en NVMe local. Varios días: cada 15 minutos con sincronización periódica al almacenamiento duradero.
  4. Ejecute gpu-burn y dcgmi diag -r 3 tras la entrega, antes de la primera carga de trabajo real. Detecta tarjetas muertas de fábrica y daños de transporte. Repítalo cada trimestre.
  5. Lea los artículos sobre risers y fuentes de alimentación antes de culpar a la GPU. En servidores con GPU de consumo, el riser y el raíl de la fuente son el origen del fallo el doble de veces que el chip de la GPU.

Artículos relacionados: K02 (entrenamiento distribuido y formatos de punto de control), K04 (almacenamiento de clúster), N06 (análisis de latencia).


Esto forma parte de la Kentino Wiki, una serie de referencia sobre cómputo de IA, robótica y los sistemas que los conectan. Comentarios y correcciones en info@kentino.com.