AWS 기술 블로그

분산 학습을 위한 AWS 컴퓨트 선택 가이드 (3편: 클러스터 구축과 운영)

1편에서 모델 규모에 맞는 인스턴스 타입과 인터커넥트 기술을, 2편에서 Amazon EC2 UltraClusters(울트라클러스터)Amazon EC2 UltraServer(울트라서버)와 고성능 GPU 인스턴스 확보 전략을 다뤘습니다. 무엇을 고르고 어떻게 확보할지가 정해졌다면, 이제 실제로 클러스터를 구성하고 운영할 차례입니다. 이번 3편에서는 컨테이너 기반 환경 구성, 클러스터를 구성하기 전 점검사항, 온프레미스 환경과의 비교, GPU와 Trainium의 선택, 그리고 현장에서 자주 마주치는 문제의 해결까지 다룹니다.

시리즈 블로그 보기

컨테이너 환경: Enroot Pyxis

분산 학습에서는 수십에서 수백 개의 노드가 완전히 동일한 소프트웨어 스택을 실행해야 합니다. CUDA, cuDNN, NCCL, aws-ofi-nccl, PyTorch 같은 핵심 구성 요소들은 버전 사이 호환성이 매우 민감해서, 노드마다 미세하게 다른 환경이 그대로 학습 실패로 이어집니다. 전통 HPC의 단순한 의존성(주로 컴파일러와 MPI)과 달리 ML/DL은 의존성이 복잡하고 버전 변경도 잦기 때문에, 컨테이너로 환경을 통째로 고정하는 접근이 표준으로 자리 잡았습니다.

특성 전통적 엔지니어링 시뮬레이션 ML/DL 트레이닝
의존성 복잡도 상대적 단순, 변화 거의 없음 매우 복잡, 버전 변경 빈번
핵심 구성요소 컴파일러 + MPI CUDA + cuDNN + NCCL + ML 프레임워크
환경 불일치 위험 낮음 높음 (노드 간 미세한 차이도 학습 실패 원인)

<표1. 전통 엔지니어링 시뮬레이션과 ML/DL 트레이닝의 의존성 및 환경 일관성 비교>

기존에 Slurm으로 CFD나 구조 해석 잡을 돌려 온 HPC 인프라 담당자라면, “컨테이너가 필요하면 그냥 Docker 쓰면 되지 않나”라고 생각하기 쉽습니다. 그러나 전통 Slurm HPC 환경에서 Docker를 그대로 쓰기는 어렵습니다. 이유는 두 가지입니다.

첫째, 권한 문제입니다. Docker는 일반적으로 root 권한과 백그라운드 데몬(dockerd)을 전제로 동작하는데, 다수 사용자가 자원을 공유하는 HPC 클러스터는 보안상 사용자에게 root 권한을 주지 않는 것이 원칙입니다. (최근에는 rootless Docker도 있지만, 이는 권한 문제만 일부 풀 뿐 아래의 두 번째 문제는 그대로 남습니다.)

둘째, 스케줄러와의 단절입니다. 이것이 사실 더 본질적인 차별점입니다. Slurm은 잡을 노드에 배치하고 자원(CPU, GPU, 메모리)을 할당하고 어카운팅(accounting)하는 스케줄러인데, Docker 컨테이너는 스케줄러 바깥에서 별도 데몬을 띄웁니다. Docker는 원래 한 호스트에서 컨테이너를 중앙 집중 관리하는 용도로 설계됐지, HPC 잡 스케줄러에 잡 단위로 얹히는 것을 전제로 만들어진 게 아니기 때문입니다. 그 결과 Slurm이 정해 둔 자원 제한, 즉 각 잡에 대해 “이 잡은 GPU, CPU, 메모리를 이만큼까지만 쓸 수 있다”고 강제하는 상한선이 컨테이너에는 적용되지 않습니다. 또한 잡이 자원을 얼마나 썼는지 집계하는 사용량 기록(어카운팅)이 부정확해지고, 잡이 끝난 뒤에도 컨테이너가 정리되지 않고 남기도 합니다. 한마디로 Slurm과 Docker가 서로를 인지하지 못해, 그대로 붙이면 자원 관리가 깨집니다.

그래서 전통 Slurm HPC 환경에서 컨테이너 기반 분산 트레이닝을 수행하려면 이 간극을 메우는 전용 구성이 필수입니다. 대표적인 선택지는 Enroot + Pyxis와 Apptainer(구 Singularity) 두 가지입니다. 둘 다 루트 권한 없이 컨테이너를 실행하고 Slurm과 연동되지만, 강점이 갈립니다. Enroot + Pyxis는 NVIDIA GPU 생태계(CUDA, NCCL)와의 통합, 그리고 Pyxis를 통한 Slurm 잡 스케줄러와의 긴밀한 연동에 최적화되어 있어 GPU 분산 학습에 특히 적합합니다. Apptainer는 이식성과 재현성이 강점이라 GPU 워크로드를 포함한 HPC 전반에서 폭넓게 사용됩니다. 이 글은 GPU 분산 학습에 초점을 두므로 Enroot + Pyxis를 기준으로 설명합니다.

