- 넷플릭스는 LLM을 별도 사일로로 분리하지 않고 기존 ML 인프라에서 함께 운영하며,
vLLM과 Triton을 통합 서빙 체계에 연결함
- 기본 엔진으로 선택한
vLLM은 사용자 정의 모델 지원, 디버깅 용이성, 확장 훅, 연구 환경과의 친숙성을 갖췄으며, Triton의 vLLM backend로 모델과 프런트엔드의 결합도 줄임
- 기존 gRPC와 OpenAI 호환 API를 함께 제공하지만
response_format
누락, Triton·vLLM 버전 불일치, 비표준 모델 처리처럼 프로덕션에서 드러난 간극을 직접 보완해야 했음
- 안정적인 배포에는 비용이 낮은
Red-Black 전략을 우선 적용하고, 호환되지 않는 I/O 변경이 불가피할 때만 여러 버전을 동시에 유지하는 Versioned 전략을 사용함
- 요청별 제약을 디코딩 루프에서 강제하는 로짓 프로세서를 vLLM V1의 배치 처리와 멀티스레드 C++로 재구현했으며, 앞으로 GPU 융합 커널·비동기 스케줄링·저정밀 모델로 확장할 계획임
기존 ML 인프라에 통합한 서빙 구조
-
Netflix의 JVM 기반 통합 서빙 시스템은
라우팅과 A/B 테스트, 후보 생성, 특징 조회, 추론, 후처리, 단계별 로깅을 처리하며 실시간 및 캐시된 배치 경로를 모두 지원함
-
호출자는 기존 서빙 시스템의
gRPC 경로 또는 새로운 LLM 애플리케이션용 직접 HTTP 경로로 추론에 접근함
-
실행 위치는 모델 규모에 따라 달라짐
-
작은 CPU 모델은 원격 호출 비용을 피하도록 프로세스 안에서 실행함
-
큰 GPU 모델은 전·후처리를 로컬에서 수행하고 추론을 원격
Model Scoring Service(MSS) 에 위임함
-
MSS는 XGBoost, TensorFlow, PyTorch, LLM을 하나의 인터페이스로 제공하며, 하부의 NVIDIA Triton Inference Server가 모델 로딩, 배치 처리, GPU 스케줄링을 담당함
-
Triton 위의 Java 제어 영역은 배포, 버전 관리, 상태 확인, 자동 확장, 다중 리전 롤아웃을 처리함
-
모델 개발자가 아티팩트와 배포 설정을 패키징하면 GPU 인스턴스를 프로비저닝하고 Triton을 구성함
-
업그레이드는
무중단 방식으로 조정함
기본 추론 엔진으로 vLLM 선택
-
초기 플랫폼은 당시 성능이 높고 MSS의 Triton과 이미 통합돼 있던
TensorRT-LLM을 사용함
-
2025년 여름에는 오픈소스 엔진이 특화 스택과의 성능 차이를 대부분 좁혔고, 워크로드도 다음 범위로 넓어짐
-
임베딩 생성
-
순위화와 검색을 위한 prefill-only 추론
-
자기회귀 디코딩
-
단계별 제약 로직이 복잡한 사용자 정의 모델
-
이 워크로드를 다시 벤치마크한 뒤 운영 적합성을 기준으로
vLLM을 기본 경로 엔진으로 선정함
-
다단계 컴파일 없이 사용자 정의 모델 아키텍처를 로드할 수 있어 비표준 모델의 반복 개발이 빨라짐
-
사용자 정의 디코딩 로직을 위한 확장 훅을 제공함
-
컴파일 엔진이던 초기 TensorRT-LLM보다 장애와 중간 상태를 조사하기 쉬움
-
연구 단계에서 이미 vLLM에 익숙한 ML 실무자가 많아 프로덕션 이관 비용이 줄어듦
Triton과 vLLM의 패키징 방식
- Triton에는
Python backend와 vLLM backend라는 두 가지 패키징 경로가 있으며, 프런트엔드 업그레이드와 모델 아티팩트가 얼마나 강하게 결합되는지가 핵심 차이임
- Python backend에서는 개발자가 패키징 시점에 입출력 텐서 명세를 정의함
- 명세가 아티팩트에 고정되고 외부 프런트엔드의 요청 빌더와 일치해야 함
- 프런트엔드 업그레이드로 I/O가 바뀌면 패키징 코드도 함께 수정해야 하며, 그렇지 않으면 런타임 요청이 실패함
vLLM backend의 아티팩트는 모델 가중치와 토크나이저를 가리키는 JSON 설정으로 구성됨
-
배포 시 Triton backend가 I/O 텐서 명세를 동적으로 생성함
-
모델 개발자가 텐서 명세를 정의하지 않아도 되며 모델과 프런트엔드를 독립적으로 변경할 수 있음
-
기본 선택은 vLLM backend지만 프로덕션에서 두 가지 제약이 나타남
버전 불일치: Triton backend는 특정 vLLM API를 기준으로 컴파일되므로 두 버전이 어긋나면 backend 전체를 로드할 수 없음
-
예를 들어 Triton 25.09는
vllm.engine.metrics
를 가져오지만, 해당 모듈은 vLLM 0.11.2에서 제거됨
- 서비스 이미지 생성 시 호환 버전을 고정하고, 모델 개발자가 패키징 단계에서 vLLM 버전을 덮어쓰지 못하게 해야 함
사용자 정의 실행 로직: vLLM backend는 표준 HuggingFace 호환 모델과 전체 추론 수명주기를 전제로 함
- 사용자 정의 전·후처리, 앙상블 파이프라인, 별도 토큰화 등 비표준 실행에는
execute()
를 제어할 수 있는 Python backend가 필요함
gRPC와 OpenAI 호환 HTTP API
- XGBoost 앙상블부터 대규모 LLM까지 동일한
gRPC 호출로 평가해 기존 클라이언트 라이브러리, 상태 확인, 배포 파이프라인을 재사용함
- LLM 생태계의 추론 엔진, 오케스트레이션 프레임워크, 평가 도구, 클라이언트 라이브러리가 OpenAI 호환 인터페이스를 사용하므로 이를 gRPC와 나란히 제공함
- 같은 API를 유지하므로 품질, 지연시간, 비용, 데이터 프라이버시를 이유로 호스팅 모델에서 미세 조정한 자체 호스팅 모델로 옮길 때 코드 변경이 작음
- 구현은 NVIDIA의 Triton OpenAI 호환 프런트엔드를 재사용함
- 내장 Triton 서버를 시작함
TritonLLMEngine
이 요청 스키마를 Triton 추론 요청으로 변환함
을 vLLM에 전달하기 전에 조용히 버리는 문제가 발견됨
- JSON 출력을 요청해도 유도 디코딩 제약 없이 실행돼 잘못된 JSON을 반환할 수 있었고, 플랫폼 오류도 노출되지 않았음
- 프런트엔드를 Git subtree로 가져와
response_format
요청을 vLLM의 유도 디코딩 매개변수로 변환하도록 패치함
무중단 모델 배포 전략
-
GPU 배포는 CPU 서비스보다 시작 시간이 길고 모델 버전 사이에서 I/O 스키마까지 바뀔 수 있어, 요청을 중단하지 않는 롤아웃에 추가 조정이 필요함
Red-Black 배포는 기존 버전 옆에 새 버전을 올린 뒤 상태 확인을 통과하면 단계적으로 트래픽을 전환함
-
새 버전과 기존 버전의 확장·축소를 같은 비율로 진행함
-
어느 단계에서든 실패하면 원자적으로 롤백함
-
모델 인터페이스가 안정적일 때 적합함
-
새 텐서 차원처럼 I/O 스키마가 바뀌면 Red-Black에
조정 간극이 생김
-
새 모델이 완전히 활성화되기 전에는 상위 소비자가 설정을 바꿀 수 없음
-
전환 구간에 기존 형식의 요청이 새 배포로 전달되면 실패함
Versioned 배포는 (modelId, modelVersion)
쌍마다 독립적인 배포를 유지해 이 문제를 해결함
-
여러 버전을 동시에 서비스하므로 모델 배포와 소비자 업데이트가 분리됨
-
소비자는 새 버전이 완전히 준비된 뒤 설정을 바꾸고, 기존 버전은 레거시 트래픽을 계속 처리함
-
비활성 상태가 된 이전 배포는 정리하지만 최신 버전은 항상 보존함
-
전환 중 버전이 겹치는 기간에는 GPU 비용이 일시적으로 증가함
-
텐서 형태처럼 변할 수 있는 설정은 추론 모델 안에 직접 넣어
버전 독립적으로 만들고, 비용이 낮은 Red-Black을 사용하는 방식을 권장함
-
Versioned는 호환되지 않는 인터페이스 변경을 피할 수 없는 경우에만 사용함
시작 절차와 모델 캐시
-
vLLM-on-Triton 인스턴스는 여러 시작 단계를 마쳐야 gRPC 포트를 열 수 있음
-
대형 LLM을 시작할 때 S3나 Hugging Face에서 직접 내려받으면 콜드 스타트가 스케줄러 허용 범위를 넘을 만큼 길어짐
-
모델 발표 시점에 모델을
Amazon FSx에 미리 구체화함
-
이후 시작 과정에서는 객체 저장소 대신 고성능 파일 시스템을 사용함
-
OpenAI 호환 API가 필요한 배포에서는 Triton을 해당 프런트엔드 프로세스 안의
내장 서버로 실행함
-
그렇지 않은 배포는 Triton을 독립 실행함
-
실행 방식은 패키징 시 배포별로 설정함
-
나머지 시작 절차에는 모델 패키지 압축 해제, Python
entry_points
를 통한 사용자 정의 vLLM 플러그인 설치, Prometheus 멀티프로세스 디렉터리 정리, 엔진 준비 완료까지 gRPC 포트 차단이 포함됨
Triton과 vLLM 메트릭 통합
- vLLM은
PROMETHEUS_MULTIPROC_DIR
에 .db
파일로 메트릭을 기록하고, Triton은 별도의 Prometheus 엔드포인트로 서버 메트릭을 제공함
-
두 시스템은 서로의 메트릭을 인식하지 못하며, Triton 내장 브리지는 vLLM의
40개 이상 메트릭 중 9개만 노출함
-
토큰 처리량
-
KV 캐시 사용률
-
접두사 캐시 적중률 같은 핵심 지표가 빠짐
-
경량 HTTP 프록시가 Triton 메트릭을 HTTP로 가져오고, Prometheus
MultiProcessCollector
로 디스크의 vLLM 메트릭을 읽어 하나의 /metrics
응답으로 합침
- 기존 대시보드와 경보는 수정 없이 그대로 사용할 수 있음
디코딩 과정에서 출력 제약 강제
- 일부 프로덕션 워크로드는 토큰 생성에 세밀한 제어가 필요해, 추론 후 잘못된 결과를 재시도하거나 복구하는 대신
디코딩 루프 안에서 제약을 적용함
- 각 제약은 생성된 토큰 이력에 따라 상태가 변하고 단계마다 허용 토큰 마스크를 내보내는 상태 머신으로 모델링함
- vLLM의 사용자 정의
로짓 프로세서 인터페이스를 사용하며, 요청마다 규칙이 다르므로 별도로 설정된 프로세서를 할당함
- 초기에는 기능 격차 때문에 vLLM V0를 사용했고, V1이 성숙한 2025년 4분기에 이전함
vLLM V0에서 발생한 확장 병목
-
최초의 순수 Python 구현은 기능적으로 동작했지만 동시 요청이 늘면 확장되지 않았음
-
vLLM V0의 사용자 정의 로짓 프로세서는 요청별로 실행됨
-
GPU가 전체 배치의 로짓을 생성함
-
CPU가 이를 복사하고 전송이 끝날 때까지 대기함
-
각 요청의 제약 로직을 순차 실행함
-
Python의
GIL 때문에 요청별 작업을 병렬화할 수 없어 로짓 처리 CPU 시간이 배치 크기에 비례해 증가하고 꼬리 지연시간이 커짐
-
GPU의 모델 순전파가 효율적으로 배치 처리돼도 전체 지연시간은 CPU에 묶임
-
이 병목은 단일 요청 벤치마크에서는 보이지 않고 실제 수준의 동시성에서만 나타남
vLLM V1의 배치 단위 처리
- vLLM V1은 로짓 처리를 요청별 방식에서
배치 단위로 옮김
- 사용자 정의 프로세서를 배치 자료구조 기반으로 다시 작성해 여러 요청의 마스크를 함께 계산함
- 성능 핵심 경로는 GIL을 피하도록 멀티스레드
C++ 로 재구현했으며, 배치 크기가 커져도 로짓 처리 시간이 일정하게 유지됨
- V1 API에서는
update_state(batch_update)
를 통해 배치 구성원 변화를 명시적으로 추적해야 함
- V0의 요청별 인터페이스보다 복잡함
- 동적으로 바뀌는 배치에서 요청별 상태를 정확히 유지하는 데 필요함
상태 기반 제약 처리의 운영 보강
- 성능 병목을 해결한 뒤에도 상태를 가진 디코딩 로직에서 두 가지 문제가 나타남
부분 prefill
- V1은 청크 단위 prefilling을 수행하므로 한 요청의 prefill이 여러 엔진 단계에 걸칠 수 있음
BatchUpdate
만으로는 완전한 prefill과 부분 prefill을 구분할 수 없어 내부 추적을 추가함
선점(preemption)
- 메모리가 부족하면 vLLM이 일부 완료된 요청의 KV 캐시를 제거하고, 이후 다른 프롬프트 및 출력 토큰 목록으로 다시 예약할 수 있음
- 이는 출력 토큰 목록이 계속 증가한다는 상태 머신의 전제를 깨뜨림
- 디코딩 단계 사이에서 토큰 이력이 짧아졌는지 감지하고, 상태 머신을 초기화한 뒤 새 프롬프트로 다시 구성함
다음 투자 영역
-
현재 플랫폼은 낮은 지연시간, 깊은 사용자 정의, 기존 인프라 통합을 목표로 하며
vLLM과 Triton, 일관된 API를 통해 실험에서 프로덕션까지 이어지는 경로를 제공함
-
버전 고정, 조용히 누락되는 API 필드, 패키징 선택의 절충을 보완해 플랫폼 안정성과 개발자 경험을 개선함
-
다음 네 가지 개선을 계획함
-
품질을 희생하지 않고 프롬프트 길이를 줄이는
시스템 프롬프트 압축
-
vLLM V1의 비동기 스케줄링
-
CPU 코드 대신 GPU 융합 커널로 실행하는 벡터화 로짓 프로세서
-
메모리 사용량을 줄이고 처리량을 높이는 저정밀 모델 변형
-
Triton, vLLM, PyTorch 등 오픈소스 ML 라이브러리를 계속 활용하며 관련 커뮤니티와 협력할 계획임
댓글과 토론