ML 파이프라인이 느린 건 모델 탓이 아닐 수 있다 — GPU 스케줄링과 서빙의 OS 레벨 최적화
GPU 메모리 계층, NUMA·CPU Pinning 같은 서빙 최적화, Kubernetes 리소스 스케줄링까지 ML Ops를 OS 자원 관리 관점에서 정리한다
2026-08-12 · 최초 발행 2026-01-19
모델 학습 코드를 아무리 최적화해도 GPU가 유휴 상태로 노는 시간이 길면 학습은 느려진다. ML Ops가 데이터 파이프라인부터 서빙까지 다루는 이유는, 각 단계가 요구하는 자원 특성이 서로 다르고 그 자원을 운영체제 레벨에서 어떻게 관리하느냐가 성능과 비용을 갈라놓기 때문이다.
파이프라인 단계마다 자원 요구사항이 다르다
데이터 수집·전처리는 I/O 집약적이고 대용량 파일을 다룬다. 특징 추출(Feature Engineering)은 CPU 집약적이라 병렬 처리 최적화가 관건이고, 모델 학습은 GPU·TPU 집약적이면서 메모리 대역폭이 중요하다. 모델 검증은 중간 규모 연산에 체크포인팅이 필요하고, 배포는 컨테이너 오케스트레이션과 버전 관리가 핵심이며, 서빙은 저지연 추론과 높은 동시성을 동시에 요구한다.
각 단계가 독립적으로 확장 가능하고, 모니터링 시스템이 단계별 성능과 자원 사용률을 계속 추적하는 구조다.
학습 단계에서 GPU를 나눠 쓰는 방법
GPU는 학습에서 가장 중요한 자원이라 스케줄링 방식이 곧 처리량을 결정한다. NVIDIA MPS(Multi-Process Service)는 단일 GPU를 여러 프로세스가 공유하게 하고, CUDA Unified Memory는 CPU-GPU 간 메모리 이동을 투명하게 처리한다. Kubernetes Device Plugin이 GPU 자원을 동적으로 할당하고, 실험용 작업보다 프로덕션 학습 작업에 높은 우선순위를 주는 스케줄링 정책이 함께 적용된다.
CPU 메모리에서 PCIe를 거쳐 GPU HBM으로 데이터가 이동하는 이 계층에서, OS의 페이지 폴트 핸들러와 CUDA 드라이버가 협력해 오버서브스크립션을 처리한다. 이 위에서 학습 자체를 최적화하는 기법으로는 torch.utils.data.DataLoader의 worker 수를 CPU 코어 수에 맞추는 것, FP16/BF16 연산으로 메모리 사용량을 절반으로 줄이는 Mixed Precision Training, 중간 활성화 값을 재계산해 메모리를 아끼는 Gradient Checkpointing, Horovod·PyTorch DDP를 통한 다중 GPU/노드 분산 학습이 있다.
서빙은 지연시간과 처리량 사이의 줄다리기다
모델 서빙에서는 동적 배칭으로 여러 요청을 묶어 GPU 활용률을 끌어올리고, 대규모 모델은 여러 GPU에 분산 배치(모델 병렬화)하며, 빈번한 입력에 대한 추론 결과는 캐싱하고, INT8/INT4 양자화로 모델 크기를 줄이면서 추론 속도를 높인다.
TensorFlow Serving은 이런 동적 배칭으로 요청을 모아 GPU에 전송하고, 여러 모델 버전을 동시에 서빙해 A/B 테스트와 Canary 배포를 지원한다. 여기서 한 단계 더 내려가면 OS 레벨 튜닝이 나온다 — 추론 스레드를 특정 NUMA 노드에 고정해 메모리 지역성을 확보하는 NUMA 친화성, 추론 프로세스를 특정 CPU 코어에 고정해 컨텍스트 스위칭을 줄이는 CPU Pinning, 2MB/1GB 대형 페이지로 TLB 미스를 줄이는 Huge Pages, 예측 가능한 디스크 응답 시간을 위한 Deadline I/O 스케줄러다.
Kubernetes가 ML 워크로드를 스케줄링하는 방식
Kubernetes는 ML Ops의 사실상 표준 오케스트레이션 플랫폼이다. GPU Operator가 NVIDIA GPU 드라이버와 런타임을 자동 배포하고, Kubeflow가 ML 워크플로우 전용 확장을 제공하며, Job/CronJob이 주기적 재학습 작업을 스케줄링하고, Horizontal Pod Autoscaler가 추론 부하에 맞춰 자동으로 확장한다.
Pod의 리소스 요청에 따라 노드가 스케줄링되고, cgroup을 통해 CPU·메모리·GPU가 격리되면서 다중 테넌트 환경에서도 안정적인 실행이 보장된다. 컨테이너 이미지 쪽에서는 런타임 이미지에서 빌드 도구를 빼는 다단계 빌드, 불변 의존성을 하위 레이어에 두는 레이어 캐싱, 모델 파일을 별도 볼륨으로 마운트해 이미지 갱신을 피하는 방식, Alpine·Distroless 같은 경량 베이스 이미지가 함께 쓰인다.
분산 학습에서 네트워크가 병목이 되는 지점
여러 노드로 학습을 분산하면 그래디언트 동기화가 네트워크 병목의 주요 원인이 된다. Ring All-Reduce는 각 노드가 이웃과만 통신하도록 설계해 대역폭을 최적으로 쓴다.
그래디언트를 N개 청크로 나눠 Reduce-Scatter 단계에서 링 토폴로지로 전송·합산한 뒤, All-Gather 단계에서 완성된 그래디언트를 모든 노드에 분산하는 방식이다. 이 과정을 GPU 간 고속 통신으로 뒷받침하는 게 NCCL(NVIDIA Collective Communications Library)이고, InfiniBand·RoCE 같은 저지연 RDMA 네트워크가 통신 오버헤드를 줄이며, 그래디언트 자체를 압축해 전송량을 줄이는 방법도 함께 쓰인다.
스토리지와 I/O도 학습 속도를 좌우한다
테라바이트 규모 데이터셋을 다루는 학습에서는 HDFS 블록 위치를 고려한 스케줄링(데이터 로컬리티), Parquet·TFRecord 같은 열 지향 압축 포맷, io_uring·libaio를 통한 비동기 I/O, ML 배치 크기에 맞춘 커널 readahead 설정이 성능을 좌우한다. 파이프라인 병렬화 쪽에서는 다음 배치를 미리 CPU 메모리에 올려두는 Dataset Prefetching, 데이터 변환을 여러 스레드로 나누는 방식, NVMe SSD에서 GPU로 CPU를 거치지 않고 직접 전송하는 GPU Direct Storage, Redis·Memcached를 통한 특징 벡터 캐싱이 쓰인다.
모니터링과 비용 관리
Prometheus는 GPU 사용률·네트워크 대역폭 같은 시스템 메트릭과 학습 손실·추론 지연시간 같은 ML 메트릭을 함께 수집하고, Grafana 대시보드로 시각화하며 이상 상황에 알림을 보낸다. 프로파일링에는 GPU 커널 타임라인을 보는 NVIDIA Nsight Systems, 연산별 시간·메모리를 측정하는 PyTorch Profiler, CPU·커널 이벤트를 추적하는 perf/BPF, Python 레벨 병목을 잡는 cProfile/line_profiler가 쓰인다.
비용 최적화는 클라우드 학습 비용을 줄이는 핵심 전략이다. 주기적으로 모델 상태를 저장해 중단 시 재시작하는 체크포인팅, Kubernetes 클러스터에 스팟 인스턴스 노드를 추가하는 Preemptible Nodes, 중요한 작업은 온디맨드로 실험은 스팟으로 나누는 우선순위 클래스, 스팟 인스턴스 중단 시 자동으로 작업을 재개하는 자동 재시도가 함께 맞물린다. 자원 활용률을 높이는 쪽에서는 여러 팀의 작업을 단일 클러스터에서 돌리는 멀티 테넌시, 야간 시간대 클러스터를 축소하는 오토스케일링, 추론 워크로드가 GPU를 공유하는 방식, 노드당 여러 작업을 밀집 배치하는 Bin Packing이 쓰인다.