Obsługa awarii w klastrach AI: co naprawdę zawodzi i jak to naprawić

Trening rozproszony to jedyne obciążenie, przy którym awarie sprzętu nie są rzadką uciążliwością — są podatkiem operacyjnym płaconym nieustannie. Opublikowana przez Meta analiza powdrożeniowa Llama 3.1 405B odnotowuje 419 nieoczekiwanych przerw w ciągu 54 dni na klastrze liczącym 16,384 GPU: jedno zdarzenie co trzy godziny, przy czym mniej więcej połowa przypada na usterki GPU i HBM. Tak wygląda codzienność pracy tysięcy intensywnie obciążonych GPU.

Większość klientów Kentino nigdy nie zobaczy takich liczb. Jednowęzłowe dostrajanie na 8 GPU jest statystycznie spokojne. Ale tryby awarii, narzędzia diagnostyczne i wzorce odzyskiwania są te same. Ten artykuł to uczciwy katalog: co się psuje, jak to zauważyć, co z tym zrobić i gdzie nakład pracy inżynierskiej naprawdę się opłaca w naszej skali.

Rzeczywiste tryby awarii

Liczą się dwie kategorie — zdarzenia sprzętowe (GPU, zasilacz, karta sieciowa, dysk robią coś fizycznego) oraz zdarzenia programowe (CUDA, NCCL, framework lub system operacyjny źle reagują na zakłócenie). Poniżej z grubsza w kolejności częstotliwości występowania na wielokartowej stacji roboczej lub w małym klastrze.

Błędy XID GPU

Źródłem prawdy są logi jądra (dmesg, journalctl -k). NVIDIA zapisuje wiersz XID przy każdej usterce GPU. Te, które spotyka się naprawdę:

XID Znaczenie Co to naprawdę oznacza
13 Graphics Engine Exception Błąd aplikacji, niedozwolony dostęp do pamięci — zwykle CUDA OOM
31 Błąd strony pamięci GPU Błąd aplikacji lub sterownika, sporadycznie wadliwy VRAM
43 Przerwane przetwarzanie Problem po stronie aplikacji, GPU jest sprawne
48 Dwubitowy błąd ECC Sprzęt. Komórka pamięci padła, GPU należy wycofać
63 Wycofywanie stron ECC / oczekujące remapowanie wierszy Sprzęt się degraduje. Zaplanować wymianę
74 Błąd NVLink Usterka kabla, risera lub płyty
79 GPU zniknęło z magistrali Zasilanie, PCIe, riser lub wyłączenie termiczne
92 Wysoka częstość jednobitowych błędów ECC Sprzęt się degraduje
94 Opanowany błąd ECC (klasa Hopper) Jedno obciążenie ubite, GPU pracuje dalej
119 Przekroczenie czasu GSP RPC Problem sterownika/firmware, często usuwany restartem

Dwie uwagi z praktyki:

  • To przy XID 79 klienci dzwonią w panice. „GPU zniknęło”. W konstrukcji z 4 lub 8 kartami na riserach XID 79 to niemal zawsze problem risera PCIe, złącze zasilania poluzowane przez cykle termiczne albo wyłączenie z powodu temperatury — a nie martwe GPU. Przed RMA warto przepiąć, poprawić okablowanie i przetestować ponownie.
  • XID 48 i 63 są realne. Defekty ECC narastają przez miesiące na mocno eksploatowanych kartach. GPU automatycznie wycofuje strony, dopóki nie wyczerpią się zapasowe wiersze. Potem karta nie nadaje się już do treningu; większość operatorów ją wymienia.

Brak pamięci CUDA w trakcie przebiegu

Najczęstsza awaria treningu na naszym sprzęcie i niemal zawsze wina operatora, a nie sprzętu. Typowy scenariusz: trening idzie gładko przez 200 kroków, po czym kończy się błędem CUDA error: out of memory. Przyczyną zwykle jest:

  1. Pamięć aktywacji rośnie wraz z długością sekwencji — dłuższe próbki w późniejszej części epoki rozsadzają budżet.
  2. Równoległy proces na tym samym GPU. nvidia-smi pokazuje dwa PID-y; jeden miał zostać ubity, a nie został.
  3. Fragmentacja pamięci. Alokator cache'ujący PyTorcha odmawia przydzielenia dużego ciągłego bloku nawet przy wystarczającej ilości wolnej pamięci. Rozwiązanie: PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True.

Podwojenie GPU nie pomoże. Właściwą odpowiedzią jest zmniejszenie mikrobatcha, włączenie gradient checkpointingu albo shardowanie optymalizatora (zob. K02).

