05. Scale to zero: 유휴 비용을 0으로¶
GPU가 필요하지만 요청이 드문 경우 유휴 비용을 없앨 수 있나요?
Scale to zero를 사용할 수 있습니다. 이 실험에서 cold start는 471초(약 8분)였고,
MinInstanceCount: 0 외에 Application Auto Scaling 설정이 필요했습니다.
Serverless Inference와 무엇이 다른가요?
GPU가 필요하지 않다면 Serverless Inference도 비교하세요. 설정이 더 단순하고 유휴 인스턴스 비용이 없습니다. 실측 결과는 06 Serverless Inference에 있습니다.
Serverless Inference는 GPU를 지원하지 않으며 memory 상한은 6144MB입니다.
ServerlessConfig에는 accelerator field가 없습니다. GPU가 필요하면 이 시나리오의
ManagedInstanceScaling을 검토하세요.
| 05 (여기) | 06 서버리스 | |
|---|---|---|
| GPU | ✅ | ❌ |
| 콜드 스타트 | 471초 | 43초 (Provisioned Concurrency 켜면 9.7초) |
| 유휴 과금 종료 | 27분 후 | 즉시 |
축소 대기 중에도 과금됩니다
인스턴스 수가 0이 되기 전까지 비용이 계속 발생합니다. 이 실험에서는 트래픽 중단 후 0이 되기까지 27분이 걸렸습니다.
MinInstanceCount=0 외에 auto scaling 설정이 필요합니다¶
endpoint_config에 ManagedInstanceScaling.MinInstanceCount: 0을 넣으면 API validation은
통과하지만, 이 설정만으로 인스턴스 수가 0이 되지는 않습니다.
Application Auto Scaling에 inference component의 copy 수를 scalable target으로 등록하고 scaling policy를 구성해야 합니다.
| # | 설정 | 역할 | 없으면 |
|---|---|---|---|
| 1 | ManagedInstanceScaling MinInstanceCount: 0 |
인스턴스 수 0 허용 | 인스턴스가 최소 1대 유지 |
| 2 | register_scalable_target MinCapacity: 0 |
copy 수의 하한을 0으로 설정 | 축소가 시작되지 않음 |
| 3 | StepScaling + NoCapacityInvocationFailures alarm |
copy가 0일 때 scale-out 실행 | 0에서 자동 복구 불가 |
Copy가 0인 상태에서 요청이 들어오면 실행 대상이 없어 CloudWatch에
NoCapacityInvocationFailures metric이 기록됩니다. 이 metric의 alarm이 scale-out action을
실행합니다. alarm이 없으면 copy가 0인 endpoint가 자동으로 scale-out되지 않습니다.
aas = boto3.client("application-autoscaling")
resource_id = f"inference-component/{ic_name}"
dim = "sagemaker:inference-component:DesiredCopyCount"
# 2) copy를 0 까지 줄일 수 있게 등록
aas.register_scalable_target(
ServiceNamespace="sagemaker", ResourceId=resource_id, ScalableDimension=dim,
MinCapacity=0, # ← 0 이어야 scale to zero
MaxCapacity=2,
)
# 3) 0 에서 복구하는 경로 (StepScaling + CloudWatch 알람)
cw.put_metric_alarm(
MetricName="NoCapacityInvocationFailures", # copy 0 일 때 올라가는 지표
Namespace="AWS/SageMaker",
Dimensions=[{"Name": "InferenceComponentName", "Value": ic_name}],
AlarmActions=[step_policy_arn],
Period=30, EvaluationPeriods=1, Threshold=1,
ComparisonOperator="GreaterThanOrEqualToThreshold",
TreatMissingData="missing",
)
deploy.py가 세 설정을 만들고, common.cleanup이 scalable target, policy, alarm까지
삭제합니다.
inference component가 필요합니다
Scalable dimension이 sagemaker:inference-component:DesiredCopyCount이므로 inference
component 구성이 필요합니다. 이 시나리오는 03의 endpoint 구성을 확장합니다.
축소 판정이 15분 단위입니다
TargetTracking이 만드는 AlarmLow는 Period=10, EvaluationPeriods=90 입니다.
즉 10초 × 90 = 15분 연속으로 지표가 낮아야 축소가 시작됩니다. 트래픽을 멈춘
직후부터 재면 최소 15분은 인스턴스 비용을 더 내야 합니다.
Scale-out은 더 짧은 주기로 평가됩니다. scale-in과 scale-out의 평가 조건이 다르므로 실제 축소 시간은 policy와 traffic pattern으로 확인해야 합니다.
어느 지표로 스케일링해야 할까요?
IC 용 predefined metric은 두 개입니다.
| 지표 | 해상도 | 특징 |
|---|---|---|
SageMakerInferenceComponentInvocationsPerCopy |
1분 | 호출 건수 기반 |
SageMakerInferenceComponentConcurrentRequestsPerCopyHighResolution |
10초 | 동시 요청 기반, 반응이 빠름 |
이 repository는 HighResolution metric을 사용합니다. 10초 해상도이며, 짧은 인코더
요청에서는 동시 요청 수로 현재 부하를 확인할 수 있습니다. 1분 해상도 metric에 같은
EvaluationPeriods를 사용하면 평가 시간이 더 길어집니다.
고해상도 지표는 3시간만 보존됩니다
60초 미만 주기로 발행된 CloudWatch 데이터포인트는 3시간 뒤 원해상도가 사라집니다. 스케일링 판정에는 문제없지만, 나중에 되짚어 분석하려면 그 전에 저장해 두세요.
두 metric은 copy가 0이면 발행되지 않습니다. 0에서 scale-out하는 경로에는
NoCapacityInvocationFailures를 사용합니다.
Serverless와 혼동하지 마세요¶
둘은 다른 기능입니다.
| GPU | 0까지 축소 | 상한 | |
|---|---|---|---|
| Serverless Inference | ❌ 없음 | ✅ | 메모리 6144MB |
ManagedInstanceScaling |
✅ | ✅ MinInstanceCount: 0 |
인스턴스 한도 |
ServerlessConfig에는 accelerator 필드가 아예 없습니다 (MemorySizeInMB,
MaxConcurrency, ProvisionedConcurrency뿐). GPU가 필요하면 Serverless는 선택지가
아닙니다.
ManagedInstanceScaling.MinInstanceCount의 최소값은 0이고 GPU 인스턴스 구성도
create_endpoint_config validation을 통과합니다. --dry-run은 endpoint 인스턴스를 만들지
않지만 실제 scale-in 동작까지 검증하지는 않습니다.
실행¶
# endpoint 인스턴스 생성 전 MinInstanceCount=0 validation 확인
uv run python 05_gpu_scale_to_zero/deploy.py --dry-run
# 03(inference component)에서 만든 endpoint에 적용
uv run python 05_gpu_scale_to_zero/deploy.py --endpoint <03 또는 04 에서 만든 ep>
# 또는 새로 만들기
uv run python 05_gpu_scale_to_zero/deploy.py
# 콜드 스타트 실측
uv run python 05_gpu_scale_to_zero/measure_cold_start.py \
--endpoint <ep> --component <ic>
uv run python -m common.cleanup --delete-all # auto scaling 설정과 실습 리소스 삭제
deploy.py --endpoint는 기존 endpoint에 적용합니다. SageMaker의 endpoint_config는
불변이라, 새 config를 만들고 update_endpoint로 교체합니다.
실측 결과¶
ml.g5.xlarge + mdeberta, inference component 1개, us-east-1 기준입니다.
| 구간 | 실측 | 비고 |
|---|---|---|
| warm latency (p50) | 30.5 ms | 기준값 |
| 트래픽 중단 → 인스턴스 0 | 1595초 (약 27분) | 이 구간은 계속 과금 |
| 콜드 스타트 | 471초 (약 8분) | 0에서 첫 요청 성공까지 |
| 콜드 스타트 / warm 비율 | 15,422배 | |
| 첫 성공 요청 자체 | 438 ms | 이후 30ms 대로 복귀 |
실제로 일어난 순서입니다.
| 시각 | 사건 |
|---|---|
| 19:43 | 트래픽 중단 |
| 19:56 | AlarmLow 발동 → copy 0 (13분 후) |
| 20:09 | 인스턴스 0 도달 (과금 정지) |
| 20:10 | NoCapacityInvocationFailures = 1 발행 |
| 20:10 | step scaling 알람 발동 → copy 1 요청 |
| 20:17 | 첫 요청 성공 |
축소가 두 단계로 일어납니다
IC copy가 먼저 0 이 되고, 인스턴스는 나중에 회수됩니다. 실측에서 copy 0 이 19:56, 인스턴스 0 이 20:09 로 13분 차이가 났습니다. 과금은 인스턴스 기준이므로 copy가 0 이 되어도 그 사이에는 계속 비용이 발생합니다.
트래픽을 멈춘 시점부터 인스턴스 수가 0이 되기까지 27분이 걸렸습니다. 유휴 구간이 이보다 짧으면 축소 전 비용과 cold start를 함께 고려해야 합니다.
복구 중 요청은 실패합니다
copy가 0 인 동안 들어온 요청은 대기하지 않고 즉시 에러입니다.
이 실험에서는 8분 동안 95회 retry한 뒤 첫 성공 응답을 받았습니다. 최초 요청이
NoCapacityInvocationFailures metric을 기록하므로 client는 해당 오류를 처리하고
retry해야 합니다.
콜드 스타트를 줄이는 방법¶
Cold start를 줄일 수 있는 설정은 적용 대상이 서로 다릅니다. 다음 표는 이 repository의 278M 인코더와 HF DLC 구성에 적용할 수 있는지 구분합니다.
| 수단 | 어느 구간 | 이 구성에 적용 |
|---|---|---|
| container image caching | ECR image pull | ✅ 자동 |
| 압축 해제된 모델 형식 | tar.gz 해제 | ✅ API 필드 |
MetricPublishFrequencyInSeconds: 10 |
감지 지연 | ✅ endpoint config |
DataCacheConfig.EnableCaching |
copy 추가 (0 → 1 은 무효) | ✅ 단 효과 제한 |
MinInstanceCount: 1 |
콜드 스타트 자체 | ✅ 유휴 과금 복귀 |
| Fast Model Loader | 모델 로드 | ❌ LLM 전용 |
| Provisioned Concurrency | 컴퓨트 예약 | ❌ 서버리스 전용 |
Container image caching (자동)¶
2026-06에 추가된 기능이며 별도 opt-in이 필요 없습니다. 새 인스턴스를 시작할 때 ECR image pull에 cache를 사용합니다. GPU 인스턴스와 inference component를 지원하며 HF DLC도 대상입니다.
AWS가 공개한 ml.g5.xlarge 예시는 346초에서 216초로 줄었습니다. image 10.6GB, model
6.5GB를 사용한 별도 workload의 결과이므로 이 실습에 같은 비율을 적용할 수는 없습니다.
이름이 비슷한 기능이 두 개입니다
2024-12 의 data cache(DataCacheConfig.EnableCaching)와 2026-06 의 container
image caching 은 다른 기능입니다.
| data cache (2024) | container image caching (2026) | |
|---|---|---|
| 캐시 위치 | 이미 떠 있는 인스턴스 | 새로 띄우는 인스턴스 |
| 캐시 대상 | 이미지 + 모델 아티팩트 | 이미지만 |
| 0 → 1 경로 | ❌ 무효 | ✅ 유효 |
Data cache는 scale to zero의 0에서 1 경로에 적용되지 않습니다. cache가 기존 인스턴스에 있으므로 인스턴스 수가 0이면 사용할 cache도 없습니다. copy를 1에서 2로 늘리는 경로에는 적용됩니다.
2024 data cache 안내의 지원 DLC 목록에는 이 repository가 사용하는
huggingface-pytorch-inference가 없습니다. 목록의
huggingface-pytorch-tgi-inference는 별도 repository입니다.
압축 해제된 모델 형식¶
tar.gz 해제 단계를 없앱니다. 622MB artifact를 쓰는 02 나 06 에서는 의미가 있지만, 471초
중 해제가 차지하는 비중은 이미지 pull 보다 작습니다.
sm.create_model(
ModelName=mn,
ExecutionRoleArn=role,
PrimaryContainer={
"Image": image,
"ModelDataSource": {
"S3DataSource": {
"S3Uri": "s3://bucket/prefix/", # 반드시 / 로 끝나야 합니다
"S3DataType": "S3Prefix",
"CompressionType": "None",
},
},
},
)
서버리스에서는 쓸 수 없습니다
ModelDataSource는 Serverless Inference, multi-model endpoint, batch transform에서
금지됩니다. 그래서 06 서버리스의 622MB 압축 해제는 피할 방법이 없습니다.
S3 콘솔의 "폴더 만들기"로 생긴 0 바이트 객체가 prefix 안에 있으면 배포가 실패합니다.
감지를 빠르게¶
축소 판정과 별개로 복구 감지를 앞당길 수 있습니다.
sm.create_endpoint_config(
EndpointConfigName=epc,
MetricsConfig={
"EnableEnhancedMetrics": True, # invocation 지표에 적용받으려면 필수
"MetricPublishFrequencyInSeconds": 10, # 10/30/60/120/180/240/300, 기본 60
},
...
)
ConcurrentRequestsPerCopy는 원래 10초 주기로 발행되는 고해상도 지표입니다. Application
Auto Scaling에서 쓸 때 enum 이름에 HighResolution이 붙습니다
(SageMakerInferenceComponentConcurrentRequestsPerCopyHighResolution). 표준
InvocationsPerInstance가 60초 주기이므로 감지가 6배 빨라집니다.
scale-out만 빨라집니다
AWS 문서: 트래픽이 줄 때의 scale-in 속도는 표준 지표와 같습니다. 그래서 축소에 걸린 실측 27분은 이 지표로 줄지 않습니다.
Copy가 0이면 이 metric은 발행되지 않습니다. 0에서 scale-out하는 경로에는
NoCapacityInvocationFailures를 사용합니다.
컨테이너를 바꾸면 콜드 스타트도 달라집니다¶
이 repository의 HF DLC 구성에서는 471초였습니다. container가 달라지면 cold start도 달라질 수 있습니다.
07 의 Triton + TensorRT를 쓰면 추론은 빨라지지만(p50 15.4ms) batch shape
마다 엔진을 컴파일합니다. 실측으로 첫 단건 호출 47.7초, 첫 b=8 호출은 컨테이너 응답 제한
60초를 넘어 timeout됐습니다. cache 경로가 /tmp이므로 container를 다시 시작하면 engine을
다시 compile합니다.
trtexec로 사전 컴파일한 .plan을 배포하면 없앨 수 있지만, 엔진이 GPU 아키텍처에 묶입니다
(A10G 용은 T4에서 돌지 않습니다).
Inference latency와 cold start는 별도로 측정해야 합니다. Scale to zero와 TensorRT를 함께 사용할 때는 예상 batch shape의 compile 시간을 포함해 검증하세요.
적용할 수 없는 것들¶
Fast Model Loader 는 지원 모델이 Llama, Mistral, Mixtral 계열뿐이고 인코더는 목록에
없습니다. ModelShardingConfig.Image가 LMI DLC만 받아서 HF DLC로는 쓸 수 없고,
OPTION_TENSOR_PARALLEL_DEGREE가 필수인데 ml.g5.xlarge는 GPU 1장이라 샤딩할 것이
없습니다. 현재 기준이므로 지원 목록은 재확인하세요.
Provisioned Concurrency 는 ProductionVariantServerlessConfig 안에만 있는 필드입니다.
Instance-based endpoint에는 대응 필드가 없습니다. GPU로 콜드 스타트를 없애려면
MinInstanceCount: 1로 두면 항상 인스턴스를 유지하므로 cold start는 피할 수 있지만 유휴
시간에도 비용이 발생합니다.
정보 기준 시점
2026-08-07 확인입니다. container image caching은 AWS What's New와 블로그에만 있고 개발자 안내서에 해당 페이지가 아직 없습니다. 지원 인스턴스와 리전 목록도 열거되어 있지 않으니 배포 전에 재확인하세요.
무엇을 측정하나요¶
measure_cold_start.py가 다음 세 구간을 순서대로 측정합니다.
- Warm latency: 기준값
- 0으로 축소되기까지의 시간: 이 구간은 아직 과금됩니다
- 콜드 스타트: 0에서 첫 요청이 성공하기까지
3번이 판단 기준입니다. 인스턴스 프로비저닝, 컨테이너 시작, 모델 로드가 전부 필요하므로 수십 초에서 수 분이 걸립니다. 그 사이 요청은 실패하거나 대기합니다.
주의할 점¶
- 축소 시간은 scaling policy와 traffic pattern에 따라 달라집니다. 인스턴스 수가 0이 되기 전까지 비용이 발생합니다.
- 실시간 응답이 필요하면
MinInstanceCount: 1로 두세요. scale to zero는 배치성 워크로드나 사내 도구처럼 첫 요청이 느려도 되는 경우에 맞습니다. - LLM 답변 검증이 사용자 요청 경로에 있다면 콜드 스타트가 그대로 사용자에게 노출됩니다. 오프라인 검증 파이프라인이라면 문제가 없습니다.
전체 실측 결과: docs/concepts/findings.md