스프린트미션

위클리 페이퍼 #17

goodella 2026. 7. 6. 03:45

 

1. 모델 서빙(Model Serving)의 본질과 필요성

모델 서빙이란 무엇인가?

학습이 완료된 머신러닝/딥러닝 모델을 파일 형태(e.g., .pth, .onnx, .saved_model)로 방치하지 않고, 외부 애플리케이션이 네트워크(HTTP, gRPC)를 통해 실시간 혹은 배치로 추론(Inference) 결과를 요청하고 받아갈 수 있도록 API 형태로 패키징하여 운영 환경에 노출하는 과정을 말합니다.

왜 필요한가? (기존 소프트웨어와의 차이점)

전통적인 백엔드 애플리케이션은 데이터의 연산 처리가 CPU와 메모리 바운드(Memory-bound) 성격을 띠며 예측 가능한 선형적 흐름을 갖습니다. 반면 ML 추론은 다음과 같은 독특한 제약 조건을 가집니다.

  • 무거운 리소스 집약성 (Heavy Compute-bound): 수천만~수십억 개의 파라미터를 가진 행렬 연산은 CPU만으로 처리가 불가능하거나 극도로 느립니다. GPU 자원의 효율적 배분이 필수적입니다.
  • 컴퓨팅 예측 불가능성: 입력 데이터(이미지 크기, 텍스트 길이)에 따라 연산 병목과 메모리 스파이크(OOM: Out Of Memory)가 빈번히 발생합니다.
  • 동적 가용성 요구: 주기적인 모델 재학습 및 배포가 서비스 중단(Zero-downtime) 없이 이루어져야 합니다.

실제 서비스 환경에서 서빙 프레임워크의 역할

FastAPI나 Flask 같은 범용 웹 프레임워크로도 추론 API를 만들 수는 있습니다. 하지만 트래픽이 몰리는 프로덕션 환경에서 Triton Inference Server, TorchServe, TF Serving 같은 전문 서빙 프레임워크를 도입하는 이유는 명확합니다.

  1. 동적 배치 처리 (Dynamic Batching): 개별적으로 들어오는 여러 클라이언트의 요청을 마이크로초 단위로 모아서 하나의 거대한 행렬(Batch)로 묶어 GPU에 전달합니다. GPU는 1개의 요청을 처리할 때와 10개의 요청을 동시에 처리할 때의 속도 차이가 크지 않으므로, 이 기능 하나만으로 처리량(Throughput)이 수배 이상 향상됩니다.
  2. 동시 모델 실행 (Concurrent Model Execution): GPU 메모리가 허용하는 한, 동일한 모델의 인스턴스를 여러 개 띄우거나(Multi-instance) 여러 종류의 모델을 동시에 로드하여 내부적으로 요청을 롸우팅 및 병렬 처리합니다.
  3. 모델 관리 및 동적 로딩 (Model Repository Control): 서버를 재시작하지 않고도 새로운 버전의 모델 파일만 스토리지에 업로드하면 실시간으로 추론 엔진이 갱신(Hot-reload)됩니다.

2. Streamlit + FastAPI + Triton 아키텍처 설계

프로덕션 MLOps 관점에서 세 가지 기술 스택을 결합할 때, 각 컴포넌트의 책임(Single Responsibility)을 엄격히 분리하는 3-Tier 아키텍처가 가장 바람직합니다.

추천 아키텍처 구조

[ Client / Web Browser ]
         │ (HTTP)
         ▼
┌─────────────────────────────────┐
│       Streamlit Window          │  <-- Presentation Layer (UI 전용)
└─────────────────────────────────┘
         │ (REST API / HTTP)
         ▼
┌─────────────────────────────────┐
│         FastAPI Server          │  <-- Business Logic Layer (Gateway & 오케스트레이션)
└─────────────────────────────────┘
         │ (gRPC / Protocol Buffers)
         ▼
┌─────────────────────────────────┐
│     Triton Inference Server     │  <-- Inference Layer (Heavy Compute 전용)
└─────────────────────────────────┘