Przekroczenia czasu NCCL i zakłócenia sieci

Kolektywy NCCL (all_reduce, all_gather, reduce_scatter) są synchroniczne dla wszystkich rang. Jeśli jedna ranga się zatnie — wadliwa karta sieciowa, przeciążony switch, czkawka planisty jądra, jedno wolne GPU — każda pozostała czeka na kolejnym kolektywie i całe zadanie staje. Bez asynchronicznej obsługi błędów zatrzymanie jest ciche; zadanie sprawia wrażenie „zawieszonego”, dopóki nie zadziała watchdog (domyślnie 30 minut).

Lekarstwem jest jedna zmienna środowiskowa:

export TORCH_NCCL_ASYNC_ERROR_HANDLING=1
export TORCH_NCCL_TRACE_BUFFER_SIZE=20000  # do analizy powykonawczej

PyTorch przerywa wówczas działanie sygnałem SIGABRT przy kolektywie, który przekroczył czas. W połączeniu z torchelastic zadanie wznawia się od ostatniego punktu kontrolnego. Uwaga: starsza zmienna NCCL_ASYNC_ERROR_HANDLING jest wycofana.

Odłączenie węzła i awarie zasilaczy

W klastrach wielowęzłowych węzeł może odpaść wskutek resetu karty sieciowej, migotania portu switcha, kernel panic, zadziałania OOM-killera lub zdarzenia zasilania. Wykrywanie wygląda tak samo jak przy przekroczeniu czasu NCCL. W jednowęzłowych konstrukcjach z 8 GPU — czyli u większości naszych klientów — ta kategoria nie występuje.

Padnięty zasilacz to twarda awaria. W serwerze z 8 GPU i dwoma zasilaczami ATX w konfiguracji split-rail awaria zasilacza nie oznacza redundancji. Zasilacz A zasila GPU 0–3, zasilacz B zasila GPU 4–7. Po utracie zasilacza B cztery GPU znikają z błędem XID 79 w ciągu milisekund. Odzyskanie oznacza fizyczną wymianę. Prawdziwa redundancja wymaga jednostek CRPS w układzie 1+1 hot-swap, a to konstrukcja serwerowa, nie stacja robocza na konsumenckich GPU.

Błędy zapisu podczas tworzenia punktu kontrolnego

Rzadsze, ale bolesne. Zadanie pracuje dziesięć godzin, dochodzi do punktu kontrolnego i zapis się nie udaje, bo serwer NFS jest pełny, lokalny NVMe przekroczył swój limit DWPD i przechodzi w tryb tylko do odczytu, osiągnięto limit i-węzłów albo zmieniły się uprawnienia. Szkody są proporcjonalne do odstępu między punktami kontrolnymi; jeśli problem wychodzi na jaw dopiero przy następnej próbie, można stracić godzinę lub więcej.

Powolne wycieki ECC

Cichy zabójca. GPU zaczyna zgłaszać XID 92 (jednobitowy błąd ECC) raz w tygodniu, potem codziennie, potem co godzinę. Każde zdarzenie jest „opanowane” i zadanie pracuje dalej, ale dokładność dryfuje, a strata treningowa nabiera powolnego trendu wzrostowego. Zanim ktokolwiek to zauważy, wycofane są setki stron, a karta zmierza ku XID 48. Właśnie dlatego sekcja o monitoringu znaczy więcej niż sekcja o odzyskiwaniu.

Wykrywanie — co obserwować

Trzy warstwy: poziom jądra (wiersze XID w dmesg), poziom producenta GPU (eksporter DCGM do Prometheusa, dcgmi diag do aktywnych kontroli) oraz poziom frameworka (watchdog PyTorcha, bufor śladu NCCL, alerty o stracie i przepustowości).

Alerty, które mają znaczenie:

  • Dowolny wiersz XID 48 / 63 / 79 / 92 w dmesg → wezwanie dyżurnego
  • Temperatura GPU > 85 °C przez ponad 5 minut → wezwanie dyżurnego
  • Rosnący licznik ulotnych błędów ECC → zgłoszenie, nie wezwanie
  • Niezerowy dcgm_thermal_violation w DCGM → problem z chłodzeniem, sprawdzić przepływ powietrza
  • Strata treningowa nie maleje przez >100 kroków → warto się przyjrzeć

Przykłady prawdziwych logów awarii

Oto co widać w journalctl -k, gdy zgłoszony zostaje XID 79 (RTX 5090, kabel risera poluzowany przez cykle termiczne):

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.