Enroot는 NVIDIA가 만든 컨테이너 런타임으로, 앞서 짚은 권한 문제를 정면으로 해결합니다. rootless로 동작해 root 권한 없이 컨테이너를 실행할 수 있고, 상시 떠 있는 데몬도 필요 없어 HPC의 멀티 유저 정책과 충돌하지 않습니다. 한 노드에서 여러 컨테이너를 동시에 띄우는 것도 지원합니다. Enroot는 Docker 이미지를 .sqsh 파일(학습을 돌리는 환경, 조리도구와 레시피 재료가 세팅된 일종의 주방)로 변환해 사용하는데, 이는 squashfs 기반의 Enroot 전용 이미지 포맷입니다. 쉽게 말해 “PyTorch 실행에 필요한 전체 스택이 미리 설치된 리눅스 환경 한 덩어리”를 파일 하나로 떠둔 것입니다.

# Docker 이미지를 .sqsh 파일로 변환
enroot import -o pytorch.sqsh docker://nvcr.io/nvidia/pytorch:24.01-py3
# -> pytorch.sqsh 파일 생성

실무에서는 이 .sqsh 파일을 노드마다 따로 복사하지 않고, Amazon FSx for Lustre 같은 공유 파일시스템에 한 번 올려 두고 모든 노드가 마운트해서 읽는 방식을 씁니다. 수십 GB에 이르는 이미지를 노드 수만큼 복제할 필요가 없고, 모든 노드가 같은 파일을 참조하므로 환경 일관성도 자연스럽게 보장됩니다.

Enroot가 권한 문제를 풀었다면, 스케줄러와의 단절을 메우는 것이 Pyxis입니다. Pyxis는 NVIDIA가 만든 Slurm 플러그인으로, Slurm이 컨테이너를 직접 다룰 수 있게 해 줍니다. Pyxis가 설치되어 있으면 srun이나 sbatch에 –container-image 옵션만 덧붙여도, Slurm이 잡을 스케줄링하면서 그 안에서 Enroot 컨테이너를 띄우고 할당한 GPU 자원을 컨테이너에 그대로 연결합니다. 인프라 담당자 입장에서 중요한 점은, 기존 Slurm 워크플로우(파티션, QOS, sbatch 스크립트)를 하나도 바꾸지 않고 컨테이너를 얹을 수 있다는 것입니다.

# Pyxis 없으면: 컨테이너를 수동으로 직접 실행해야 하고, GPU 노출과 마운트, 멀티노드 실행을 일일이 챙겨야 함
srun enroot start ./myimage.sqsh python train.py
# Pyxis 있으면: 옵션 하나로 Slurm이 자원 연결과 컨테이너 실행을 알아서 처리
srun --container-image=./myimage.sqsh python train.py

정리하면 역할 분담은 이렇습니다. Slurm은 여러 노드에 잡을 배치 및 스케줄링하고, Pyxis는 그 잡이 컨테이너 안에서 돌도록 Slurm과 Enroot를 중개하며, Enroot는 root 없이 컨테이너를 실행하고, .sqsh 이미지는 모든 노드에 동일한 환경을 보장합니다. 여기에 AWS 환경에서 한 가지가 더 맞물립니다. 의존성 목록에 있는 aws-ofi-nccl은 NCCL의 통신을 EFA 위로 태워 주는 플러그인으로, 이게 컨테이너 안에 올바른 버전으로 들어 있어야 GPU 간 AllReduce가 EFA의 고속 경로를 타게 됩니다. 즉 .sqsh 이미지에 CUDA 및 NCCL, aws-ofi-nccl이 검증된 조합으로 고정돼 있어야, 노드 간 통신까지 제 성능을 냅니다.

분산 학습은 노드 하나라도 CUDA 및 NCCL 버전이 어긋나면 통신이 깨지거나 통째로 실패하는데, 이 조합이 “모든 노드 환경 일치”라는 까다로운 조건을 사람 손 없이 자동으로 충족시켜 줍니다. 그래서 전통 Slurm HPC 환경에서 GPU 분산 트레이닝으로 넘어갈 때, Enroot + Pyxis는 선택이 아니라 사실상 필수 구성으로 권장됩니다.

그림1은 AWS ParallelCluster를 이용하여 클러스터 구축 후 잡이 제출된 뒤, 컨테이너 안에서 분산 학습이 실행되는 전체 경로를 보여 줍니다. 위쪽 Head 노드에는 클러스터를 총괄하는 Slurm 컨트롤러(master)와 모니터링과 같은 부가 서비스(Grafana 등)가 올라가 있습니다. 사용자가 잡을 제출하면 흐름은 “사용자 → Slurm 컨트롤러 → 컴퓨트 노드” 순으로 내려갑니다.

