콘텐츠로 이동

02. 멀티컨테이너 endpoint: CPU co-host

경량 인코더 여러 개를 CPU 인스턴스 하나에 올려 각각 호출할 수 있을까요?

가능합니다. 이 실험에서는 ONNX Runtime의 p50이 58ms였습니다.

런타임 b=1 p50
PyTorch 1810 ms
ONNX Runtime 58 ms

ONNX Runtime의 p50은 PyTorch보다 31배 낮았습니다. 검증 sample에서 두 출력은 소수점 6자리까지 일치했습니다. GPU(28ms)보다 latency는 높지만 인스턴스 비용은 낮습니다. 이 모델의 CPU 배포에는 ONNX Runtime 경로를 사용합니다.

이 방식은 GPU를 쓸 수 없습니다

Direct 모드는 GPU 인스턴스를 지원하지 않습니다. 확인한 AWS 문서에는 이 조건이 명시되어 있지 않았습니다. GPU co-host가 필요하면 04_gpu_cohost_lmi를 검토하세요.

uv run python 02_cpu_cohost_multicontainer/deploy.py --prove-gpu-fails   # endpoint 인스턴스 없음

멀티컨테이너 endpoint의 구조

멀티컨테이너 endpoint 구조와 Serial / Direct 호출 방식

인스턴스 한 대 안에 컨테이너를 최대 15개까지 띄우고, 컨테이너마다 다른 이미지와 프레임워크를 쓸 수 있습니다. 모델을 미리 로드해 두므로 multi-model endpoint와 달리 콜드 스타트가 없습니다.

멀티컨테이너 endpoint는 SerialDirect 두 호출 방식을 제공합니다.

Serial (직렬) Direct (직접)
요청 흐름 전처리 → 추론 → 후처리 로 체인 대상 컨테이너 하나만 호출
대상 지정 불가 (전체를 통과) TargetContainerHostname
용도 추론 파이프라인 co-host (모델별 독립 호출)
GPU ✅ 가능 거부됨

co-host에는 대상 container를 지정할 수 있는 Direct mode가 필요하지만 이 mode는 GPU 인스턴스를 지원하지 않습니다. 같은 GPU image로 Serial mode를 만들면 API validation을 통과하므로 제한은 멀티컨테이너 전체가 아니라 Direct mode에 적용됩니다.

요청 payload 상한은 6MB, timeout은 60초입니다. 이 실습의 512-token NLI payload는 수 KB 수준입니다.

실행

# 1) ONNX 변환 (별도 venv를 자동 생성, 약 1분)
uv run python 02_cpu_cohost_multicontainer/scripts/export_onnx.py --models mdeberta minilm

# 2) 출력된 URI를 export
export ONNX_S3_MDEBERTA=s3://...
export ONNX_S3_MINILM=s3://...

# 3) 배포
uv run python 02_cpu_cohost_multicontainer/deploy.py --onnx --dry-run   # endpoint 인스턴스 생성 전 확인
uv run python 02_cpu_cohost_multicontainer/deploy.py --onnx

# 4) 호출: TargetContainerHostname으로 대상 지정
uv run python 02_cpu_cohost_multicontainer/invoke.py --endpoint <ep> --mode cloud --all
uv run python -m benchmark.run --mode cloud --endpoint <ep> \
    --target-container mdeberta --pad-to-max --sweep-batch

uv run python -m common.cleanup --delete-all     # 실습 리소스 삭제

이 방식의 특징

컨테이너를 최대 15개까지 올리고 TargetContainerHostname으로 골라 부릅니다.

장점: container마다 서로 다른 image를 사용할 수 있습니다. 이 실험에서 비교한 co-host 구성 중 시간당 비용이 가장 낮았습니다.

제약: GPU를 사용할 수 없고 모델을 추가하면 endpoint를 다시 생성해야 합니다. scaling도 인스턴스 단위로 적용됩니다.

모델별로 스케일할 수 없습니다

이 방식의 가장 큰 제약입니다. 스케일아웃하면 컨테이너 구성이 인스턴스마다 통째로 복제됩니다. 인스턴스를 2대로 늘리면 15개 컨테이너가 양쪽에 다 뜨고, 부하가 몰리는 모델 하나만 늘릴 방법이 없습니다.

인스턴스 1대                    스케일아웃 후 (2대)
┌──────────────────┐          ┌──────────────────┐  ┌──────────────────┐
│ mdeberta │ minilm│    →     │ mdeberta │ minilm│  │ mdeberta │ minilm│
└──────────────────┘          └──────────────────┘  └──────────────────┘
                               mdeberta만 늘리는 것은 불가능

오토스케일링 지표가 InvocationsPerInstance 라서 인스턴스 단위로만 판단합니다. AWS 문서도 이 한계를 이렇게 설명합니다.

각 컨테이너의 모델이 요청마다 비슷한 CPU 사용률과 latency 를 보이는 것을 권장합니다. 트래픽이 CPU 사용률이 낮은 모델에서 높은 모델로 옮겨 가면 전체 호출량은 같으므로 Endpoint가 스케일아웃하지 않고, 높은 사용률 모델의 요청을 처리할 인스턴스가 부족해질 수 있습니다.

, Autoscale multi-container endpoints

크기와 CPU 사용률이 크게 다른 모델을 함께 배포하면 InvocationsPerInstance만으로 부하 변화를 감지하기 어렵습니다. 모델별 traffic과 resource 사용량이 비슷한지 먼저 확인하세요.

인프라로 보면 inference pipeline과 거의 같습니다

두 방식 모두 인스턴스 한 대에 컨테이너 여러 개를 띄우고 함께 복제합니다. 차이는 호출 방식뿐입니다.

inference pipeline (Serial) 멀티컨테이너 Direct
인프라 구조 인스턴스에 컨테이너 N개 같음
스케일 단위 인스턴스 같음
호출 전체를 체인으로 통과 컨테이너를 골라 호출
제어권 파이프라인 순서만 어느 컨테이너든 지정 가능

Direct mode는 container별 호출을 지원하지만 모델별 자원 배정이나 독립 scaling은 제공하지 않습니다. 해당 기능이 필요하면 03 inference componentCopyCount를 검토하세요.

놓치기 쉬운 것들

Mode: Direct를 생략하면 기본값이 Serial입니다. 그러면 컨테이너가 파이프라인으로 연결되어 골라 부를 수 없습니다.

InferenceExecutionConfig={"Mode": "Direct"}     # 생략 금지

TargetContainerHostname은 필수입니다. 없는 이름을 주거나, 지정하지 않거나, Direct가 아닌 endpoint에 주면 세 경우 모두 validation error입니다. 확인:

uv run python 02_cpu_cohost_multicontainer/invoke.py --endpoint <ep> --mode cloud \
    --show-missing-target-error

Worker를 1개로 제한합니다. ONNX session이 worker마다 모델을 따로 로드하므로 여러 worker를 사용하면 큰 모델 process가 메모리 부족으로 종료될 수 있습니다. deploy.py가 이 값을 설정합니다.

이 mDeBERTa 모델에는 INT8 quantization 결과를 사용하지 않습니다. 검증 sample의 예측이 모두 neutral로 바뀌었습니다(1/4). 이 실습은 fp32 model을 사용합니다.

막힌 경우 → docs/troubleshooting.md

다음으로 읽을 것

실측 근거: docs/concepts/findings.md, docs/benchmark/results.md