Gestão de falhas em clusters de IA: o que avaria realmente e como recuperar

O treino distribuído é a única carga de trabalho em que as falhas de hardware não são um contratempo raro — são um imposto operacional pago continuamente. A análise publicada pela Meta sobre o Llama 3.1 405B regista 419 interrupções inesperadas em 54 dias num cluster de 16,384 GPU: um evento a cada três horas, com as falhas de GPU e de HBM a responderem por cerca de metade. É esta a experiência em regime permanente de quem põe milhares de GPU a trabalhar no limite.

A maioria dos clientes da Kentino nunca verá números destes. Os afinamentos num único nó de 8 GPU são estatisticamente tranquilos. Mas os modos de falha, as ferramentas de diagnóstico e os padrões de recuperação são os mesmos. Este artigo é o catálogo honesto: o que falha, como se dá por isso, o que fazer a seguir e onde o esforço de engenharia compensa realmente à nossa escala.

Os modos de falha reais

Interessam duas categorias — eventos de hardware (GPU, fonte de alimentação, NIC ou disco fazem algo físico) e eventos de software (CUDA, NCCL, a framework ou o sistema operativo reagem mal a um transitório). Abaixo, por ordem aproximada da frequência com que cada um ataca numa estação de trabalho multi-GPU ou num pequeno cluster.

Erros XID da GPU

Os registos do kernel (dmesg, journalctl -k) são a fonte de verdade. A NVIDIA emite uma linha XID em qualquer falha de GPU. As que realmente se veem:

XID Significado O que significa na prática
13 Graphics Engine Exception Erro da aplicação, acesso ilegal à memória — normalmente CUDA OOM
31 Falha de página na memória da GPU Erro da aplicação ou do driver, por vezes VRAM defeituosa
43 Processamento interrompido Problema do lado da aplicação, a GPU está bem
48 Erro ECC de duplo bit Hardware. A célula de memória morreu, a GPU deve ser retirada
63 Retirada de páginas ECC / remapeamento de linhas pendente Hardware a degradar-se. Agende a substituição
74 Erro de NVLink Falha de cabo, de riser ou da placa
79 A GPU desapareceu do barramento Alimentação, PCIe, riser ou corte térmico
92 Taxa elevada de erros ECC de bit único Hardware a degradar-se
94 Erro ECC contido (classe Hopper) Uma carga de trabalho é terminada, a GPU continua a funcionar
119 Timeout de RPC do GSP Problema de driver/firmware, muitas vezes resolvido com um reinício

Duas notas da experiência:

  • O XID 79 é aquele que leva os clientes a telefonar em pânico. «A GPU desapareceu.» Numa montagem de 4× ou 8× com risers, o XID 79 é quase sempre um problema de riser PCIe, um conector de alimentação que se soltou com o ciclo térmico ou um encerramento por temperatura — e não uma GPU morta. Volte a encaixar, a passar os cabos e a testar antes de pedir RMA.
  • Os XID 48 e 63 são a sério. Os defeitos de ECC vão aparecendo ao longo de meses em placas muito usadas. A GPU retira páginas automaticamente até esgotar as linhas de reserva. A partir daí, a placa deixa de ser segura para treino; a maioria dos operadores substitui-a.

CUDA out-of-memory a meio da execução

É a falha de treino mais frequente no nosso hardware e quase sempre culpa do operador, não da máquina. Padrão típico: o treino corre bem durante 200 passos e depois estoira com CUDA error: out of memory. A causa costuma ser:

  1. A memória de ativações cresce com o comprimento da sequência — amostras mais longas, mais à frente na época, rebentam o orçamento.
  2. Um processo vizinho na mesma GPU. O nvidia-smi mostra dois PID; um deles devia ter sido terminado e não foi.
  3. Fragmentação de memória. O alocador de cache do PyTorch recusa um bloco contíguo grande mesmo havendo memória livre suficiente. Solução: PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True.

Duplicar a GPU não ajuda. A resposta certa é reduzir o tamanho do micro-lote, ativar o gradient checkpointing ou fazer sharding do otimizador (ver K02).