실제 실행은 각 컴퓨트 노드 안에서 일어납니다. 컴퓨트 노드의 Slurm 클라이언트가 Pyxis를 호출하고, Pyxis가 Enroot 컨테이너를 띄웁니다. 한 노드에 여러 컨테이너가 동시에 뜰 수 있고 모두 동일한 .sqsh 이미지를 사용하므로, 노드와 컨테이너에 관계없이 CUDA, NCCL, 딥러닝 프레임워크(PyTorch, TensorFlow 등) 버전이 완전히 일치합니다. 이 구조를 그대로 복제해 노드를 필요한 만큼 추가하면, 수십에서 수백 노드가 같은 환경에서 하나의 분산 학습 잡을 함께 수행하게 됩니다. 요약하면 “Slurm이 배치하고, Pyxis가 중개하고, Enroot가 실행하며, .sqsh 이미지가 모든 노드의 환경을 동일하게 묶는다”는 한 문장입니다.

<그림1. 컨테이너 기반 분산 학습 실행 아키텍처>

여기까지가 “모든 노드에 동일한 실행 환경(정적, 안 바뀜)을 어떻게 구성하는가”에 대한 답이라면, 그 위에서 실제 학습은 다음과 같이 협업합니다. 데이터 병렬(Data Parallelism) 방식에서는 모델(학습이 갱신해 나가는 대상, 예: Llama 70B는 약 700억 개의 숫자 묶음)이 모든 GPU에 동일하게 복제되고, 학습 데이터는 GPU마다 서로 다른 배치로 나뉘어 처리됩니다. PyTorch의 DistributedSampler가 데이터셋을 겹치지 않게 분할해, 각 컨테이너(프로세스)가 자기 몫의 배치만 학습하도록 합니다.

각 GPU가 서로 다른 데이터를 보게 되므로, 매 스텝에서 계산되는 그래디언트도 GPU마다 다릅니다. 이를 그대로 두면 복제된 모델들이 제각기 갱신되어 흩어지므로, 매 스텝 끝에 모든 GPU의 그래디언트를 평균 내어 동기화한 뒤 같은 값으로 모델을 갱신합니다. 이 동기화가 바로 AllReduce이며, NCCL이 수행합니다. 앞서 언급한 aws-ofi-nccl과 EFA가 중요한 이유가 여기에 있습니다. 노드 개수가 증가할수록 그래디언트 동기화 통신량이 커지므로, AllReduce가 EFA의 고속 경로를 타야 수십에서 수백 노드로 확장해도 성능이 유지됩니다.

ML 클러스터를 구성하기 전에 점검할 것들

클러스터를 실제로 구성하기에 앞서 컴퓨트 요건과 리전 제약, 운영 플랫폼 선택을 미리 정리해 두면 시행착오를 크게 줄일 수 있습니다.

먼저 컴퓨트 요건입니다. 분산 학습을 시작하기 전에, 필요한 GPU 인스턴스를 어떤 방식으로 확보할지부터 결정해야 합니다. 앞선 블로그에서 다룬 것처럼 p5 및 p6 같은 인기 인스턴스는 대규모로 즉시 확보하기 어렵기 때문에, ODCR과 Capacity Block 두 가지 예약 방식을 워크로드에 맞게 선택하는 것이 출발점입니다. 개발 및 실험처럼 일정이 불규칙하면 ODCR이, 일정이 확정된 대규모 학습이라면 Capacity Block이 적합합니다.

이 확보 방식 결정이 중요한 이유는, 그것이 곧 클러스터 구성의 출발점이 되기 때문입니다. AWS ParallelCluster나 AWS PCS(Parallel Computing Service)를 사용하든 간에, 예약한 용량을 클러스터에 연결하는 설정이 반드시 따라옵니다. 예를 들어 ParallelCluster는 클러스터 설정 파일(YAML)의 큐 정의에 예약 ID를 지정하고, PCS는 컴퓨트 노드 그룹이나 시작 템플릿(launch template)에 지정하는 식으로, 플랫폼마다 그 설정을 작성하는 위치와 방식이 다릅니다. 한편 Amazon SageMaker HyperPod는 ODCR이나 Capacity Block을 직접 지정하기보다 training plan 등 자체적인 용량 확보 체계를 사용하므로, 접근 방식 자체가 다릅니다. 구체적인 구성은 선택한 플랫폼의 공식 문서를 따르되, “어떤 방식으로 얼마만큼의 인스턴스를 언제 확보할 것인가”라는 결정은 그보다 앞서 내려두어야 합니다.

리전 제약도 반드시 확인해야 합니다. 클러스터 운영 플랫폼과 최고의 스루풋을 제공하는 Amazon FSx for Lustre Persistent_2가 모든 리전에서 지원되지 않으며, 최신 세대 GPU일수록 가용 리전이 좁습니다. 일례로 p6-b300은 2026년 8월 기준 미국의 일부 리전에서만 사용할 수 있습니다. 리전을 선택할 때는 다음을 함께 점검하는 것이 안전합니다.

ParallelCluster, PCS, SageMaker HyperPod와 같은 클러스터 구성 플랫폼 지원 여부
Amazon FSx for Lustre Persistent_2 지원 여부
필요한 FSx for Lustre 용량 확보 가능 여부
원하는 GPU 인스턴스 타입 가용 여부

