- Published on
SageMaker 엔드포인트 5xx·타임아웃 원인 9가지
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
SageMaker 실시간 엔드포인트는 InvokeEndpoint 호출이 성공하더라도 내부적으로는 컨테이너, 모델 로딩, 오토스케일링, 네트워크, 그리고 애플리케이션 코드까지 여러 계층을 통과합니다. 그래서 5xx 와 타임아웃은 “한 가지 원인”이 아니라, 요청 경로 어디에서 병목이나 실패가 발생했는지를 좁혀가는 방식으로 접근해야 합니다.
이 글에서는 운영에서 자주 마주치는 SageMaker 엔드포인트 5xx·타임아웃 원인 9가지를 증상, 확인 지표, 해결책 중심으로 정리합니다.
참고로 타임아웃 이슈는 로드밸런서나 게이트웨이의 유휴 타임아웃과도 결합됩니다. EKS 환경에서
504가 60초로 끊기는 패턴은 이 글도 함께 보면 좋습니다: EKS ALB Ingress 504(60초) idle_timeout 해결
먼저: 5xx·타임아웃을 어디서 확인하나
진단은 “요청이 어디서 실패했는지”를 분리하는 것부터 시작합니다.
- CloudWatch 지표(엔드포인트)
Invocations,Invocation4XXErrors,Invocation5XXErrorsModelLatency,OverheadLatencyCPUUtilization,MemoryUtilization,GPUUtilization(GPU 인스턴스)
- CloudWatch Logs
/aws/sagemaker/Endpoints/엔드포인트명- 컨테이너 stdout, stderr, 프레임워크별 서버 로그(TorchServe, MMS, custom gunicorn 등)
- SageMaker
DescribeEndpoint/DescribeEndpointConfig- 인스턴스 타입, 초기 인스턴스 수, 모델 아티팩트,
ContainerStartupHealthCheckTimeoutInSeconds등
- 인스턴스 타입, 초기 인스턴스 수, 모델 아티팩트,
아래 코드는 엔드포인트 지표를 빠르게 조회하는 예시입니다.
import boto3
from datetime import datetime, timedelta, timezone
cw = boto3.client("cloudwatch")
endpoint = "my-endpoint"
end = datetime.now(timezone.utc)
start = end - timedelta(hours=1)
def metric(name, stat="Sum", period=60):
return cw.get_metric_statistics(
Namespace="AWS/SageMaker",
MetricName=name,
Dimensions=[{"Name": "EndpointName", "Value": endpoint}],
StartTime=start,
EndTime=end,
Period=period,
Statistics=[stat],
)["Datapoints"]
print("5XX:", metric("Invocation5XXErrors"))
print("Latency:", metric("ModelLatency", stat="Average"))
print("Overhead:", metric("OverheadLatency", stat="Average"))
ModelLatency가 높으면 “모델 추론 자체”가 느린 경우가 많습니다.OverheadLatency가 높으면 “컨테이너 바깥 오버헤드” (직렬화, 라우팅, 큐잉, 네트워크, 런타임 준비 등) 가능성이 큽니다.
원인 1) 콜드 스타트: 모델 다운로드·로딩이 느림
대표 증상
- 배포 직후 또는 오토스케일로 새 인스턴스가 붙은 직후
5xx또는 타임아웃 - 특정 시간대(트래픽 스파이크 직후)에만 오류가 집중
확인 방법
- 엔드포인트 로그에서 모델 로딩 메시지가 오래 지속
ModelLatency보다OverheadLatency가 비정상적으로 치솟기도 함
해결책
- 모델 아티팩트 크기 축소(불필요 파일 제거, 압축 최적화)
- 컨테이너 시작 시 가중치 로딩을 지연시키지 말고, readiness 이전에 끝내기
ContainerStartupHealthCheckTimeoutInSeconds를 늘려 “헬스체크 실패로 교체 반복”을 막기
import boto3
sm = boto3.client("sagemaker")
# 엔드포인트 설정에서 startup health check timeout을 늘리는 예시
# 실제로는 EndpointConfig를 새로 만들고 UpdateEndpoint 해야 합니다.
print(sm.describe_endpoint_config(EndpointConfigName="my-endpoint-config"))
원인 2) 오토스케일링 지연: 트래픽 급증에 비해 스케일이 늦음
대표 증상
- 평소엔 정상인데 피크에
Invocation5XXErrors증가 InvocationsPerInstance가 급격히 상승ModelLatency가 계단식으로 증가한 뒤 실패
확인 방법
- Application Auto Scaling 이벤트, CloudWatch 알람 히스토리
- 스케일 아웃이 발생했는데 실제 인스턴스 준비까지 시간이 오래 걸림
해결책
- 최소 인스턴스 수를
1이상으로 유지(항상 웜 상태) - 스케일 정책을 보수적으로(더 빨리) 조정
- 트래픽 패턴이 예측 가능하면 스케줄 기반 스케일링 고려
원인 3) 인스턴스 리소스 부족: CPU·메모리·GPU OOM
대표 증상
- 간헐적
500또는 컨테이너 재시작 - 특정 입력에서만 실패(큰 이미지, 긴 시퀀스 등)
- 로그에
Killed,OOM,CUDA out of memory류 메시지
확인 방법
- CloudWatch
MemoryUtilization급등 후 오류 - GPU 사용률과 GPU 메모리(프레임워크 로그 또는 커스텀 지표) 확인
해결책
- 배치 크기 축소, 입력 크기 제한, 토큰 길이 제한
- 모델 양자화, mixed precision
- 더 큰 인스턴스 또는 GPU 인스턴스로 변경
이미지/생성 모델 계열은 VRAM 이슈가 특히 잦습니다. 유사한 최적화 아이디어는 이 글도 참고할 만합니다: Stable Diffusion VRAM OOM, xFormers·Tiled VAE로 해결
원인 4) 컨테이너 서버 설정 문제: 워커 수·타임아웃·큐잉
SageMaker는 컨테이너 내부에 웹 서버(예: gunicorn, uvicorn, TorchServe 등)가 떠서 요청을 처리합니다. 여기서 워커 수가 과하거나, 타임아웃이 너무 짧거나, 동시성 제어가 없으면 스레드/프로세스 경합으로 타임아웃이 터집니다.
대표 증상
ModelLatency가 들쭉날쭉하고 tail latency가 큼- 동시 요청에서만 실패
확인 방법
- 컨테이너 로그에서 request queueing, worker timeout, restart 흔적
- CPU utilization 이
100%근처에서 고정
해결책
- 워커 수를 CPU 코어에 맞게 조정
- 요청당 최대 처리 시간에 맞게 서버 타임아웃 조정
- 동시 처리량을 제한하고(세마포어), 과부하 시 빠르게
429로 실패시키는 전략도 고려
# 예: FastAPI에서 동시 처리 제한(간단한 세마포어)
import asyncio
from fastapi import FastAPI, HTTPException
app = FastAPI()
sem = asyncio.Semaphore(4)
@app.post("/invocations")
async def invocations(payload: dict):
if sem.locked():
raise HTTPException(status_code=429, detail="busy")
async with sem:
# heavy inference
return {"ok": True}
과부하 제어(레이트리밋, 오토스케일링) 관점은 BentoML 사례지만 패턴은 동일합니다: BentoML 서빙 429 폭주 대응 - 오토스케일·레이트리밋
원인 5) 요청/응답 페이로드 문제: 크기 제한·직렬화 실패
대표 증상
- 특정 요청만
5xx또는4xx로 실패 - base64 이미지나 대용량 JSON에서 오류 급증
확인 방법
- 클라이언트에서 전송한
Content-Type,Content-Length확인 - 컨테이너 로그에 JSON decode error, payload too large 등
해결책
- 입력을 S3에 두고 키만 전달하는 방식으로 변경
- 압축, 바이너리 포맷(예:
application/x-npy) 고려 - 서버에서 입력 검증을 선제적으로 수행하고 명확히
4xx로 반환
원인 6) 네트워크/VPC 설정: NAT, 보안그룹, 엔드포인트 접근
VPC에 붙인 엔드포인트가 외부 리소스(S3, ECR, 외부 API)를 호출할 때 NAT 게이트웨이, VPC 엔드포인트, 보안그룹이 꼬이면 “처음엔 되다가” 갑자기 타임아웃이 납니다.
대표 증상
- 모델 다운로드(S3) 또는 이미지 pull(ECR) 단계에서 멈춤
- 외부 API 호출이 있는 경우 특정 AZ에서만 타임아웃
확인 방법
- VPC Flow Logs, NAT 게이트웨이 지표
- 컨테이너 로그에서 DNS resolve failure, connect timeout
해결책
- S3 Gateway Endpoint, ECR Interface Endpoint 구성
- 보안그룹 egress, NACL 점검
- 외부 호출이 꼭 필요하면 타임아웃/재시도/서킷브레이커 구현
원인 7) 멀티모델 또는 모델 캐시 문제: 디스크 공간·eviction
Multi-Model Endpoint 또는 모델을 동적으로 로딩하는 패턴은 인스턴스 로컬 디스크(EBS) 사용량과 eviction 정책에 영향을 크게 받습니다.
대표 증상
- 시간이 지날수록 5xx 증가
- 특정 모델만 유독 느리거나 실패
- 디스크 부족으로 로딩 실패
확인 방법
- 로그에서 “no space left on device” 류 메시지
- 인스턴스 스토리지 사용량(커스텀 지표 필요)
해결책
- 모델 수를 줄이거나, 모델 크기 최적화
- 캐시 디렉터리 정리, eviction 전략 설계
- 엔드포인트를 모델별로 분리하는 것이 더 안정적인 경우도 많음
원인 8) 헬스체크/리드니스 미흡: 살아있지만 준비 안 됨
컨테이너가 프로세스는 떠 있지만 모델이 아직 로딩 중이거나, GPU 초기화가 끝나지 않았는데 트래픽이 들어오면 5xx 가 납니다. 특히 커스텀 컨테이너에서 /ping 과 /invocations 구현이 부실할 때 자주 발생합니다.
대표 증상
- 배포 직후
5xx후 안정화 - 로그에 초기화 중 예외
확인 방법
/ping응답이 너무 빨리200을 반환하는지 확인- readiness 조건(모델 로딩 완료 여부)을 로그로 남기기
해결책
/ping에서 “모델 로딩 완료”를 확인한 뒤에만200반환- 초기화 실패 시 빠르게 프로세스를 종료하여 교체가 일어나게 하기
# 간단한 readiness 플래그 예시(Flask)
from flask import Flask, Response, request
app = Flask(__name__)
ready = False
@app.route("/ping", methods=["GET"])
def ping():
return Response(status=200 if ready else 503)
@app.route("/invocations", methods=["POST"])
def invoke():
if not ready:
return Response("not ready", status=503)
# inference...
return {"ok": True}
def load_model():
global ready
# heavy init...
ready = True
원인 9) 클라이언트 타임아웃·재시도 폭주: 실패를 증폭
서버가 느려지기 시작하면 클라이언트의 공격적인 재시도(특히 짧은 타임아웃)로 트래픽이 폭증하고, 결국 5xx 와 타임아웃이 “연쇄적으로” 증가합니다.
대표 증상
- 트래픽이 실제 사용자 수보다 과도하게 튐
- 서버가 회복 직전에 다시 과부하로 떨어짐
확인 방법
- 클라이언트 로그에서 동일 요청의 반복
Invocations대비 비즈니스 이벤트 수가 비정상
해결책
- 클라이언트 타임아웃을 현실적으로 설정(모델 p95 기준)
- 지수 백오프와 지터 적용
- 멱등성 키를 도입하거나, 재시도 가능한 에러만 재시도
# boto3 호출에 타임아웃/재시도 정책을 명시하는 예시
import boto3
from botocore.config import Config
cfg = Config(
read_timeout=70,
connect_timeout=5,
retries={"max_attempts": 3, "mode": "standard"},
)
rt = boto3.client("sagemaker-runtime", config=cfg)
resp = rt.invoke_endpoint(
EndpointName="my-endpoint",
ContentType="application/json",
Body=b"{\"text\": \"hello\"}",
)
print(resp["Body"].read())
실전 체크리스트: 15분 안에 범위 좁히기
Invocation5XXErrors와ModelLatency/OverheadLatency를 같은 시간축으로 비교- 오류가 배포/스케일 이벤트와 맞물리는지 확인(콜드 스타트 의심)
- CPU·메모리·GPU 지표가 상한에 붙는지 확인(OOM 또는 경합)
- 컨테이너 로그에서
OOM, worker timeout, decode error 같은 “명확한 문자열”을 찾기 - 입력 크기/형식이 특정 케이스에서만 커지는지 확인
- VPC 환경이면 S3/ECR 접근 경로(NAT, VPC 엔드포인트)부터 점검
- 클라이언트 재시도 정책이 장애를 증폭시키는지 확인
마무리: 5xx는 결과, 원인은 계층별로 다르다
SageMaker 엔드포인트의 5xx 와 타임아웃은 대개
- 콜드 스타트와 스케일 지연,
- 리소스 부족(OOM 포함),
- 컨테이너 서버의 동시성/타임아웃 설정,
- 네트워크 경로,
- 클라이언트 재시도 정책 중 하나(또는 복합)로 수렴합니다.
가능하면 다음을 기본값으로 가져가면 장애 빈도가 크게 줄어듭니다.
- 최소 인스턴스
1유지로 콜드 스타트 제거 - p95 기준으로 서버·클라이언트 타임아웃 정렬
- 입력 크기 상한과 빠른
4xx처리 - 과부하 시
429로 빠르게 실패시키는 전략과 오토스케일 튜닝
원하시면 사용 중인 스택(예: PyTorch + TorchServe, Hugging Face DLC, custom FastAPI)과 인스턴스 타입, 평균/최대 입력 크기, 현재 타임아웃 값을 알려주시면 9가지 중 어디를 먼저 파야 하는지 우선순위로 좁혀서 체크리스트를 더 구체화해 드릴게요.