통합 서빙 인프라와 vLLM 도입 사실

JVM 기반의 통합 서빙 시스템은 라우팅, A/B 테스트, 특징 조회, 추론, 후처리 및 로깅을 단일 파이프라인에서 처리한다. 호출자는 기존 gRPC 경로 또는 LLM 전용 HTTP 경로를 통해 추론에 접근하며, 모델 규모에 따라 실행 위치가 결정된다. 작은 CPU 모델은 원격 호출 비용을 줄이기 위해 프로세스 내부에서 직접 실행하고, 큰 GPU 모델은 전·후처리를 로컬에서 수행한 뒤 추론만 원격 Model Scoring Service(MSS)에 위임하는 구조다.

MSS는 XGBoost, TensorFlow, PyTorch, LLM을 하나의 인터페이스로 제공하며, 하부의 NVIDIA Triton Inference Server가 모델 로딩과 GPU 스케줄링을 담당한다. 기본 추론 엔진으로는 vLLM을 선택했다. 초기에는 TensorRT-LLM을 사용했으나, 2025년 여름 기준 오픈소스 엔진의 성능 격차가 줄어든 점과 임베딩 생성, prefill-only 추론, 자기회귀 디코딩 등 워크로드의 다양성을 고려해 전환했다. vLLM은 다단계 컴파일 없이 사용자 정의 모델 아키텍처를 로드할 수 있어 비표준 모델의 반복 개발 속도를 높인다.

인터페이스는 기존 클라이언트 라이브러리와 배포 파이프라인을 재사용하기 위한 gRPC와, LLM 생태계의 도구 및 프레임워크 호환성을 위한 OpenAI 호환 HTTP API를 나란히 제공한다. HTTP API는 NVIDIA의 Triton OpenAI 호환 프런트엔드를 재사용해 구현했으며, TritonLLMEngine이 요청 스키마를 Triton 추론 요청으로 변환하고 FastAPI를 통해 응답을 내보낸다.

vLLM-Triton 작동 방식과 성능 최적화

Triton 내에서 vLLM을 패키징하는 경로는 Python backend와 vLLM backend로 나뉜다. Python backend는 개발자가 입출력 텐서 명세를 정의하며, 프런트엔드 업그레이드로 I/O가 바뀌면 패키징 코드를 함께 수정해야 한다. 반면 vLLM backend는 모델 가중치와 토크나이저 정보가 담긴 JSON 설정만으로 구성되며, Triton backend가 I/O 텐서 명세를 동적으로 생성해 모델과 프런트엔드를 독립적으로 변경할 수 있게 한다. 다만 Triton backend는 특정 vLLM API 기준으로 컴파일되므로, Triton 25.09가 `vllm.engine.metrics`를 참조하지만 vLLM 0.11.2에서 해당 모듈이 제거된 경우처럼 버전 불일치 시 backend 로드가 불가능한 제약이 있다.

모델 배포는 비용과 안정성에 따라 두 가지 전략을 쓴다. Red-Black 배포는 새 버전을 올린 뒤 상태 확인을 거쳐 트래픽을 단계적으로 전환하며, 인터페이스가 안정적일 때 사용한다. I/O 스키마 변경이 불가피한 경우에는 `(modelId, modelVersion)` 쌍마다 독립적인 배포를 유지하는 Versioned 배포를 적용해 소비자 업데이트와 모델 배포를 분리한다. 콜드 스타트 문제를 해결하기 위해 모델을 Amazon FSx에 미리 구체화하여 객체 저장소 대신 고성능 파일 시스템에서 직접 로드한다.

디코딩 루프의 제약 강제 방식은 vLLM V0에서 V1으로 전환하며 구조를 바꿨다. vLLM V0의 Python 기반 로짓 프로세서는 GPU가 배치의 로짓을 생성한 뒤 CPU가 이를 복사해 요청별로 순차 실행하는 구조였다. 이 과정에서 Python의 GIL(Global Interpreter Lock)로 인해 배치 크기가 커질수록 CPU 처리 시간이 선형적으로 증가하며 꼬리 지연시간이 늘어나는 병목이 발생했다. vLLM V1에서는 로짓 처리를 배치 단위로 옮기고 핵심 경로를 멀티스레드 C++로 재구현해, 배치 크기와 상관없이 로짓 처리 시간이 일정하게 유지되도록 개선했다. V1 API에서는 `update_state(batch_update)`를 통해 동적 배치 내 요청 상태를 명시적으로 추적하며, 청크 단위 prefilling으로 인한 부분 prefill과 메모리 부족으로 인한 선점(preemption) 상황에서 상태 머신을 초기화하는 로직을 추가했다.

운영 제약과 실무적 도입 판단

Triton과 vLLM의 메트릭 통합 과정에서는 데이터 누락 문제가 발생했다. Triton 내장 브리지가 vLLM의 40개 이상 메트릭 중 9개만 노출하여 KV 캐시 사용률이나 접두사 캐시 적중률 같은 핵심 지표가 빠졌기 때문이다. 이를 해결하기 위해 경량 HTTP 프록시가 Triton 메트릭을 가져오고, Prometheus MultiProcessCollector가 디스크의 `.db` 파일에서 vLLM 메트릭을 읽어 하나의 `/metrics` 응답으로 합치는 구조를 구축했다.

API 수준에서는 Triton 프런트엔드가 스키마에서 허용한 `response_format`을 vLLM에 전달하기 전에 누락시키는 결함이 확인되었다. 이로 인해 JSON 출력을 요청해도 유도 디코딩 제약 없이 실행되어 잘못된 JSON이 반환되는 문제가 있었다. 넷플릭스는 프런트엔드를 Git subtree로 가져와 `response_format` 요청을 vLLM의 유도 디코딩 매개변수로 변환하도록 직접 패치해 해결했다.

실무자가 인프라를 설계할 때 가장 주의해야 할 점은 I/O 스키마의 가변성이다. 텐서 형태와 같은 설정 변경을 모델 내부에 포함해 버전 독립적으로 만들 수 있다면 비용이 낮은 Red-Black 전략을 선택하고, 인터페이스 변경이 불가피한 경우에만 GPU 비용 증가를 감수하고 Versioned 배포를 적용해야 한다.