마지막으로 운영 플랫폼과 노드 환경(AMI)을 정해야 합니다. 먼저 AWS 네이티브 플랫폼인 ParallelCluster, PCS, SageMaker HyperPod 등에서 운영 부담과 제어 수준, 워크로드 성격에 맞는 것을 선택합니다. 대체로 ParallelCluster는 사용자가 가장 세밀하게 제어하는 대신 관리 부담이 크고, PCS는 관리형으로 부담을 낮추면서도 Slurm 제어를 유지하며, SageMaker HyperPod는 대규모 ML 학습에 특화된 관리형에 가깝습니다.

그 다음, 노드에 들어갈 소프트웨어 환경, 즉 AMI를 정합니다. 여기에는 대체로 세 가지 접근이 있습니다. 첫째는 표준 AMI를 그대로 쓰고 필요한 패키지를 부팅 시점에 설치하는 방식으로, 유연하지만 노드를 띄울 때마다 설치 시간이 더해집니다. 둘째는 GPU 드라이버와 CUDA, 딥러닝 프레임워크가 미리 설치된 DLAMI(Deep Learning AMI)로, 별도 구성 없이 빠르게 시작할 수 있습니다. 셋째는 필요한 환경을 이미지에 미리 담아 고정해 두는 Custom AMI로, 부팅이 빠르고 노드 간 환경이 일정해 장기 및 대규모 운영에 적합합니다.

세 방식의 트레이드오프(유연성 ↔ 부팅 속도, 환경 일관성)는 세 플랫폼 모두에서 공통적으로 성립합니다. 다만 완전히 임의의 AMI를 그대로 쓰는 것은 아니고, 커스터마이즈 요건은 플랫폼마다 다릅니다. PCS는 세 플랫폼 중 AMI 자유도가 가장 높아, 특정 base AMI를 강제하지 않고 원하는 AMI에 임의의 소프트웨어와 설정을 담을 수 있습니다. 다만 노드가 클러스터에 합류하려면 PCS 에이전트(AWS 제공 설치 도구로 설치 필수)와 호환되는 Slurm이 들어 있어야 하고, Slurm도 AWS 설치 도구로 넣는 것을 권장합니다. 프로덕션에는 이들이 미리 담긴 PCS-ready DLAMI나 Custom AMI를 권장하고, 샘플 AMI는 테스트 용도로만 사용합니다. SageMaker HyperPod는 공개된 HyperPod 기반 AMI 위에서 Custom AMI를 빌드하는 방식을 지원하며(Slurm 클러스터는 2026년부터), 기존의 lifecycle script로 환경을 구성하는 방식도 함께 지원합니다. ParallelCluster는 요구 사양을 충족하는 AMI를 지정하고 부팅 시점의 custom action 스크립트로 환경을 보완합니다. 이처럼 AMI를 지정하고 커스터마이즈하는 구체적인 방법은 플랫폼마다 다르므로, 각 플랫폼의 공식 문서를 따르는 것이 안전합니다.

다만 앞서 다룬 Enroot와 Pyxis 기반 컨테이너를 함께 쓰면, AMI에 어떤 버전의 소프트웨어가 깔려 있느냐에 대한 의존을 크게 줄일 수 있습니다. 그림2와 같이 CUDA, NCCL, 딥러닝 프레임워크 같은 핵심 스택을 .sqsh 이미지에 고정해 두면, 노드의 AMI에 GPU 드라이버만 갖춰져 있으면 그 위의 소프트웨어 버전에 관계없이 모든 노드가 동일한 환경에서 실행되기 때문입니다. GPU 드라이버는 커널 모듈이라 컨테이너가 아닌 호스트 AMI에 있어야 하고, 그 드라이버가 컨테이너 안 CUDA 버전을 지원하기만 하면 됩니다. 그래서 플랫폼과 AMI를 어떻게 고르든, 환경 일관성과 운영 부담 측면에서는 컨테이너 기반 구성이 유리합니다.

<그림2. Enroot/Pyxis로 실행 환경 분리: 드라이버 vs 컨테이너 스택>

AWS GPU 인스턴스와 온프레미스 GPU 서버

온프레미스 GPU 클러스터를 운영하다 AWS로 분산 학습을 옮기려는 담당자가 가장 먼저 갖는 의문은 “클라우드 가상화 때문에 성능이 깎이지 않느냐”입니다. 결론부터 말하면, GPU 자체와 노드 내부 구조는 사실상 동일하고, 달라지는 것은 주로 노드 바깥의 운영 모델입니다.

AWS p5는 H100/H200, p6는 B200/B300으로, 온프레미스 DGX/HGX에 들어가는 것과 동일한 NVIDIA GPU를 씁니다. 노드 안에서 GPU를 연결하는 NVLink와 NVSwitch도 같은 HGX 구성을 따릅니다. 즉 한 노드 안의 GPU 8장(또는 GB200 구성)이 통신하는 방식은 온프레미스 환경과 다르지 않습니다.