각 레이어별 역할 분담

  • Streamlit (Presentation Layer):
    • 역할: 사용자 인터페이스(UI) 렌더링, 파일 업로드 컴포넌트 제공, 최종 결과 시각화.
    • 금기 사항: 절대 Streamlit 내부에서 비즈니스 로직을 처리하거나 Triton과 직접 통신해서는 안 됩니다. Streamlit은 단일 세션 지향적이며, 무거운 연산이나 복잡한 에러 핸들링을 내포하기에 적합하지 않습니다.
  • FastAPI (Business Logic & Gateway Layer):
    • 역할: 인증/인가, 입력 데이터 유효성 검증(Pydantic), 요청 파싱, DB CRUD 비즈니스 로직 처리, 그리고 Triton으로의 추론 위임 및 결과 가공.
    • 통신 프로토콜: 외부(Streamlit)와는 HTTP JSON으로 통신하고, 내부(Triton)와는 고속 효율을 위해 gRPC로 통신합니다.
  • Triton Inference Server (Inference Layer):
    • 역할: 순수 모델 추론 연산 가속화, Dynamic Batching 제어. 다른 어떤 백엔드 로직도 관여하지 않고 오직 오퍼레이션(Tensor in, Tensor out)에만 집중합니다.

디자인 인텐트 (Design Intent) & MLOps 고려사항

엔지니어링 철학: 백엔드와 AI 추론 레이어의 분리는 단순히 '깔끔한 코드'를 위함이 아닙니다. 이것은 컴퓨팅 자원의 격리(Resource Isolation)를 의미합니다. CPU 집약적인 비즈니스 로직(FastAPI)과 GPU 집약적인 모델 연산(Triton)을 물리적/논리적으로 분리해야만, 급격한 트래픽 증가 시 어느 구간에서 병목이 생겼는지 모니터링할 수 있고 독립적인 스케일 아웃(Scale-out)이 가능해집니다.

1. 왜 FastAPI와 Triton 사이에 gRPC를 쓰는가?

  • Trade-off: HTTP/REST는 JSON 기반이라 가독성이 좋고 디버깅이 쉽지만, 대용량 이미지나 고차원 텐서(Tensor) 데이터를 문자열(Base64 등)로 직렬화/역직렬화하는 과정에서 엄청난 CPU 오버헤드가 발생합니다.
  • 해결책: Triton과는 HTTP 대신 gRPC(Protocol Buffers)를 사용합니다. 데이터가 바이너리 형태로 압축되어 네트워크 패킷 크기가 극적으로 줄어들고, HTTP/2 기반의 멀티플렉싱을 통해 네트워크 지연 시간(Latency)을 최소화할 수 있습니다.

2. 전처리(Preprocessing)와 후처리(Postprocessing)는 어디서 해야 하는가?

  • Lazy Design (안 좋은 예시): 클라이언트(Streamlit) 단에서 이미지 크기를 (224, 224)로 리사이즈하고 정규화까지 마친 뒤 API 서버로 보내는 방식.
    • 비판: 프론트엔드가 모델의 세부 명세(입력 셰이프, 정규화 파라미터 등)를 알게 되므로 강한 결합(Tight Coupling)이 발생합니다. 모델이 업데이트되어 입력 형태가 바뀌면 프론트엔드 코드도 배포해야 하는 재앙이 옵니다.
  • Best Practice: 전/후처리는 크게 두 가지 방법이 권장됩니다.
    1. FastAPI 레이어에서 처리: CPU 바운드 연산(이미지 디코딩, 리사이즈)을 FastAPI가 수행하고 퓨어 텐서 데이터만 Triton에 토스합니다.
    2. Triton Ensemble / BLS (Business Logic Scripting) 활용: Triton 내부에 전처리 모델(Python Backend)과 메인 추론 모델(TensorRT/Onnx Runtime)을 파이프라인으로 묶는 방식입니다. 네트워크 구간에는 순수 로우 데이터(e.g., JPEG 바이너리)만 오고 가므로 아키텍처가 가장 깔끔해지며, 대규모 서빙에서 가장 선호되는 방식입니다.

3. 동시성 관리와 서킷 브레이커 (Circuit Breaker)

  • Race Conditions 및 Bottleneck 예방: Triton이 수용할 수 있는 최대 큐(Queue) 크기를 넘어서는 요청이 들어오면 가용성이 무너집니다.
  • 해결책: FastAPI 게이트웨이 단에 서킷 브레이커를 배치하거나 레디스(Redis) 기반의 메시지 큐를 두어, Triton 시스템 전체가 연쇄적으로 다운(Cascading Failure)되는 현상을 방지해야 합니다.

'스프린트미션' 카테고리의 다른 글

위클리 페이퍼 #16  (0) 2026.06.29
위클리 페이퍼 #15  (0) 2026.06.21
위클리페이퍼 #14  (0) 2026.06.15
위클리 페이퍼 #12  (0) 2026.04.27
위클리 페이퍼 #11  (0) 2026.04.20