A tak wygląda przekroczenie czasu NCCL, w skrócie:

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

Zgłasza to ranga 3, ale ranga 3 prawie nigdy nie jest faktycznym problemem. Wolną rangą jest ta, która nie dotarła. Bufor śladu NCCL pokazuje, które rangi zablokowały się na którym wywołaniu — i tak właśnie znajduje się prawdziwego winowajcę.

Wzorce odzyskiwania

Punkty kontrolne na tyle często, by restart był tani

Dla dostrajania modelu 7B na 8× RTX 5090 z punktami kontrolnymi na lokalnym NVMe: ~14 GB zapisu przy ~3 GB/s ≈ 5 s na punkt kontrolny, co 30 minut daje 0.3% narzutu, a w najgorszym razie traci się 15 minut. Dla shardowanego punktu kontrolnego FSDP modelu 70B na tej samej maszynie: ~140 GB rozłożone równolegle na 8 GPU, narzut podobny. Tanio, warto to robić.

Pełny punkt kontrolny pretreningu Llama-70B na pamięci sieciowej zajmuje ~520 GB i może trwać ponad 20 minut; to właśnie tam firmy klasy Meta wprowadzają asynchroniczne, warstwowe punkty kontrolne (szybki zapis lokalny, powolne przelewanie na trwały nośnik). W skali Kentino: punkt kontrolny co 15–30 minut na lokalny NVMe, synchronizacja na NAS po zakończeniu przebiegu. Wszystko bardziej wyszukane to przeinżynierowanie.

Automatyczny restart z torchelastic

torchrun obsługuje trening elastyczny od razu po instalacji:

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

Przy TORCH_NCCL_ASYNC_ERROR_HANDLING=1 łańcuch zdarzeń wygląda tak: kolektyw NCCL zawiesza się → watchdog PyTorcha zgłasza błąd → proces przerywa działanie sygnałem SIGABRT → torchelastic ubija siostrzane rangi i wznawia z latest_checkpoint.pt. Cała sekwencja trwa zwykle 60–120 sekund. Chwilowe zakłócenia zostają przetrzymane. Trwała usterka (GPU poszło w XID 79) zużywa budżet --max-restarts, po czym do akcji musi wkroczyć człowiek.

Praktyka operacyjna

Największy wpływ na koszt awarii ma nie kod odzyskiwania, lecz to, co robi się przed startem zadania.

Kontrole przedstartowe

Przed uruchomieniem czegokolwiek, co potrwa dłużej niż kilka godzin, warto wykonać sekwencję walidacyjną:

# 1. Test obciążeniowy każdego GPU — wyłapuje ciche problemy termiczne/ECC
gpu-burn 600                        # 10 minut na GPU przy pełnym obciążeniu

# 2. Diagnostyka DCGM — znajduje utajone usterki sprzętowe
sudo dcgmi diag -r 3                # poziom 3 = dokładny, ~15 min

# 3. Test tkaniny NCCL — sprawdza przepustowość między GPU w maszynie
mpirun -np 8 ./build/all_reduce_perf -b 8 -e 1G -f 2 -g 1

# 4. Próbny przebieg PyTorcha — jeden krok, pełny batch, wszystkie rangi
torchrun --nproc-per-node=8 dryrun.py
Kontrola Co wyłapuje
gpu-burn Throttling termiczny, ciche błędy ECC ujawniające się tylko pod obciążeniem
dcgmi diag Zawężenie szerokości łącza PCIe, problemy z zasilaniem, błędy pamięci, NVLink
nccl-tests Wadliwy riser, wolna linia PCIe, uszkodzony mostek NVLink, źle skonfigurowany switch
próbny przebieg OOM, błędy w kodzie, zawieszenia dataloadera, zły tokenizer

Na sprawnym serwerze z 8× RTX 5090 all_reduce_perf powinien osiągać przepustowość magistrali rzędu 50–80 GB/s, zależnie od topologii PCIe. Wynik wyraźnie niższy oznacza problem z riserem lub topologią — trzeba go usunąć przed treningiem. W ramach kontroli jakości przed wysyłką uruchamiamy gpu-burn przez pełną godzinę na każdej konstrukcji opuszczającej Kentino.

Uwaga na powolne wycieki

Prawdziwe bazy kodu kumulują pamięć: hook logujący trzyma referencję do tensora, ścieżka wyjątku zapomina wyczyścić bufor, scheduler LR gubi domknięcie. Efektem jest OOM na kroku 5000 przebiegu liczącego 10000 kroków. Najtańsze zabezpieczenie: wypisywanie torch.cuda.memory_allocated() co N kroków do logu treningu. Jeśli wartość rośnie, nie powinna.

