Incident Library

IL-0480 Samsung SDS · 2026-08-06 (게시일)ai-infra

B300 16장 FSDP 미세 조정이 에포크 끝 체크포인트에서 NCCL 교착으로 세 시간 동안 조용히 멈췄다

Samsung SDS의 엔지니어들은 두 노드에 나뉜 NVIDIA B300 16장에서 FSDP FULL_SHARD로 Qwen3-32B를 전체 미세 조정했다. 데이터 로더는 레코드를 랭크마다 고르게 나눴고, 각 레코드를 토큰화해 2048 토큰 블록으로 묶어 노드 로컬 NVMe 파일에 저장했다. 레코드 길이가 서로 달라 묶은 뒤의 블록 수가 랭크마다 달랐다. 랭크 3이 30,835개로 가장 적었고 랭크 11이 30,888개로 가장 많아 차이가 53블록이었다. 이 차이는 랭크당 작업량의 0.17%여서 다른 지표에는 보이지 않았다.

사전 학습된 모델에서 시작한 실행은 약 5시간 동안 정상으로 돌았다. 그러다 랭크 3이 스텝당 8블록 기준으로 약 7 스텝 먼저 데이터를 다 써서 루프를 빠져나왔다. 랭크 3은 에포크 끝 체크포인트 저장 앞의 dist.barrier()가 낸 all_reduce에 들어갔고, 나머지 15개 랭크는 역전파의 reduce_scatter에 있었다. 랭크들이 같은 순번에서 서로 다른 집합 통신을 기다리게 되어 NCCL이 영원히 멈췄다. GPU 사용률은 100%로 남았고 오류도 없어 세 시간 동안 아무도 알아채지 못했다. 세 시간 뒤 NCCL watchdog이 멈춤을 드러냈다. 에포크 끝에만 체크포인트를 저장하던 때라 약 5시간의 진행도 되살릴 수 없었다. 한 번의 장애로 약 130 GPU·h, 에포크 약 1.5개 분량의 계산을 잃었다.

PyTorch의 Join은 랭크마다 입력 수가 다를 때 집합 통신이 어긋나 멈추는 문제를 막는 기능이다. 그러나 Join은 FSDP를 지원하지 않고, 이번 교착이 난 수동 barrier도 Join이 다루는 범위 밖이었다. 엔지니어들은 학습 루프 전에 각 랭크의 블록 수를 all_reduce MIN으로 전체 최솟값에 맞추는 evenfix를 넣었다. 처음부터 다시 돌린 16 GPU 에포크는 3,854 스텝을 첫 시도에 끝냈고, 에포크 끝 저장도 watchdog이나 교착 흔적 없이 끝났다.

심각도
–
영향 범위
16-GPU B300 fine-tuning run hung for about 3 hours and lost about 5 hours of progress, about 130 GPU·h
영향 사용자
–
지역
–
감지까지
3h
복구까지
–

증상

약 5시간 동안 정상으로 돌던 미세 조정 작업에서, 에포크 끝 체크포인트에 들어가던 3,857 스텝 중 3,850번째 스텝에 GPU 16개가 모두 멈췄다. GPU 사용률은 계속 100%로 나왔지만 처리량은 정확히 0이었고, NCCL watchdog이 세 시간 뒤에야 문제를 드러냈다.

멈추기 전까지 손실은 1.60에서 0.74를 거쳐 약 0.68로 내려가고 있었고, 처리량은 약 53k tok/s였으며 16개 GPU 모두 사용률 100%였다. 멈춘 뒤에도 dmesg에 OOM이 없었고 segfault나 오류도 없었다.

nvidia-smi로 본 보드 전력은 약 190 W로 떨어져 있었다. 랭크 하나는 사용률 0%이고 나머지는 100%였다. 정상 체크포인트에서는 랭크 0만 0%로 떨어지고 약 2분 안에 돌아오는데, 이번에는 모양이 반대였고 회복되지 않았다.

NCCL flight recorder 덤프에서 랭크 3은 에포크 끝 save_checkpoint를 지키는 dist.barrier()의 all_reduce에 들어가 있었다. 나머지 15개 랭크는 역전파의 기울기 집계인 reduce_scatter에서 막혀 있었다. 랭크들이 같은 순번에서 서로 다른 집합 통신을 기다리고 있었다. 멈추기 전까지 처리량이 꾸준히 53k tok/s였고 IB 대역폭도 정상이었으므로 네트워크는 원인이 아니었다.

이 문제는 스모크 테스트로 드러나지 않았다. max_steps=N으로 짧게 돌리면 모든 랭크가 대칭인 루프 본문만 실행하고, 데이터가 가장 적은 랭크가 데이터를 다 쓰기 전에 끝나기 때문이다.

증상 NCCL 타임아웃학습 작업 실패

원인

촉발
데이터가 가장 적은 랭크 3이 다른 랭크보다 약 7 옵티마이저 스텝 먼저 데이터를 다 써서 학습 루프를 빠져나와, 에포크 끝 체크포인트의 barrier에 들어갔다.

감지

NCCL watchdog이 세 시간 뒤에 멈춤을 드러냈다. 엔지니어들은 nvidia-smi로 보드 전력과 랭크별 사용률을 보고 교착의 모양을 확인했고, NCCL flight recorder에서 랭크마다 서로 다른 집합 통신을 기다리는 것을 보고 확정했다.

조치

후속 조치

교훈

분산 학습에서 GPU 사용률은 실제 진행을 보여 주지 않는다. NCCL이 멈춰도 사용률은 100%로 나오므로 보드 전력과 랭크별 사용률의 모양을 봐야 한다. 랭크마다 작업량이 데이터에 따라 달라지는 작업에서는 스모크 테스트를 통과했다고 전체 실행이 안전한 것이 아니다. 실행 전에 불변 조건을 확인해야 한다. 스스로 교착에 빠진 노드는 자기 상태를 알릴 수 없으므로 실행 밖에서 지켜봐야 한다.

출처

참고 문서

관련 사례

내 클러스터에도 있는지 확인하기

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: NCCL, PyTorch, 학습 데이터 로더. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.