“클라우드면 하이퍼바이저가 성능을 갉아먹지 않나”라는 우려는 AWS Nitro 시스템이 해소합니다. Nitro 시스템은 네트워크, 스토리지, 보안 기능을 전용 하드웨어 칩으로 떼어 내(오프로드) 처리하기 때문에, 호스트 CPU는 거의 전부 게스트(인스턴스)에 할당됩니다. GPU는 패스스루로 가상화 계층 없이 인스턴스에 직접 붙고, EFA는 OS 커널을 우회해 하드웨어에 직접 접근합니다. 그 결과 p5/p6는 베어메탈에 준하는 성능을 내면서도, 클라우드의 유연성을 함께 제공합니다.

클라우드 전환 담당자가 실제로 기억해야 할 부분은 노드를 연결하고 운영하는 방식입니다. 첫째, 노드 간 인터커넥트가 다릅니다. 온프레미스 환경은 보통 인피니밴드를 쓰고 크레딧 기반 흐름 제어로 무손실(lossless)을 기본 보장하지만, AWS는 이더넷 기반 위에서 동작하는 AWS EFA/SRD를 씁니다. SRD는 무손실을 전제하지 않고 패킷 손실 및 순서 뒤바뀜을 하드웨어에서 재전송 및 재정렬로 처리합니다. 실무에서 중요한 건, 분산 학습 시 EFA가 활성화되어 NCCL이 그 경로를 타도록 설정하는 것입니다(미설정 시 조용히 TCP로 폴백되어 성능이 급락합니다). 또한 인피니밴드 전용 환경에 강하게 묶인 일부 소프트웨어(예: IBGDA 의존 라이브러리)는 EFA에서 그대로 동작하지 않을 수 있는데, 이 차이는 이미 다른 EFA와 관련된 AWS 테크 블로그 시리즈에서 다룬 바 있습니다.

둘째, 용량 확보의 셈법이 다릅니다. 온프레미스는 하드웨어를 구매 또는 리스해 갖추는 데 수개월이 걸리고, 한 번 사면 사용률과 무관하게 비용이 고정됩니다. 반면 AWS는 필요한 시점에 수분에서 수주 내로 GPU를 확보할 수 있습니다. ODCR은 필요할 때 만들고 필요 없어지면 취소해 비용을 멈출 수 있고, Capacity Block은 예약한 기간만큼 용량을 확보하는 대신 그 기간에 해당하는 비용이 발생합니다.

셋째, 장애 대응이 다릅니다. 수백에서 수천 노드 규모에서는 하드웨어 장애가 일상인데, 온프레미스는 직접 노드를 교체해야 하기 때문에 수 시간에서 수 일이 걸립니다. SageMaker HyperPod를 사용하면 노드 장애를 자동으로 감지, 격리, 교체하고, 교체 후 학습 잡을 자동으로 재개(auto-resume)합니다. 이때 학습은 미리 저장해 둔 최근 체크포인트에서 이어집니다. 동기식 분산 학습은 노드 하나만 멈춰도 전체가 멈추기 때문에, 이 자동 복구가 대규모 학습에서 운영 부담을 크게 줄여 줍니다.

구분 온프레미스 DGX/HGX AWS p5/p6 인스턴스
GPU H100/H200/B200/B300 (동일)
NVLink/NVSwitch 있음
가상화 오버헤드 없음 (베어메탈) Nitro로 최소화 (베어메탈 수준)
노드 간 인터커넥트 InfiniBand (무손실 기본) EFA/SRD (이더넷 기반, 손실 허용)
하드웨어 관리 직접 관리 AWS 관리
용량 확보 구매/리스 후 수개월 CB/ODCR 등으로 수분~수주 내
노드 장애 대응 직접 교체 (수 시간~수 일) HyperPod 사용 시, 자동 감지/교체

<표2. 온프레미스 GPU 서버와 AWS GPU 인스턴스 비교>

정리하면, GPU와 노드 내부(NVLink, NVSwitch)는 온프레미스와 동일하고 Nitro 덕분에 성능 손실도 사실상 없습니다. 전환 시 새로 익혀야 할 것은 인터커넥트(InfiniBand → EFA/SRD), 용량 확보 방식(구매 → 예약), 그리고 장애 대응(수동 교체 → 자동 복구)이라는 운영 모델의 차이입니다.

GPU Trainium 중 무엇을 고를까?

이 블로그는 GPU(p5/p6) 기반 분산 학습을 중심으로 다뤘지만, AWS에는 자체 개발한 AI 액셀러레이터인 AWS Trainium(Trn1/Trn2/Trn3)도 있습니다. Trainium은 검증된 모델(특히 트랜스포머 계열)을 대규모로 반복 학습할 때 가격 대비 성능이 좋고, GPU 대비 상대적으로 확보가 수월합니다. 다만 CUDA 및 NCCL 위에서 그대로 작동하는 GPU와 달리 AWS Neuron SDK와 PyTorch/XLA 기반으로 동작하므로, 기존 코드를 이식 및 검증하는 작업이 필요합니다. 따라서 빠르게 시작하거나 최신 및 실험적 모델, 커스텀 커널을 다룬다면 생태계가 가장 성숙한 GPU가 안전하고, 아키텍처가 안정적이고 대규모 학습을 반복하며 비용 효율이 중요하다면 Trainium을 검토할 만합니다.