Realia statystyczne w skali Kentino

Tu właśnie liczy się uczciwość wobec skali. Współczynniki awarii skalują się z GPU-godzinami; duże klastry psują się bez przerwy, bo mają wiele GPU pracujących przez wiele godzin.

Konfiguracja GPU-godziny/miesiąc Oczekiwane zdarzenia sprzętowe/miesiąc
Pojedyncza stacja robocza, 4 GPU 2,880 ~0.05 — czyli jedno raz na 1–2 lata
Pojedynczy serwer, 8 GPU 5,760 ~0.1 — raz w roku przy intensywnym użyciu
Mały klaster, 32 GPU 23,040 ~0.5 — raz na 2 miesiące
Mały klaster, 32 GPU 24/7 Pełny cykl pracy ~1/miesiąc
Hiperskala, 16,384 GPU ~12M 232/miesiąc (Meta Llama 3)

Szacunki skalibrowane względem danych Meta (jedna awaria na ~50,000 zaobserwowanych GPU-godzin). Rzeczywiste liczby zależą od modelu GPU — konsumenckie karty 4090 i 5090 na riserach psują się częściej niż datacenterowe L40s we własnych obudowach, głównie z powodu zużycia PCIe i złączy zasilania.

Wniosek: w skali jednowęzłowej z 8 GPU należy spodziewać się jednego zdarzenia sprzętowego na rok intensywnego użycia, a nie na tydzień. Większość dostrajań kończy się bez żadnego. Klienci, którzy je widują, prowadzą trening w trybie ciągłym, a dominującym trybem awarii jest strona risera i zasilacza, nie krzem GPU.

Koszt restartu

Na koszt restartu składa się utracony czas treningu plus czas inżyniera na diagnostykę. Przy konstrukcji z 8× RTX 5090 i amortyzacji rzędu, powiedzmy, 300 €/dzień dodatkowe 30 minut kosztuje 6 €. Czas inżyniera na diagnozę, przepięcie kabla i ponowne uruchomienie to od jednej do trzech godzin. Strata mocy obliczeniowej jest błędem zaokrąglenia; kosztem jest praca ludzka. Dlatego właściwą inwestycją są monitoring i kontrole przedstartowe, a nie egzotyczna infrastruktura odzyskiwania.

Większość materiałów o obsłudze awarii w sieci pisana jest dla poziomu hiperskali. W skali Kentino to w dużej części przeinżynierowanie. Zasada 80/20 brzmi: monitorować logi jądra, zapisywać punkty kontrolne na lokalny NVMe, ustawić TORCH_NCCL_ASYNC_ERROR_HANDLING=1 i uruchamiać gpu-burn przed dużymi zadaniami.

Co zrobić dalej

Dla osób prowadzących wielokartową maszynę w skali Kentino konkretne działania to:

  1. Uruchomić eksporter DCGM i minimalny alert Prometheusa na błędy ECC i przekroczenia termiczne. Pół dnia pracy; wyłapuje 80% powoli narastających problemów sprzętowych.
  2. Dodać TORCH_NCCL_ASYNC_ERROR_HANDLING=1 oraz --max-restarts=3 do skryptu uruchomieniowego jeszcze dziś. Zero wysiłku, a zapobiega nocnemu zawieszeniu.
  3. Dobrać odstęp między punktami kontrolnymi do długości zadania. Poniżej 2 godzin: nie ma potrzeby. 2–24 godziny: co 30 minut na lokalny NVMe. Wiele dni: co 15 minut z okresową synchronizacją na trwały nośnik.
  4. Uruchomić gpu-burn i dcgmi diag -r 3 po dostawie, przed pierwszym prawdziwym obciążeniem. Wyłapuje karty martwe od początku i uszkodzenia transportowe. Powtarzać kwartalnie.
  5. Przeczytać artykuły o riserach i zasilaczach, zanim obwini się GPU. W serwerach na konsumenckich GPU riser i szyna zasilacza są źródłem awarii dwa razy częściej niż rdzeń GPU.

Artykuły powiązane: K02 (trening rozproszony i formaty punktów kontrolnych), K04 (pamięć masowa klastra), N06 (analiza opóźnień).


To część Kentino Wiki, serii referencyjnej o obliczeniach AI, robotyce i systemach, które je łączą. Komentarze i sprostowania prosimy kierować na adres info@kentino.com.