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:
- A memória de ativações cresce com o comprimento da sequência — amostras mais longas, mais à frente na época, rebentam o orçamento.
-
Um processo vizinho na mesma GPU. O
nvidia-smimostra dois PID; um deles devia ter sido terminado e não foi. -
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 / 92no 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_violationdiferente 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:
- 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.
-
Acrescente hoje
TORCH_NCCL_ASYNC_ERROR_HANDLING=1e--max-restarts=3ao seu script de arranque. Esforço zero, evita o bloqueio durante a noite. - 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.
-
Corra o
gpu-burne odcgmi diag -r 3após a entrega, antes da primeira carga de trabalho real. Apanha placas mortas à chegada e danos de transporte. Repita trimestralmente. - 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.