구분 GPU (p5/p6) Trainium (Trn1/Trn2/Trn3)
소프트웨어 스택 CUDA, NCCL, PyTorch AWS Neuron SDK, PyTorch/XLA
코드 이식성 기존 CUDA 코드 그대로 Neuron SDK로 포팅 필요
생태계 성숙도 매우 높음 (업계 표준) AWS 특화 (지원 범위 GPU 대비 좁음)
가격/가용성 높은 수요로 확보 경쟁적 상대적으로 확보 용이, 저렴
적합 상황 빠른 시작, 범용 비용 효율 중요, 장기 운영

<표3. GPU와 Trainium 선택 기준>

자주 묻는 질문과 현장의 문제 해결

마지막으로 인스턴스 확보와 클러스터 구축 과정 등에서 반복적으로 나오는 질문과 문제들을 정리하도록 하겠습니다.

인스턴스 확보

먼저 “On-Demand로 p5를 바로 쓸 수 있느냐”는 질문이 많은데, Service Quota 할당량이 0으로 잡혀 있는 경우가 흔합니다. AWS 콘솔의 Service Quotas에서 vCPU 한도를 확인하고 증가를 먼저 요청해야 하며, 대규모로 필요하다면 ODCR이나 Capacity Block 등으로 미리 예약하는 편이 현실적입니다. “Capacity Block은 얼마나 미리 신청해야 하느냐”는 질문에는, 중요한 학습 마일스톤이 있다면 최소 4~6주 전에 예약할 것을 권합니다. 앞서 언급한 기간 단위 규칙(1~14일은 1일 단위, 15~182일은 7일 단위)도 함께 확인해야 합니다. “분산 학습에 스팟(Spot) 인스턴스를 써도 되느냐”는 질문에는 원칙적으로 권하지 않습니다. 스팟 인스턴스는 2분 전 통보 후 회수될 수 있어, 수백 노드 학습 중 단 하나만 회수돼도 전체가 멈추기 때문입니다. 다만 전처리나 하이퍼파라미터 탐색처럼 작업 단위가 짧고 재시작이 쉬운 경우라면 활용할 여지가 있습니다. 

클러스터 구축과 운영

노드 하나의 장애로 전체 학습이 멈추는 문제가 잦습니다. 분산 학습은 모든 노드가 동기화된 채 돌기 때문에 하나만 실패해도 전체가 종료됩니다. HyperPod를 쓰면 노드 장애를 자동으로 감지해 교체하고, 학습 잡을 자동으로 재개(auto-resume)합니다. 이때 학습은 미리 저장해 둔 최근 체크포인트에서 이어집니다.

소프트웨어 버전 불일치로 학습이 아예 시작되지 않거나, 시작되더라도 통신 성능만 조용히 떨어지는 경우가 있습니다. 분산 학습 환경에서는 CUDA, NCCL, aws-ofi-nccl, 그리고 EFA 드라이버가 서로 맞물려 동작하는데, 이 중 한 조각만 따로 업그레이드하면 사슬이 끊어지기 때문입니다. 대표적인 사례가 NCCL만 새 버전으로 올리고 거기에 맞는 aws-ofi-nccl을 함께 갱신하지 않는 경우입니다. 이러면 NCCL이 EFA 경로를 찾지 못해 통신이 일반 TCP로 폴백되는데, 오류 메시지 없이 GPU 간 통신 속도만 급락하기 때문에 원인을 찾기가 특히 어렵습니다. 또 다른 흔한 사례는 노드마다 컨테이너 이미지나 라이브러리 버전이 미세하게 달라, NCCL 초기화 단계에서 학습이 멈추는 경우입니다. NCCL은 모든 노드의 버전이 동일해야 정상 동작하기 때문입니다.

이런 문제를 원천적으로 막으려면 환경을 통째로 고정하는 것이 가장 확실합니다. Enroot/Pyxis와 AWS DLC(Deep Learning Containers) 이미지를 함께 쓰면 CUDA, NCCL, aws-ofi-nccl이 검증된 조합으로 묶여 있고, 모든 노드가 동일한 이미지를 사용하므로 버전이 어긋날 여지 자체가 사라집니다.

여러 팀이 하나의 GPU 클러스터를 공유할 때 가장 흔한 갈등은 두 가지입니다. 하나는 한 팀이 대규모 잡으로 GPU를 독점하여 다른 팀이 며칠씩 대기하는 상황이고, 다른 하나는 팀별로 GPU를 고정 배정해 두었을 때 한 팀이 자기 몫을 다 쓰지 않아도 그 유휴 GPU를 다른 팀이 빌려 쓰지 못해, 클러스터 전체 사용률이 떨어지는 상황입니다. 핵심은 “급한 잡은 빨리 들어가게 하되, 장기적으로는 팀 간 사용량이 공평하게 수렴하도록” 만드는 것입니다.

