
현대적인 MLOps 아키텍처에서 MLflow는 실험 추적과 모델 관리를 위한 표준으로 자리 잡았습니다. 하지만 데이터 과학팀이 직면하는 가장 큰 병목 현상 중 하나는 대규모 모델 가중치(Weights)와 데이터셋을 저장하고 불러오는 '아티팩트(Artifact)' 관리입니다. 본 가이드는 2026년 최신 인프라 환경을 기준으로 S3(Object Storage)와 NFS(File Storage)의 성능 차이를 심층 분석하고, 엔지니어가 현업에서 즉시 적용할 수 있는 7가지 최적화 예제를 제공합니다.
1. MLflow 아티팩트 저장소의 두 축: S3 vs NFS 비교
실험의 규모와 팀의 인프라 성격에 따라 선택 기준은 달라집니다. 클라우드 네이티브 환경과 온프레미스 고성능 컴퓨팅(HPC) 환경에서의 차이를 아래 표를 통해 확인하십시오.
| 비교 항목 | Amazon S3 (객체 저장소) | NFS (네트워크 파일 시스템) | 기술적 차이 및 해결 포인트 |
|---|---|---|---|
| 확장성 | 무제한 (수평적 확장) | 제한적 (스토리지 용량 증설 필요) | 데이터 폭증 시 S3가 유리 |
| 액세스 방식 | HTTP/HTTPS API | POSIX Mount (로컬 경로) | NFS는 기존 코드 수정 최소화 가능 |
| 지연 시간 (Latency) | 상대적으로 높음 (TTFB 발생) | 매우 낮음 (로컬 입출력 수준) | 체크포인트 잦은 경우 NFS 권장 |
| 비용 구조 | 사용한 만큼 지불 (종량제) | 인프라 구축 및 유지 관리비 | 클라우드 환경에선 S3가 경제적 |
| 병렬 처리 | 강력한 동시 읽기/쓰기 지원 | 파일 락킹(Locking) 이슈 발생 가능 | 대규모 워커 운영 시 S3 안정성 우위 |
2. 개발자를 위한 아티팩트 저장소 최적화 실전 Example (7가지)
다음은 MLflow 서버 설정부터 파이썬 코드 레벨에서의 성능 최적화까지, 실무에서 바로 복사하여 사용할 수 있는 예제들입니다.
Example 1: S3를 백엔드로 사용하는 MLflow 서버 실행
가장 표준적인 클라우드 기반 설정 방법입니다.
# MLflow 추적 서버 실행 (S3 아티팩트 경로 설정)
mlflow server \
--backend-store-uri postgresql://user:pass@localhost/mlflowdb \
--default-artifact-root s3://my-mlflow-artifacts/ \
--host 0.0.0.0
Example 2: NFS 마운트 경로를 활용한 빠른 아티팩트 로깅
NFS는 로컬 파일 시스템처럼 인식되므로 경로 지정이 직관적입니다.
import mlflow
# NFS가 마운트된 로컬 경로 설정
nfs_path = "file:///mnt/nfs/mlflow_artifacts"
mlflow.set_tracking_uri("http://localhost:5000")
with mlflow.start_run(run_name="NFS_Storage_Test"):
mlflow.log_param("optimizer", "adam")
# 대용량 모델 파일 저장 시 로컬 쓰기 속도 활용
mlflow.log_artifact("/tmp/large_model.bin", artifact_path="models")
Example 3: Boto3를 활용한 S3 멀티파트 업로드 최적화
대규모 모델 파일을 S3에 올릴 때 병렬 업로드를 통해 시간을 단축하는 방법입니다.
import boto3
from boto3.s3.transfer import TransferConfig
# 100MB 이상 파일에 대해 멀티파트 업로드 활성화
config = TransferConfig(multipart_threshold=1024 * 100, max_concurrency=10)
s3 = boto3.client('s3')
def upload_to_mlflow_s3(local_path, s3_bucket, s3_key):
s3.upload_file(local_path, s3_bucket, s3_key, Config=config)
print(f"Optimized Upload Finished: {s3_key}")
Example 4: 런타임 중 아티팩트 저장소 동적 전환 해결
환경에 따라 S3와 로컬(NFS) 저장소를 전환하는 유연한 코드 구조입니다.
import os
import mlflow
def get_artifact_uri():
if os.getenv("ENV") == "production":
return "s3://prod-artifacts"
else:
return "file:///mnt/nfs/dev-artifacts"
mlflow.create_experiment("Dynamic_Storage_Exp", artifact_location=get_artifact_uri())
Example 5: 아티팩트 비동기 로깅을 통한 학습 속도 저하 해결
학습 루프 내에서 업로드가 완료될 때까지 기다리지 않고 백그라운드에서 처리합니다.
import threading
import mlflow
def async_log_artifact(local_path):
thread = threading.Thread(target=mlflow.log_artifact, args=(local_path,))
thread.start()
with mlflow.start_run():
# 학습 코드...
async_log_artifact("checkpoint_epoch_10.pt")
Example 6: NFS 파일 락(Lock) 충돌 방지를 위한 유니크 경로 생성
분산 학습 시 여러 노드가 같은 NFS 폴더에 쓸 때 발생하는 문제를 해결합니다.
import uuid
import mlflow
# 노드별 고유 ID를 부여하여 경로 충돌 해결
node_id = str(uuid.uuid4())[:8]
with mlflow.start_run():
mlflow.log_artifact("results.csv", artifact_path=f"results_{node_id}")
Example 7: MLflow 아티팩트 가비지 컬렉션(GC) 자동화
저장소 비용 절감을 위해 오래된 실험 데이터를 삭제하는 스크립트입니다.
from mlflow.tracking import MlflowClient
client = MlflowClient()
# 특정 기간 지난 실험 데이터 정리 (예시 로직)
def cleanup_old_runs(experiment_id, days=30):
runs = client.search_runs(experiment_id)
for run in runs:
# 시간 비교 후 삭제
# client.delete_run(run.info.run_id)
pass
3. 성능 향상을 위한 아키텍처 해결 가이드
실제 엔터프라이즈 환경에서는 S3와 NFS 중 하나만 선택하는 것이 아니라, 두 저장소의 장점을 결합한 하이브리드 전략을 취하는 경우가 많습니다.
- 해결책 1: 학습 노드와 저장소 사이의 네트워크 대역폭을 확인하십시오. S3의 경우 VPC 엔드포인트를 사용하여 보안과 속도를 동시에 잡을 수 있습니다.
- 해결책 2: NFS를 사용한다면 'noatime' 마운트 옵션을 사용하여 메타데이터 업데이트 오버헤드를 줄이십시오.
- 해결책 3: 모델 로깅 시 모든 파일을 올리기보다 핵심 체크포인트만 선별적으로 로깅하여 I/O 부하를 최소화하십시오.
4. 결론: 어떤 저장소를 선택해야 하는가?
결론적으로 확장성과 클라우드 관리의 편의성을 중시한다면 S3가 압승입니다. 반면, 초고속 학습 피드백과 온프레미스 GPU 클러스터를 운영 중이라면 NFS가 더 나은 성능을 보여줍니다. 팀의 워크로드 성격에 맞춰 위 예제 코드를 변형 적용해 보시기 바랍니다.
5. 참고 문헌 및 출처
- MLflow 공식 문서: "Artifact Stores Overview"
- AWS Architecture Blog: "Optimizing S3 Performance for Machine Learning"
- NVIDIA Developer Blog: "Accelerating AI Workflows with Network Storage"
- Databricks: "Managing Machine Learning Experiments at Scale"