Timeouts de NCCL e falhas de rede

As coletivas NCCL (all_reduce, all_gather, reduce_scatter) são síncronas em todos os ranks. Se um rank bloquear — NIC avariada, switch congestionado, soluço do escalonador do kernel, uma GPU mais lenta —, todos os outros ficam à espera na coletiva seguinte e o trabalho inteiro para. Sem tratamento assíncrono de erros, o bloqueio é silencioso; o trabalho parece «pendurado» até disparar o timeout do watchdog (por omissão, 30 minutos).

A solução é uma variável de ambiente:

export TORCH_NCCL_ASYNC_ERROR_HANDLING=1
export TORCH_NCCL_TRACE_BUFFER_SIZE=20000  # para análise posterior

O PyTorch aborta então com SIGABRT numa coletiva que excedeu o tempo. Em conjunto com o torchelastic, o trabalho reinicia a partir do último checkpoint. Nota: a antiga NCCL_ASYNC_ERROR_HANDLING está descontinuada.

Perda de nós e falhas de fonte de alimentação

Em clusters multinó, um nó pode cair por reinício da NIC, oscilação da porta do switch, kernel panic, atuação do OOM-killer ou um evento elétrico. A deteção é igual à do timeout de NCCL. Em máquinas de nó único com 8 GPU — o caso da maioria dos nossos clientes —, esta categoria não se aplica.

Uma fonte de alimentação morta é uma falha irrecuperável. Num servidor de 8 GPU com duas fontes ATX em configuração split-rail, a falha de uma fonte não equivale a redundância. A fonte A alimenta as GPU 0–3 e a fonte B as GPU 4–7. Perca a fonte B e quatro GPU desaparecem com XID 79 em milissegundos. A recuperação passa pela substituição física. Redundância a sério exige unidades CRPS em 1+1 hot-swap, o que é uma montagem de classe servidor e não uma estação de trabalho com GPU de consumo.

Falhas de escrita no armazenamento durante o checkpoint

Menos frequentes, mas dolorosas. O trabalho corre dez horas, chega a um checkpoint e a escrita falha porque o servidor NFS está cheio, o NVMe local ultrapassou a sua quota de DWPD e entrou em modo de leitura, atingiu-se um limite de inodes ou mudaram as permissões. O estrago é proporcional ao intervalo entre checkpoints; se só der por isso na tentativa seguinte, pode perder uma hora ou mais.

Fugas lentas de ECC

O assassino silencioso. Uma GPU começa a emitir XID 92 (ECC de bit único) uma vez por semana, depois todos os dias, depois a cada hora. Cada evento é «contido» e o trabalho continua, mas a exatidão vai derivando e a função de perda do treino desenvolve um viés lentamente ascendente. Quando alguém repara, já centenas de páginas foram retiradas e a placa caminha para o XID 48. É por isto que a secção sobre monitorização importa mais do que a secção sobre recuperação.

Deteção — o que vigiar

Três camadas: ao nível do kernel (linhas XID no dmesg), ao nível do fabricante da GPU (exportador DCGM para o Prometheus, dcgmi diag para verificações ativas) e ao nível da framework (watchdog do PyTorch, buffer de traços do NCCL, alertas de perda/débito).

Os alertas que interessam:

  • Qualquer linha XID 48 / 63 / 79 / 92 no dmesg → alerta imediato
  • Temperatura da GPU > 85 °C durante mais de 5 minutos → alerta imediato
  • Contador volátil de erros ECC a subir → ticket, não alerta imediato
  • DCGM dcgm_thermal_violation diferente de zero → problema de arrefecimento, verifique o fluxo de ar
  • Perda de treino sem descer durante >100 passos → vale a pena investigar

Exemplos reais de registos de falha

Eis o que aparece no journalctl -k quando dispara um XID 79 (RTX 5090, cabo riser solto por ciclo térmico):

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.

E eis o aspeto de um timeout de NCCL, de forma abreviada:

[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'

É o rank 3 que reporta, mas o rank 3 quase nunca é o verdadeiro problema. O rank lento é aquele que não chegou. O buffer de traços do NCCL mostra que ranks estavam bloqueados em que chamada — é assim que se encontra o verdadeiro culpado.

Padrões de recuperação

Faça checkpoints com frequência suficiente para que reiniciar seja barato

Para um afinamento de 7B em 8× RTX 5090 com checkpoints em NVMe local: ~14 GB escritos a ~3 GB/s ≈ 5 s por checkpoint; de 30 em 30 minutos, são 0.3% de sobrecarga e, no pior caso, perdem-se 15 minutos. Para um checkpoint FSDP com sharding de um 70B na mesma máquina: ~140 GB distribuídos por 8 GPU em paralelo, com sobrecarga semelhante. É barato, faça-o.

Um checkpoint completo de pré-treino do Llama-70B em armazenamento de rede ronda os ~520 GB e pode demorar mais de 20 minutos; é aí que as operações à escala da Meta introduzem checkpointing assíncrono por camadas (escrita local rápida, drenagem lenta para armazenamento durável). À escala da Kentino: checkpoint de 15 em 15 ou de 30 em 30 minutos para NVMe local e sincronização com o NAS no fim da execução. Qualquer coisa mais elaborada é sobre-engenharia.

Reinício automático com o torchelastic

O torchrun suporta treino elástico de origem:

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

Com TORCH_NCCL_ASYNC_ERROR_HANDLING=1, a cadeia é: a coletiva NCCL bloqueia → o watchdog do PyTorch dispara → o processo aborta com SIGABRT → o torchelastic termina os ranks irmãos e reinicia a partir de latest_checkpoint.pt. A sequência completa demora normalmente 60–120 segundos. As oscilações passageiras são absorvidas. Uma falha permanente (uma GPU em XID 79) consome o orçamento de --max-restarts e aí entra um humano no circuito.

A prática operacional

A maior alavanca sobre o custo das falhas não é o código de recuperação — é o que se faz antes de o trabalho arrancar.

Verificações prévias

Antes de lançar seja o que for que vá correr mais do que umas horas, execute a sequência de validação:

# 1. Teste de esforço por GPU — apanha problemas térmicos/ECC silenciosos
gpu-burn 600                        # 10 minutos por GPU em carga máxima

# 2. Diagnóstico DCGM — encontra falhas latentes de hardware
sudo dcgmi diag -r 3                # nível 3 = exaustivo, ~15 min

# 3. Teste do tecido NCCL — valida a largura de banda entre GPU na máquina
mpirun -np 8 ./build/all_reduce_perf -b 8 -e 1G -f 2 -g 1

# 4. Ensaio do PyTorch — um passo, lote completo, todos os ranks
torchrun --nproc-per-node=8 dryrun.py
Verificação O que apanha
gpu-burn Throttling térmico, erros ECC silenciosos que só surgem em carga
dcgmi diag Regressões na largura do link PCIe, problemas de alimentação, erros de memória, NVLink
nccl-tests Riser defeituoso, via PCIe lenta, ponte NVLink partida, switch mal configurado
ensaio OOM, erros de código, bloqueios do dataloader, tokenizador errado

Num servidor limpo com 8× RTX 5090, o all_reduce_perf deve situar-se na gama de 50–80 GB/s de largura de banda de barramento, conforme a topologia PCIe. Valores bastante abaixo disso indicam um problema de riser ou de topologia — resolva-o antes de treinar. Na Kentino, corremos o gpu-burn durante uma hora inteira como parte do controlo de qualidade pré-expedição de todas as máquinas que saem da casa.

Atenção às fugas lentas

O código real acumula memória: um hook de registo que segura uma referência a um tensor, um caminho de exceção que se esquece de limpar um buffer, um escalonador de LR que deixa fugir uma closure. O resultado é um OOM ao passo 5000 de uma execução de 10000 passos. A mitigação mais barata: imprimir torch.cuda.memory_allocated() de N em N passos no registo de treino. Se estiver a crescer, não devia estar.

A realidade estatística à escala da Kentino

É aqui que ser honesto quanto à dimensão conta. As taxas de falha escalam com as horas-GPU; os grandes clusters falham constantemente porque têm muitas GPU a trabalhar muitas horas.

Configuração Horas-GPU/mês Eventos de hardware esperados/mês
Estação de trabalho única, 4 GPU 2,880 ~0.05 — ou seja, um a cada 1–2 anos
Servidor único, 8 GPU 5,760 ~0.1 — um por ano com uso intenso
Cluster pequeno, 32 GPU 23,040 ~0.5 — um de 2 em 2 meses
Cluster pequeno, 32 GPU 24/7 Ciclo de serviço completo ~1/mês
Hiperescala, 16,384 GPU ~12M 232/mês (Meta Llama 3)

Estimativas calibradas com os dados da Meta (uma falha por cada ~50,000 horas-GPU observadas). Os números reais variam com o modelo de GPU — as 4090 e 5090 de consumo com risers falham mais do que as L40 de centro de dados no seu chassis nativo, sobretudo por desgaste do PCIe e dos conectores de alimentação.

Conclusão: à escala de um nó único com 8 GPU, conte com um evento de hardware por ano de uso intenso, e não por semana. A maioria dos afinamentos termina sem ver nenhum. Os clientes que os veem são os que treinam continuamente, e o modo de falha dominante está do lado do riser e da fonte de alimentação, não do silício da GPU.

Custo de um reinício

O custo de um reinício é o tempo de treino perdido mais o tempo de engenharia de diagnóstico. Numa máquina com 8× RTX 5090 a, digamos, 300 €/dia amortizados, meia hora extra custa 6 €. O tempo de engenharia para diagnosticar, voltar a encaixar um cabo e relançar é de uma a três horas. A perda de computação é um erro de arredondamento; o custo está na mão de obra. É por isso que o investimento certo é em monitorização e verificações prévias, e não em infraestrutura de recuperação exótica.

A maior parte do que se escreve online sobre gestão de falhas é dirigida ao patamar da hiperescala. À escala da Kentino, quase tudo isso é sobre-engenharia. O 80/20 é: vigiar os registos do kernel, fazer checkpoint para NVMe local, definir TORCH_NCCL_ASYNC_ERROR_HANDLING=1 e correr o gpu-burn antes dos trabalhos grandes.

O que fazer a seguir

Se opera uma máquina multi-GPU à escala da Kentino, eis as ações concretas:

  1. Instale o exportador DCGM + um alerta mínimo no Prometheus para erros ECC e violações térmicas. Meio dia de trabalho; apanha 80% dos problemas de hardware de evolução lenta.
  2. Acrescente hoje TORCH_NCCL_ASYNC_ERROR_HANDLING=1 e --max-restarts=3 ao seu script de arranque. Esforço zero, evita o bloqueio durante a noite.
  3. Escolha o intervalo de checkpoint em função da duração do trabalho. Menos de 2 horas: não vale a pena. 2–24 horas: de 30 em 30 minutos para NVMe local. Vários dias: de 15 em 15 minutos, com sincronização periódica para armazenamento durável.
  4. Corra o gpu-burn e o dcgmi diag -r 3 após a entrega, antes da primeira carga de trabalho real. Apanha placas mortas à chegada e danos de transporte. Repita trimestralmente.
  5. Leia os artigos sobre risers e fontes de alimentação antes de culpar a GPU. Em servidores com GPU de consumo, o riser e o barramento da fonte são a origem da falha com o dobro da frequência do próprio chip da GPU.

Artigos complementares: K02 (treino distribuído e formatos de checkpoint), K04 (armazenamento de cluster), N06 (dissecação da latência).


Isto faz parte da Kentino Wiki, uma série de referência sobre computação de IA, robótica e os sistemas que as ligam. Comentários e correções são bem-vindos em info@kentino.com.