Slurm 환경이라면 세 가지를 함께 사용합니다. 먼저 파티션으로 자원 풀을 나눠 특정 GPU 그룹을 팀이나 용도(학습용, 디버그용)별로 분리하고, QoS로 팀별 최대 점유량과 우선순위에 상한을 둡니다. 그리고 Fair-share 스케줄링으로 그동안 적게 쓴 팀의 잡에 더 높은 우선순위를 부여해, 한 팀이 계속 몰아 쓰지 못하도록 장기적으로 사용량을 균형 맞춥니다. EKS 환경이라면 같은 목표를 ResourceQuota(네임스페이스별 GPU 사용 상한)와 PriorityClass(잡 우선순위)로 구현합니다.

다만 분산 학습에는 한 가지 주의가 더 필요합니다. 멀티 노드 학습 잡은 필요한 노드가 전부 동시에 확보돼야 시작할 수 있습니다. 예를 들어 16대가 필요한 잡인데 스케줄러가 15대만 확보하고 나머지 1대를 기다린다면, 이미 확보한 고비용 GPU 15대가 계산은 하지 못한 채 묶여 놀게 됩니다. GPU는 켜져 있어 요금은 나가는데 아무 일도 못 하고, 다른 잡도 그 노드를 쓰지 못하는 이중 낭비가 생기는 것입니다.

그래서 멀티 노드 학습에는 필요한 노드 전체가 확보될 때만 잡을 띄우는 “전부 아니면 대기(all-or-nothing)” 방식, 이른바 갱(gang) 스케줄링이 필요합니다. Slurm은 단일 잡의 자원을 원자적으로 할당하므로, 요청한 노드가 모두 확보될 때까지 잡을 대기시켰다가 한꺼번에 실행합니다. 즉 별도 설정 없이 기본 동작으로 이 요구를 충족합니다. 반면 쿠버네티스(EKS)의 기본 스케줄러(kube-scheduler)는 파드를 하나씩 배치하기 때문에 15대만 뜨고 1대를 기다리는 부분 점유가 실제로 발생할 수 있어, 갱 스케줄링을 위해서는 Kueue나 Volcano 같은 배치 스케줄러를 함께 씁니다.

학습 실행 중 마주치는 문제

“GPU 활용률이 예상보다 낮다”는 가장 흔한 고민입니다. 원인은 크게 두 갈래입니다. 하나는 데이터 로딩 병목으로, DataLoader worker(GPU에 데이터를 병렬로 읽어 공급하는 프로세스, PyTorch의 num_workers로 개수 지정)가 부족하거나 전처리(디스크에서 읽은 원본 데이터를 GPU에 넣을 수 있는 텐서 형태로 바꾸는 CPU 작업)와 작은 파일의 랜덤 I/O가 무거워 GPU가 데이터를 기다리며 대기하는 경우입니다. 여기에 더해 학습 초반에는, FSx for Lustre가 S3 데이터를 첫 접근 시점에 로드하는 특성상 Preload를 미리 해두지 않으면 첫 에포크(epoch) 동안 활용률이 낮을 수 있습니다(데이터가 한 번 Lustre에 올라오면 이후 접근은 빠릅니다). 다른 하나는 노드 간 통신 병목으로, NCCL 설정 오류나 EFA 미활성화로 AllReduce가 느려지는 경우입니다.

진단은 먼저 nvidia-smi dmon -s u로 GPU 사용률을 지켜봅니다. 사용률이 주기적으로 툭툭 떨어졌다 올라오면 데이터가 제때 공급되지 않는다는 신호이므로, DataLoader worker 수와 전처리 병목을 점검하고, 첫 에포크라면 lfs hsm_state로 FSx Preload가 끝났는지 확인합니다. 반면 사용률이 여러 노드에서 동시에, 매 스텝 같은 지점에서 떨어지면 노드 간 통신(AllReduce)을 기다리는 것이므로, NCCL_DEBUG=INFO로 통신이 EFA를 제대로 타는지 점검합니다.

“학습이 멈춰 있고 NCCL 타임아웃이 발생한다”는 분산 학습에서 가장 흔한 장애 중 하나입니다. 보통 노드 간 통신이 EFA를 제대로 타지 못해, 특정 집합통신에서 한 랭크가 멈추면 나머지 전체가 그 랭크를 기다리며 멈추는 경우입니다. NCCL_DEBUG=INFO로 NCCL이 어떤 경로(EFA, 소켓)로 통신하는지 확인하고, fi_info -p efa로 EFA 프로바이더가 인식되는지, 그리고 관련 EFA 환경 변수가 컨테이너 안에 제대로 설정됐는지 점검합니다. 일시적 지연이 원인이면 NCCL 타임아웃 값을 늘리는 것도 방법이지만, 근본 원인은 대개 EFA 미활성화나 (CUDA, NCCL, aws-ofi-nccl 사이의) 버전 불일치입니다.

