(NCCL_P2P_DISABLE / NCCL_IB_DISABLE 2줄로 해결)
최근 Kubernetes GPU 노드에서 PyTorch DDP(DistributedDataParallel) 학습을 돌리던 중,
GPU 2장이 모두 정상적으로 할당되고 nvidia-smi도 잘 찍히는데,
항상 일정 시간이 지나면 NCCL ALLREDUCE 타임아웃이 발생하면서 학습이 죽어버리는 문제가 있었다.
로그는 아래처럼 폭발적으로 길어지며 결국 DistBackendError로 종료된다.
Watchdog caught collective operation timeout:
WorkNCCL(SeqNum=1, OpType=ALLREDUCE)
c10::DistBackendError: watchdog thread terminated with exception
process 1 terminated with signal SIGABRT
처음엔 코드 문제(샘플러, 에폭 루프, barrier, DataLoader 워커 수 등)를 다 확인했지만
결정적인 원인은 NCCL 통신 경로 자체가 환경과 충돌하는 문제였다.
🔍 문제 원인 요약
우리가 사용한 환경은:
- 단일 노드
- GPU 2장 (RTX PRO 6000 Black)
- Kubernetes Pod 1개에 nvidia.com/gpu: 2 할당
- 외부 네트워크 통신 없이 로컬 IPC로만 통신해도 충분한 구조
즉, InfiniBand도 없고, GPU 간 P2P(Not NVLink)도 사실 필요 없는 환경이었다.
그런데 NCCL은 기본적으로 다음을 시도한다:
- GPU 간 P2P(NVLink) 통신
- InfiniBand / RDMA
- 소켓 기반 통신
- SHM 기반 IPC
여기서 **걸리는 경로(=지원되지 않거나, 지연이 발생하거나, 인터페이스가 꼬이는 경우)**가 발생하면
collective op(ALLREDUCE)의 타이밍이 뭉개지고, 결국 watchdog이 타임아웃을 때린다.
✨ 해결: 환경 변수 2줄 추가
결론적으로 문제는 아래 두 줄로 완전히 해결되었다.
os.environ["NCCL_P2P_DISABLE"] = "1" # GPU 간 P2P 통신 비활성화
os.environ["NCCL_IB_DISABLE"] = "1" # InfiniBand 비활성화
즉,
- 단일 노드지만 NVLink가 없는 GPU들끼리의 P2P를 NCCL이 억지로 시도하다가 끊김 → 타임아웃
- InfiniBand가 없는 환경에서 IB path 스캔 중 지연 발생 → 타임아웃
을 방지했다는 뜻이다.
이 두 옵션을 비활성화하자마자:
- NCCL이 SHM/Socket 기반으로 깨끗하게 고정
- 통신이 안정화
- ALLREDUCE 타임아웃 완전 소멸
- 2GPU DDP 학습이 정상적으로 끝까지 진행
정말 “두 줄의 기적”이었다.
🧪 수정 코드 (초기 DDP setup 직전)
전체 코드 구조는 유지하고, main_worker() 또는 setup_distributed() 가장 앞쪽에 아래처럼 넣으면 된다.
# --- 핵심 해결 코드 ---
os.environ["NCCL_P2P_DISABLE"] = "1" # GPU 간 P2P 통신 비활성화
os.environ["NCCL_IB_DISABLE"] = "1" # InfiniBand 비활성화
# ------------------------
dist.init_process_group(backend="nccl")
torch.cuda.set_device(local_rank)
Kubernetes 환경에서는 Container spec 안에 다음처럼 추가해도 동일하게 동작한다.
env:
- name: NCCL_P2P_DISABLE
value: "1"
- name: NCCL_IB_DISABLE
value: "1"
🧠 왜 이 두 줄이 효과가 있었을까?
정리하자면:
NCCL 기능우리 환경결과
| P2P (NVLink) | RTX PRO 6000 Black — NVLink 없음 | NCCL이 P2P 경로를 시도 → 실패/지연 |
| InfiniBand | 없음 | NCCL이 IB 스캔하다가 초기화 지연 |
| Socket/SHM | 있음 (정상) | 우리가 원하는 통신 방식 |
따라서 “쓰지 않는 기능을 강제로 끄는 것”이 오히려 더 안전했다.
🚀 최종 결과
- NCCL ALLREDUCE 타임아웃 100% 해결
- rank0/rank1 모두 안정적으로 에폭 종료
- GPU 2장 DDP 학습 정상 진행
- 학습 속도와 GPU 활용률이 일정하게 유지됨
- 종료 시 DistBackendError / SIGABRT도 더 이상 발생 안 함
결론은 아주 명확하다.
단일 노드에서 P2P(NVLink 없음) + InfiniBand 없는 환경이라면
NCCL_P2P_DISABLE=1 / NCCL_IB_DISABLE=1 을 기본값으로 깔고 가는 게 더 좋다.
📌 비슷한 문제를 겪는 분들에게
만약 다음과 같은 증상을 겪고 있다면:
- DDP에서 ALLREDUCE 타임아웃 발생
- rank 간 collective 불일치 에러
- watchdog이 collective를 죽였다는 메시지 출력
- DistBackendError
- SIGABRT, SIGKILL로 종료
- GPU는 잘 보이는데 통신이 계속 불안정함
- NCCL이 “work sequence id 1”에서 멈춰 있음
가장 먼저 아래 두 줄을 시도해보길 추천한다.
os.environ["NCCL_P2P_DISABLE"] = "1"
os.environ["NCCL_IB_DISABLE"] = "1"
10분짜리 에러 로그를 한 번에 종결할 수 있는 해결책이었다.

'<ML>' 카테고리의 다른 글
| ✅2개의 GPU 환경에서 DDP 분산 학습 구축하기: 오늘의 기술 실험 기록 (0) | 2025.11.10 |
|---|---|
| CatboostEncoder (0) | 2023.01.30 |
| SOM 자기조직화지도 (0) | 2023.01.02 |