“노드 개수를 2배로 늘렸는데 속도가 2배가 안 된다”도 자주 나옵니다. 분산 학습은 노드 개수가 증가할수록 노드 간 통신량도 함께 늘어, 선형 확장(linear scaling, 노드 수가 2배면 속도도 2배)에서 멀어지는 것이 정상입니다. 확장 효율을 높이려면 세 가지가 핵심입니다. 첫째, 통신이 가장 잦은 Tensor Parallel(한 층의 연산을 여러 GPU가 나눠 맡는 병렬화)은 노드 안 NVLink(같은 노드 내 GPU들을 잇는 고속 링크) 도메인에 가둡니다. 둘째, gradient 통신을 backward 연산과 겹쳐 실행합니다. 원래는 계산을 다 끝낸 뒤 통신을 시작하지만, 계산과 통신을 동시에 수행하면 통신 시간이 계산 시간에 가려져 전체 시간이 줄어듭니다. 셋째, 글로벌 배치 크기(한 step에서 전체 GPU가 함께 처리하는 샘플 수)를 적절히 키워 step당 통신 비중을 낮춥니다(단, 지나치게 키우면 수렴에 영향을 줄 수 있어 learning rate 조정이 함께 필요합니다). 확장 효율이 갑자기 무너진다면 straggler 노드(유독 느린 한 노드가 전체 성능을 저하시킴)나 EFA 경로부터 의심합니다.

“학습 중 OOM(GPU 메모리 부족)으로 클러스터가 종료된다”는 모델과 배치가 GPU 메모리(HBM)의 용량을 초과할 때 발생합니다. GPU는 CPU처럼 OS가 자동으로 메모리를 디스크로 옮겨 주는 swap이 없어, 용량을 초과하는 순간 프로세스가 즉시 종료됩니다. 따라서 다음과 같이 대응합니다. 배치 크기를 줄이거나 gradient accumulation(작은 배치를 여러 번 돌리고 그 결과를 모았다가 한 번에 반영해, 큰 배치로 학습한 것과 같은 효과를 내는 기법)으로 보완하고, gradient checkpointing(계산 중간에 나온 값들을 메모리에 쌓아두는 대신 지워버리고, 나중에 필요할 때 다시 계산해 메모리를 아끼는 기법)으로 activation 메모리를 줄이며, 혼합 정밀도(bf16)나 FSDP/ZeRO(모델과 옵티마이저 상태를 여러 GPU에 분산 저장하는 기법)로 GPU 한 장이 감당할 메모리를 낮춥니다. 그래도 부족하면 당장 쓰지 않는 파라미터나 옵티마이저 상태를 시스템 메모리(CPU RAM)나 NVMe로 내보내는 오프로딩(DeepSpeed ZeRO-Offload, ZeRO-Infinity 등)으로 HBM 사용량을 더 낮출 수 있습니다. 다만 오프로딩은 CPU와 GPU 사이 데이터 이동이 늘어 학습 속도가 느려지므로, 다른 방법으로 부족할 때의 최후 수단에 가깝습니다.

체크포인트 저장 주기와 고속 저장 전략은 노드 장애 및 스팟 인스턴스 회수 대응의 핵심인데, 이 부분은 다른 블로그 시리즈에서 따로 다루어 보도록 하겠습니다.

맺음말

이번 3편에서는 앞서 선정한 컴퓨트를 실제로 프로비저닝하고 운영하는 방법을 다루었습니다. 컨테이너로 실행 환경 전체를 고정하고(Enroot와 Pyxis), 클러스터를 기동하기 전에 컴퓨트, 리전, 플랫폼을 점검하며, 온프레미스와의 운영상 차이를 이해하고, 현장에서 반복되는 장애에 미리 대비하는 것이 핵심입니다. 세 편을 관통하는 메시지는 하나입니다. 분산 학습용 컴퓨트를 선정할 때 가장 흔한 실수는 “어떤 GPU가 가장 빠른가”라는 질문에서 논의를 시작하는 것입니다. 실제 처리량과 비용을 좌우하는 요소는 GPU 자체보다 이를 둘러싼 네트워크, 데이터 공급, 용량 확보 전략, 그리고 운영 방식인 경우가 훨씬 많습니다.

전체 구도는 단순합니다. 대략 10B 이하 규모는 단일 p5/p6 인스턴스로 시작하고, 10B에서 100B 구간은 울트라클러스터로 확장하며, 100B를 넘어 1T에 이르는 규모에서는 울트라서버로 NVLink 도메인을 확대합니다. 다만 이 경계는 모델 크기뿐 아니라 병렬화 전략과 예산에 따라 달라지는 경험칙(경험에서 얻어지는 규칙)에 가깝습니다. 그리고 어느 규모에서든 EFA와 NCCL 설정, 데이터 파이프라인, 체크포인트와 복구 자동화, 컨테이너 기반 환경 고정이 성능과 안정성을 떠받치는 토대가 됩니다. 이 시리즈가 AWS 환경에서 분산 트레이닝을 처음 시작하는 분, 또는 전통 HPC에서 분산 학습으로 영역을 넓혀 가는 인프라 담당자에게 조금이나마 도움이 되었기를 바랍니다.

Sangman Cho

Sangman Cho

조상만 Solutions Architect는 AWS 입사 이후, Automotive 및 Manufacturing 고객의 클라우드 기반의 디지털 전환 업무를 지원하였으며, 현재는 AWS 코리아 전체의 고성능 컴퓨팅(HPC)과 양자 컴퓨팅 등 계산 과학 영역의 디지털 전환 업무를 지원하고 있습니다.