반응형

Chapter 3. Model Serving System Design: A Deep Dive
- 1장(서빙 패러다임), 2장(LLM 추론 원리)의 기초를 실제 운영 환경에 적용하는 방법을 다루는 장
- 특정 프레임워크 사용법이 아니라 기본 원리에서 직관을 키우는 것이 목적
- 서빙 시스템의 구조를 근본적으로 이해하면 어떤 프레임워크·관리형 서비스도 평가/적용/확장할 수 있음
- 단순화된 대표 시스템 2개를 직접 구현하며 학습
- 단일 모델 LLM 서빙 (배치 + 스트리밍 지원)
- 멀티 모델 서빙 (라우팅, 격리, 리소스 관리)
- 마지막에 멀티 모델 서빙의 두 가지 설계 변형(비용 최적화 vs 지연시간 최적화)을 비교
1. Build an Online LLM Serving Service from Scratch
1.1 설계 목표
- 시작 시 단일 LLM(facebook/opt-125m, CPU 실행 가능)을 로드하고 배치·스트리밍 방식의 동시 생성 요청을 지원하는 서비스
- 이해 목표: 생성 요청을 처리하는 웹 API 설계, LLM 요청 처리 워크플로, 동시 요청의 배치 그룹화 방식, 스트리밍 생성 원리, 배치와 스트리밍의 공존 방법, 성능 병목이 생기는 지점
1.2 서비스 아키텍처(6개 핵심 컴포넌트)
| 컴포넌트 | 역할 |
| API 서버 | HTTP API 엔드포인트, 요청/응답 처리 |
| LLM 엔진 | 추론 과정 전체를 조율하는 고수준 오케스트레이터 |
| 워크로드 매니저 | 요청 큐잉·배치 관리 (배치 전략을 적용하는 핵심 지점) |
| 모델 실행기(Executor) | 워커 프로세스 관리, 프로세스 간 호출로 추론 트리거·결과 수집 |
| 모델 워커 | 별도 프로세스에서 모델 로딩·호스팅·추론 실행 |
| 모델 매니저 | 모델 로드·캐시 |
멀티 프로세스 구성이 핵심 패턴인 이유
LLM은 보통 GPU에서 실행되므로 모델 실행을 특정 GPU 장치에 바인딩된 전용 프로세스로 분리하는 것이 일반적. 메인 웹 서비스(CPU)는 동시 요청 관리·오케스트레이션을 담당한다. 이렇게 하면 토큰화/역토큰화, 전처리, 후처리 같은 CPU 작업을 기다리며 고비용 GPU가 유휴 상태로 노는 것을 방지하고 GPU 활용도를 최적화할 수 있다.
1.3 단일 생성 요청 처리
- 한 번에 프롬프트 1개만 처리 → 처리량이 낮고 컴퓨팅 리소스가 놀게 됨. LLM은 여러 프롬프트 배치 처리에 적합하므로 다음 단계에서 배치를 도입
1.4 배치 처리(Batching)
배치 처리의 2대 과제 (예: request1=promptA, B / request2=promptC, D, E 수신 시)
- 서로 다른 요청의 프롬프트를 묶어 큰 배치로 실행해 리소스 활용 극대화
- 생성 결과를 원래 요청으로 정확히 역매핑해 올바른 사용자에게 올바른 순서로 반환
- 배치 처리 프로세스
- ① 요청 접수 → ② 큐 전달 → ③ 프롬프트별 고유 ID 부여·Sequence로 추적, 다음 배치 결정 → ④ 배치 실행 → ⑤ 모델이 배치 전체를 1회 추론, 결과에 프롬프트 ID 동봉 → ⑥ ID로 원 요청에 결과 매핑
- 배치 전략이 곧 처리량 최적화 지점: 실전에서는 배치 크기·전략이 처리량에 큰 영향을 주며 모델, 프롬프트 특성, 트래픽, 하드웨어에 따라 조정이 필요. 동적 배치/연속(continuous) 배치 등 고급 기법은 6~7장에서 다룸. 각 프롬프트를 개별 추적(Sequence화)하는 것은 사용자 요청과 실제 모델 실행을 분리해 백엔드가 자유롭게 재배치 & 우선순위화할 수 있게 하는 LLM 서빙의 일반 기법.
- 예시에서는 요청 처리를 단순화 해서 처리했으나 실제 프레임워크(vLLM 등)는 연속 배치, 동적 스케줄링, 메모리 효율적 KV 캐시 관리로 고정 배치 완료를 기다리지 않고 새 요청이 활성 디코딩 배치에 합류하게 해 처리량을 높인다(6장).
1.5 Streaming with Batching
- 위 배치 구현은 모든 프롬프트가 끝나야 결과 반환 → 지연 체감 큼
- 각 생성 스텝에서 내부적으로는 요청을 배치로 처리하면서, 생성된 토큰은 즉시 사용자에게 스트리밍(높은 처리량 + 반응성 양립)하는 방식
- 서로 다른 시점(T0~T3)에 도착한 사용자 A~D의 프롬프트 1~4가 백엔드 배치에 동적으로 합류 & 이탈하며 각 프롬프트의 토큰은 생성 즉시 각자에게 스트리밍됨. 완료된 프롬프트(예: T2에 끝난 프롬프트1)는 다음 스텝(T3)에 배치에서 제거되어 새 요청 자리를 만듦
- Streaming with Batching 프로세스: ① SSE 스트림 반환 → ② 프롬프트별 Sequence 생성(출력 버퍼 + 이벤트 큐 보유) → ③ 백그라운드 스레드의 배치 루프(1회전 = 1 토큰 생성 스텝) → ④ 배치 추론으로 프롬프트당 토큰 1개 생성 → ⑤ 프롬프트 ID가 붙은 토큰 목록 수신 → ⑥ Sequence 출력·프롬프트 갱신(다음 스텝 입력) → ⑦ 이벤트 큐에 토큰 push → SSE로 클라이언트 전송
- 배치 구현 대비 주요 변경점
- 토큰 생성 API가 비동기로 동작 (토큰 생성 즉시 사용자에게 전달)
- ModelWorker가 전체 출력 대신 추론 스텝마다 토큰 1개씩 생성
- WorkloadManager가 부분 출력을 추적하며 프롬프트를 실시간 갱신
- 프롬프트마다 자체 이벤트 큐를 가져 토큰을 비동기 API 계층으로 전달
- LLMEngine에 프롬프트 전반의 토큰 수준 추론을 조율하는 전용 배치 스레드 추가
2. A General Design for Single-Model LLM Serving
2.1 요구사항
- 일반적인 서빙 요구사항: 낮은 지연시간 / 높은 처리량(QPS & TPS) / 확장성(수평 확장) / 신뢰성 & 가용성 / 리소스 효율 & 비용 관리 / 관측 가능성(SLO 추적)
- LLM 특유의 난제
- 수십~수백 GB 메모리를 요구하는 대형 모델 크기
- 요청·세션에 걸친 KV 캐시 관리
- 대화형 UX를 위한 스트리밍 응답
- 입출력 길이가 제각각인 가변 길이 워크로드의 동시성 & 배치
- 전통 딥러닝 서빙은 모델을 블랙박스로 취급해도 되지만, LLM 서빙은 모델 아키텍처(예: MHA vs MQA에 따른 KV 캐시 동작), 사용 시나리오에 따라 요구사항이 자주 바뀜 → 진화하는 구성 요소와 안정적인 인프라를 분리하는 설계가 중요.
2.2 일반 설계(관심사 3분할)
- Part A. 서비스 인프라 관리: 서빙 로직을 컨테이너/Pod 같은 복제 가능한 단위로 캡슐화, 확장 & 복구 & 리소스 할당·모니터링은 분산 컴퓨팅 플랫폼(Kubernetes, 클라우드)에 위임. 사용자는 로드밸런서 뒤의 인스턴스와만 간접 상호작용.
- Part B. 서빙 프런트엔드(비즈니스 로직): 인증/인가, 외부 시스템 통합(고객 데이터 & 감사 로그 & 과금), 모델 다운로드 & 구성 관리, 요청 전처리(검증 & 정규화 & 배치), 속도 제한 & 로깅. 고객 인터페이스와 추론 엔진 사이의 중간 계층.
- Part C. 서빙 백엔드(모델 실행 성능): 실제 추론이 일어나는 별도 프로세스. 실무에선 vLLM, Triton 같은 성숙한 프레임워크 사용(고처리량 & 저지연 엔진, 양자화 & KV 캐시& 연속 배치, GPU 활용 극대화, 활발한 커뮤니티).
3. Build a Multi-Model Serving Service from Scratch
모델(크기,버전, 태스크)이 늘어나면 모델별 전용 배포는 GPU 유휴 리소스, 비용 증가, 운영 복잡성을 초래. 공유 인프라에서 여러 모델에 대한 요청을 동적으로 로드/라우팅하는 멀티 모델 서빙이 필수가 됨(특히 소형, 파인튜닝 모델이 많을 때 효과적).
3.1 설계 목표
- 트랜스포머 모델 2개 + 이미지 분류 모델 1개(모두 CPU)를 호스팅
- 프레임워크 간 지원(PyTorch/ONNX, NLP/비전) / 통합 API 인터페이스(작업 유형과 무관하게 일관된 REST) / 리소스 관리(지연 로딩 + LRU 기반 모델 제거)
3.2 아키텍처
| 컴포넌트 | 역할 |
| API 서버 | HTTP 엔드포인트, 요청/응답 처리 |
| 모델 매니저 | 모델 캐시 관리, 워커 수명주기 조정 |
| 모델 스토어 | 모델 메타데이터 저장·검색 |
| 모델 엔진 | 메타데이터 기반으로 워커 인스턴스 생성 |
| 모델 워커 | 모델을 메모리에 로드, 추론 실행 |
- 전체 워크플로: ① 클라이언트가 model_id + 입력으로 요청 → ② 캐시 조회 → ③ 미캐시면 ModelStore에서 메타데이터 조회 → ④ ModelEngine이 ModelWorker 생성 → ⑤ 캐시 등록(가득 차면 LRU 제거) → ⑥ 워커로 추론 실행 → ⑦ 응답 반환
3.3 핵심 구현
- 프레임워크 간 지원 → 모델 유형별 ModelWorker 구현 클래스
- 통합 인터페이스 → 모델 불문 일반 입력/출력의 predict (전처리, 후처리는 클라이언트 책임)
- 리소스 관리 → 요청 시 온디맨드 로딩 + LRU 캐시 방출
3.4 NVIDIA Triton을 모델 서버로 사용
- Triton은 PyTorch/TensorFlow/ONNX/TensorRT 모델을 일관된 HTTP/gRPC API로 서빙하는 대표적 멀티 모델 솔루션. 모델 관리 API(로드/언로드/구성)와 추론 API 두 종류를 제공한다.
- TritonWorker(Wrapper)와 TritonServer(별도 프로세스의 웹 서비스)를 도입해 모델 호스팅·실행은 Triton에 위임하고, 모델 캐시 관리·모델 파일·외부 웹 인터페이스는 우리 서비스 계층에 유지.
4. Trade-offs in Multi-Model Serving Designs
4.1 도전 과제
멀티 모델 서빙의 비용 절감 효과는 명확(예: 하루 3~4시간만 도는 배치 작업, 1,000 고객용 1,000개 모델 중 동시 사용은 200개 이하)하지만, 사용자 경험 관련 아래 두 가지 문제가 있음.
- 콜드 스타트 지연: 로드되지 않은 모델 요청 시 다운로드→로드→(캐시 full이면) 방출까지 수 초~수십 초. 타임아웃 & 하위 애플리케이션 연쇄 오류 가능
- 핫 모델 스케일링: 특정 모델 트래픽 폭증 시 확장이 어려움(인스턴스마다 독립 캐시라 복제·라우팅 갱신이 복잡, 성능이 비결정적)
4.2 비용 최적화 설계
- 모델 로딩, 메모리 관리, 호스팅 로직을 각 멀티모델 서빙 인스턴스 내부에 캡슐화(FE=웹 API & 캐싱 & 모델 관리, BE=추론 & 리소스 최적화, 실무는 Triton 등 사용)
- 핵심은 모델 서비스 API + 라우팅 로직(Part A): 모델↔인스턴스 매핑을 유지하면서 아래 요건을 충족하는 것
- 이미 로드된 인스턴스로 라우팅해 콜드 스타트 최소화
- 모델별 복제본 수를 추적해 인기 모델 수평 확장
- 빈 패킹(bin-packing) 전략으로 최소 서버에 모델을 몰아 리소스 최적화
- 단점: 반응형(트래픽 패턴이 나타난 뒤에야 조정)이라 급증 시 지연 불가피. 라우팅, 확장, 캐시 상태 관리로 운영/디버깅 복잡도 증가
4.3 지연시간 최적화 설계
- "성능을 위해 용량을 희생"하는 전략: 멀티모델 인스턴스 대신 모델당 전용 단일 모델 인스턴스 그룹 배치
- 모델은 온디맨드 로딩이 아니라 모델 프로비저닝 서비스로 사전 프로비저닝. 클라이언트가 먼저 프로비저닝을 호출해 인스턴스 그룹을 만들면 라우팅 맵이 갱신되고, 이후 예측 요청은 라우팅 맵을 따라 전달
- 장점: 콜드 스타트 없음, 모델별 독립 확장, 모델별 리소스 정책, 단순한 아키텍처(운영, 트러블슈팅 용이)
- 단점: 비용 (트래픽 예측이 어려우면 저활용 모델에 리소스 과할당. 수요가 안정적·예측 가능한 모델들에 적합)
- LLM은 컴퓨팅·메모리 요구 때문에 단일 모델 방식이 일반적 But
- ① 접두사(prefix) 캐싱, 라우팅: 공유 프롬프트 접두사를 가진 요청을 해당 KV 캐시가 이미 채워진 복제본으로 라우팅해 중복 계산 감소(7장),
- ② 멀티 LoRA: 공유 베이스 모델 위에 여러 LoRA 어댑터를 동적 로드해 테넌트별 개인화를 메모리 효율적으로 지원(10장)하는 데 멀티 모델 패러다임이 그대로 쓰인다.
Chapter 4. Model Serving Best Practices
- 2~3장이 "서빙 시스템을 어떻게 만드는가"였다면, 4장은 "실제 LLM 응용 환경에서 서빙 시스템이 어떻게 진화해야 하는가"를 다룸
- 최신 LLM 앱은 단일 요청-응답 호출이 드물기 때문에 모델이 에이전트 워크플로, 엔터프라이즈 플랫폼, 계층화된 프로덕션 시스템 안에 내장되며, 서빙은 추론 문제를 넘어 시스템 아키텍처 문제가 됨
- 에이전트는 토큰 사용량 증가, 연쇄 호출에 걸친 지연 증폭, 동적 컴퓨팅 패턴, 모델 & 도구 간 오케스트레이션 요구를 만듦 → 후반부 최적화 기법(캐싱 & 배치 & 메모리 & 스케줄링 & 병렬화)의 상당수가 에이전트 워크로드에서 비롯됨
1. Model Serving in an Agentic World
1.1 에이전트 정의
- 에이전트 = 다음이 가능한 자율적 LLM 기반 시스템
- 고수준 목표 이해 → 달성 방법 추론 → 외부 도구/데이터 소스 선택 & 호출 → 중간 결과 기반 조정 & 반복 → 최소한의 인간 개입으로 최종 결과 도출
- 유형 예: 연구(논문 읽기, 핵심 추출, 문헌 검토), 코딩(생성, 리뷰, 테스트, 디버깅, 배포), 사업 운영(데이터 입력, 보고서, 요약 배포)
- 규칙 기반 챗봇 등 기존 어시스턴트와의 근본 차이는 자율성: 자연어 지시 해석, 추론 & 행동 계획, 도구 선택 & 사용, 피드백 적응, 컨텍스트 & 사용자 선호 유지
1.2 샘플 지식 에이전트(Knowledge Agent)
- PDF 파일에서 정보를 조회 & 분석하는 에이전트. 이식성을 위해 로컬 모델/DB 없이 OpenAI API(LLM 추론 + 임베딩)와 인메모리 저장 사용
- 모델 2개: text-embedding-3-small(텍스트→의미 벡터: 시맨틱 검색·매칭용), gpt-4.1-nano(추론, 계획, 자연어 생성 엔진)
- 핵심 구성 요소: Knowledge Agent(오케스트레이터) / RAG 시스템(PDF 처리, 임베딩, 벡터 검색) / 플래너(LLM으로 실행 계획 생성) / 액션(실행기)(질의, 요약, 분석 수행)
1.3 에이전트 내부 워크플로 (그림 4-2)
- 사용자 질문 수신(예: "DB 쿼리 최적화와 데이터 구조 최적화의 상세 비교를 작성해줘")
- 에이전트가 플래너 호출 → 플래너가 LLM을 호출해 가용 액션에 맞춘 실행 계획 생성
- ActionExecutor가 계획된 액션을 순서대로 실행 (query_rag_with_context가 RAG로 관련 문서를 찾고 LLM으로 요약
- generate_analysis가 사용자 쿼리 + 검색 문서를 컨텍스트로 LLM에 보내 심층 비교 분석 생성
- generate_summary가 이전 분석을 LLM으로 요약
- 에이전트가 모든 액션 결과를 통합해 최종 응답 반환
1.4 에이전트 자율성
- 특수 프롬프트 템플릿을 채워 LLM을 호출하는 것. 재사용 가능한 액션 = 프롬프트 생성기 + LLM 호출.
- 실전 에이전트의 액션은 LLM 프롬프트에 국한되지 않음: 툴 호출(웹 검색·API·DB 명령), 시스템 운영(파일·워크플로·외부 서비스), 추론 단계(중간 계산·계획 서브루틴)까지 포함.
- create_planning_prompt(query, self.available_actions) — 사용자 쿼리와 함께 에이전트가 가진 액션 목록을 프롬프트에 넣음 → LLM이 실제로 실행 가능한 액션만으로 계획을 짜게 제약.
- generate_response(planning_prompt, temperature=0.3) — 계획 생성 LLM 호출. temperature=0.3(낮음)으로 창의성보다 일관되고 결정적인 계획을 유도 — 계획 단계에서 무작위성은 해가 됨.
- plan = self._parse_plan_response(plan_response) — LLM의 텍스트 응답을 JSON으로 파싱해 구조화된 계획 객체로 변환(위 plan/reasoning/estimated_steps 형태).
- logger.info(...) 2회 — 입력 쿼리와 생성된 계획을 로깅 — 자율 시스템에서 "왜 이렇게 행동했나"를 추적하는 관측성 확보.
- MCP(Model Context Protocol): 에이전트의 도구 사용을 표준화하는 프로토콜. 통합을 하드코딩하는 대신 에이전트가 환경의 가용 도구를 검색(discover)하고, 구조화된 입력으로 호출하고, 결과를 추론 과정에 재통합하는 일관된 인터페이스를 정의. 도구 정의를 에이전트 로직에서 분리해 개발 단순화·신뢰성 향상, 임시방편적 프롬프트 엔지니어링의 취약성을 해소.
1.5 RAG (Retrieval-Augmented Generation)
- LLM의 한계
- ① 학습 데이터가 특정 시점에 고정된 정적 지식
- ② 환각(유창하지만 사실과 다른 생성)
- ③ 전문 & 최신 정보 부족. RAG는 질의 시점에 검색한 외부 지식을 컨텍스트로 추가해 정확성 & 신뢰성 & 적응성을 개선.
- 워크플로
- 인덱스 구축(오프라인): 원시 문서(HTML/PDF) 정리·파싱 → 일반 텍스트 → 약 1,000토큰 단위 청킹 → 임베딩 모델로 각 청크를 밀집 벡터로 인코딩 → 벡터 DB에 인덱싱·저장. 청킹은 검색 세분성을 정의하며, 임베딩을 배치로 미리 계산해 두는 오프라인 추론 단계
- 질의/검색(온라인): 질의 텍스트 임베딩 → 코사인 유사도 등으로 최유사 벡터 검색 → 해당 문서 청크 회수 → 질의와 함께 LLM에 전달해 답변 생성
- 청크 크기 트레이드오프: 작은 청크 = 관련 구절에 집중되어 정밀도↑, 과도하면 맥락 손실. 큰 청크 = 풍부한 맥락, 무관 내용 포함으로 정밀도↓. 최적 균형은 응용 분야와 LLM 컨텍스트 윈도우에 따라 다름. 애초에 청킹하는 이유: LLM의 컨텍스트 윈도우(입출력 토큰 상한)가 제한적이라 관련성 높은 청크 몇 개만 골라 보내야 하기 때문. 실전 RAG는 여기에 ranking & 중복 제거 & 다중 소스 검색 등이 더해짐.
1.6 CAG (Cache-Augmented Generation)
- RAG의 문제: LLM 호출 전 추가 단계·지연, 제한된 토큰으로 문서 선택 시 오선택 위험, 검색 시스템 구축·유지 부담
- 컨텍스트 윈도우가 계속 커지면서(예: 1M 토큰) "가장 관련성 높은 문서 몇 개"를 고르는 대신 지식 기반 전체(또는 상당 부분)를 모델의 KV 캐시에 사전 로드하는 접근이 가능해짐 = CAG
- 효과: 검색 지연 제거, 시스템 복잡성 감소(임베딩·인덱스·벡터 DB 관리 불필요 — 그림 4-5처럼 에이전트 설계가 크게 단순화), 외부 지식 기반 응답은 유지
- 비용: 대규모 컨텍스트·캐시 관리로 메모리·컴퓨트 요구 증가 (최적화는 7장)
- RAG vs CAG는 경쟁이 아니라 다른 계층의 도구: RAG는 외부 지식 검색으로 답변 품질을 높이고, CAG는 계산된 컨텍스트 재사용·중복 KV 캐시 계산 감소로 서빙 효율을 높인다. 지식 최신성이 우선이면 RAG부터, 지연·처리량·비용이 우선이면 CAG 도입. 실전 에이전트 시스템은 입력 보강에 RAG + 실행 최적화에 CAG를 병용하는 것이 일반적.
1.7 에이전트는 모델 서빙을 어떻게 쓰는가
- 일반적 통합 구성: 추론·계획·대화용 LLM / 검색·유사도·매칭용 임베딩 모델 / 멀티모달용 비전·음성 모델 / 코드생성·분류·요약용 태스크 특화 모델 / API·DB 등 외부 도구
- 도구 호출(tool calling) 4단계: ① LLM이 요청+가용 도구를 보고 추론 → ② 선택 도구의 입력을 인코딩한 구조화된 출력(주로 JSON) 생성 → ③ 에이전트가 도구 호출 실행 → ④ 결과를 LLM에 회신, 작업 완료까지 반복
- 모델·도구는 보통 HTTP/gRPC 서빙 API로 노출 — 에이전트는 대화형·실시간이므로 고성능·저지연·비용 효율 서빙이 에이전트 앱 성공의 관건
2. LLM Serving in Enterprise Systems: An Overview
| 계층 | 역할 | 주요 과제 |
| Public API | 외부 인터페이스: 네트워킹·인증·과금·속도 제한·요청 라우팅 | 수백만 동시 연결, 할당량·남용 방지·정확한 청구, 지리적 라우팅·지역 캐싱으로 저지연 글로벌 액세스, 테넌트 격리·보안 |
| 리소스 관리 | 리전 전반의 CPU/GPU/메모리/디스크/네트워크 관리, 예산·비용 할당 | 과잉 프로비저닝 없는 용량 계획, 이기종 GPU 풀의 높은 활용률, 중요 워크로드 할당량·예약 + 저순위 작업 선점 스케줄링 |
| 모델 선택·오케스트레이션 | 요청별 모델 선택(정확도·지연·비용 균형), 다중 모델 오케스트레이션(추측적 디코딩, 모델 제품군 간 라우팅) | 비용-품질 트레이드오프(모든 작업에 최대 모델이 필요하진 않음 — 쿼리 이해 필요), 모델 풀 부하 분산, 지연 민감 사례엔 소형 모델·고급 최적화 |
| 분산 서빙 | 대규모 모델의 분산 호스팅 + 분산 캐싱(KV·프롬프트·시맨틱) | 단일 GPU 메모리를 넘는 모델 크기, 멀티 GPU/노드 협업의 SLA 유지, KV 캐시 인식 라우팅 등 캐시 기반 트래픽 라우팅 |
| 코어 추론 | 모델이 실제 실행되는 곳 — 서빙 프레임워크(vLLM·Triton·TensorRT-LLM·SGLang) + 최적화 커널(FlashAttention·GEMM·PagedAttention)을 웹 엔드포인트로 노출 | (3장에서 상세) |
| 모델 최적화 | 재학습 없이 성능·효율을 높이는 최적화 기법 적용 | (5·6·7·9장에서 상세) |
| 모델 | 학습 파이프라인/외부 소스에서 모델 수급·배포, 기능·목적별 분류, 추적·버전 관리 | - |
- 추측적 디코딩(speculative decoding): 작은 "초안(draft)" 모델이 여러 토큰을 미리 예측하고, 큰 "목표(target)" 모델이 이를 병렬로 검증. 초안이 맞으면 승인, 틀리면 수정. 품질 저하 없이 토큰당 지연시간을 줄인다(7장에 상세).
3. Building with an Open Source Stack
- k8s 기반 운영: 컨테이너화된 앱의 배포·확장·관리를 자동화하고, 메트릭·로깅·네트워킹·인가·하드웨어 관리까지 아우르는 광범위한 생태계 보유(AWS/GCP/Azure는 물론 OpenAI·Anthropic 같은 파운데이션 모델 벤더의 핵심 기반). k8s가 리소스 관리·네트워킹·트래픽 라우팅/로드밸런싱·서비스 호스팅/확장·메트릭/모니터링을 담당한다.
- Public API 구현: FastAPI + K8s
- 모델 선택 구현: 모델 선택 로직은 요구사항에 따라 Public API 내부 / 별도 미들웨어 서비스 / 정적 라우팅 설정 중 어디든 둘 수 있음.
- 모델 서빙 엔드포인트 구현 (Ray Serve)
- 모델 호스팅 계층은 vLLM, Triton, K8s, FastAPI로 직접 구축할 수도 있지만, 확장성 & 네트워킹 관리가 부담스럽다면 Ray Serve(확장 가능, 프레임워크 불문 서빙 라이브러리)를 사용할 수 있다.
4. Building with a Cloud Vendor Show More Items
특정 서비스 사용법이 아니라 클라우드 벤더 서빙 옵션 뒤에 숨은 원리를 이해해 정보에 입각한 선택을 하는 것이 목적.
옵션 1: 완전 관리형 파운데이션 모델 서빙 (Amazon Bedrock)
- 가장 쉬움·가장 제한적. 모델 학습/호스팅 불필요 — 카탈로그에서 모델 선택 후 API만 호출
- 과금: 서버 시간당이 아닌 요청/토큰당(계정에 서버 없음, AWS가 내부적으로 확장·컴퓨트 관리) → DevOps 오버헤드 0
- 대가: AWS 제공 모델·구성으로 제한(아키텍처·학습 방식 변경 불가, 중간 수준의 파인튜닝·프롬프트 수정만 가능)
옵션 2: 원클릭 파운데이션 모델 배포 (SageMaker JumpStart)
- Bedrock처럼 모델 허브 제공 + 차이는 내 SageMaker 인프라에 배포된다는 것("원클릭 배포", Studio UI 또는 SDK)
- 과금: 관리형 인스턴스 시간당 — 인프라 관리 부담이 조금 늘고, 인스턴스 유형(g5.48xlarge 등) 선택 가능
옵션 3: Bring Your Own Model (DLC(딥러닝 컨테이너))
- "모델은 직접 가져오되, 서빙 코드는 안 가져와도 되는" 방식. TensorFlow/PyTorch/HuggingFace 등 프레임워크별 사전 구축 Docker 이미지(DLC)가 해당 모델 유형의 서빙을 알고 있음
- JumpStart와의 차이: 컨테이너(서빙 프레임워크)를 명시적으로 선택하고 배포 단계를 직접 관리 → 프레임워크 버전 선택, 카탈로그에 없는 모델 배포 가능
옵션 4: Bring Your Own Code (스크립트 모드)
- 벤더 컨테이너(DLC/LMI)는 유지하되, 모델 로딩·예측 로직을 담은 진입점 스크립트를 직접 제공 — 커스텀 전처리/후처리, 비표준 입출력, 컨테이너 내 다중 모델 로드 가능. 대가는 코드 작성·유지보수 부담.
옵션 5: Bring Your Own Serving Image (자체 Docker 컨테이너)
- 컨테이너 내부의 모든 것(언어·프레임워크·추론 코드·시스템 의존성·네트워크 구성)을 내가 결정. SageMaker는 컨테이너를 "간단한 계약(HTTP in/out, 헬스체크·호출 엔드포인트)을 지키는 블랙박스"로 취급하며 배포·엔드포인트 URL 제공만 담당
- 3장의 단일/멀티 모델 서빙 구현을 그대로 Docker에 넣어 SageMaker로 호스팅하는 것이 이 옵션
- 단점: 컨테이너 빌드·유지·업데이트, SageMaker 요구사항 준수, ECR 푸시, 테스트·디버깅 복잡성. 분산 KV 캐싱·프롬프트 캐싱·요청 라우팅 같은 인스턴스 간 협조 최적화가 필요하면 옵션 6으로
- 적합: 미지원/최신 모델·커스텀 스택, 시스템 수준 최적화·특정 OS 요구, 모델과 보조 서비스(메트릭 수집 등)를 한 컨테이너에 묶는 고급 사례
옵션 6: Build Your Own Serving Infrastructure (자체 서빙 인프라)
- 클라우드 인프라(예: 관리형 K8s=EKS) 위에 완전한 서빙 플랫폼을 직접 구축: 런타임(Triton, vLLM, TensorRT-LLM, KServe, Ray Serve) 선택, GPU 노드 그룹 운영, 트래픽 관리·오토스케일링·보안·관측성·비용 제어까지 직접 담당
- AWS 기본 요소(EKS, ALB/NLB, ECR, S3, EFS/EBS, IAM/IRSA, Karpenter/Cluster Autoscaler, CloudWatch)와 K8s 애드온(Prometheus/Grafana, OpenTelemetry, Fluent Bit, CNI/NetworkPolicy, Gatekeeper/Kyverno, Argo CD/Rollouts) 활용 가능
- 사용 시점: 커널·배치·토큰화·사이드카·비표준 API(gRPC/SSE)까지 완전 제어 필요 / GPU 스팟·GPU 공유(MIG/MPS)·모델 빈패킹·TPS 기반 오토스케일링 같은 공격적 비용·성능 튜닝 / 엄격한 컴플라이언스·데이터 격리(프라이빗 클러스터, VPC 전용 송출, 테넌트 격리, 감사 추적) / 최첨단 하드웨어·미지원 최적화(추측적 디코딩, KV 캐시 샤딩, 고급 라우팅)
옵션 비교 (의사결정 트리)
- 선택 기준의 출발점은 사용 편의성 vs 제어 — AWS 구성 요소를 많이 쓸수록 빨리 띄우고, 커스터마이즈가 필요할수록 아래 옵션으로 내려감
- 실전에서는 개발 속도만이 아니라 운영·유지보수 비용도 중요. 흔한 경로: 가장 간단한 옵션으로 아이디어 검증 → 성숙·요구 증가에 따라 커스텀으로 전환
- 예: Bedrock에서 Qwen3 실행(입력 100만 토큰당 $0.10) → 사용량 증가 시 옵션 2, 3으로 자체 계정 호스팅(시간당 $1.172 - 대량에선 토큰당보다 저렴) → 더 높은 처리량·낮은 지연이 필요해지면 옵션 4, 5, 6
5. Build or Buy?
- 자체 구축 vs 벤더 서비스는 스위치가 아니라 스펙트럼. 대부분의 팀은 벤더 플랫폼 위에서 커스텀 핸들러·오토스케일 신호·라우팅 로직·비용 제어를 얹는 중간 지점에서 운영
- 완전 BYO는 제어·대규모 비용 효율·엄격한 컴플라이언스(또는 벤더 종속 회피·멀티 클라우드)가 필요할 때만
- 선택 전략
- SLO(지연·처리량) 충족 + 비용 적정 + 개발 속도가 최우선 → 벤더 관리형 유지
- 일부 엔드포인트에 특수 배치·라우팅·성능 튜닝·테넌트 격리 필요 → 하이브리드
- 하드웨어·런타임·독립 네트워크 제어, 심층 비용 조정 필요 → BYO
- 처리량이 낮게 안정화되거나 시스템 복잡성이 효과를 못 내면 → 벤더 관리형으로 회귀
6. Measuring Performance in LLM Serving
아키텍처 결정은 결국 측정 가능한 결과로 평가된다. 핵심 지표는 지연시간(latency)과 처리량(throughput).
6.1 지연시간 지표
- E2E(종단 간) 지연시간: 요청 수신부터 전체 응답 생성 완료까지. 필요 시 요청 큐잉·네트워크·라우팅·확장 오버헤드 등 시스템 수준 지연까지 포함
- TTFT(Time To First Token): 요청 수신부터 첫 토큰 발행까지. 사용자 체감 "응답 속도". 프리필(prefill) 단계와 대응
- ITL/TPOT(Inter-Token Latency / Time Per Output Token): 첫 토큰 이후 후속 토큰 하나를 만드는 시간. 디코딩 단계와 대응, 자기회귀 생성 효율의 지표
- 우선순위는 사용 사례에 따라 다름: 하위 프로세스가 전체 출력에 의존하는 에이전트 워크플로 → E2E 최소화가 목표 / 실시간 스트리밍 챗봇 → TTFT가 UX에 가장 직결 / 출력이 매우 길면 ITL도 중요(높으면 응답이 느리게 느껴짐)
6.2 처리량 지표
- RPS/RPM(초당/분당 요청 수): ML & 비ML 공용 지표. 단, LLM에선 입출력 길이·동시 사용자 수에 크게 의존 → 트래픽 패턴이 다른 워크로드 간 비교는 무의미
- TPS(초당 토큰 수): LLM 생성 특화 지표. 출력 토큰만 계산(입력·합계 아님). 토큰당 비용 계산에도 활용
- TPS 부풀리기 위험
- ① 입력 길이를 줄이면 TTFT·요청당 작업량이 줄어 TPS가 실제보다 높게 나옴
- ② 배치 크기 확대·배치 내 입출력 길이 균일화로 GPU 활용률을 높여 TPS 개선 가능 → 벤치마크 해석 시 주의
6.3 성능 측정 모범 사례
- 지연 ↔ 처리량 트레이드오프 인지: 오프라인 배치는 처리량(=비용), 대화형은 지연이 핵심 지표
- 사용 사례별 "충분히 좋은" 지연 목표 설정: 챗봇이 이미 1초라면 0.5초 단축은 UX 개선이 미미 — 그 경우 처리량·비용 최적화로 전환
- E2E를 TTFT + ITL로 분해: 병목 위치를 특정하고 개선 방향 설정(출력 제한 시스템은 TTFT가 ITL보다 중요할 수 있음)
- 실제 트래픽 패턴 시뮬레이션: 긴 질문+짧은 답 vs 짧은 질문+긴 답은 완전히 다르게 동작. 트래픽은 균일하지 않으며 급증 시 큐잉 지연·요청 실패 발생 — 시뮬레이션 전 패턴 분석 필수
- 실험 일관성 유지: 한 번에 파라미터 하나만 변경해 효과를 분리, 요청 패턴·구성을 고정해 공정 비교
- 하드웨어 사용률 모니터링: GPU/CPU/메모리 추적으로 병목이 모델 동작인지 하드웨어 한계인지 판별
- 지표 조작·과장 금지: 부풀린 벤치마크는 프로덕션에서 역효과·최적화 방향 오도
- 프로덕션 지속 모니터링: 사용자 행동은 시간에 따라 변해 요청 급증·오류를 유발
- 테스트 스위트 주기 실행: 회귀 테스트(업데이트로 인한 성능 저하 방지), 확장성 테스트(피크 부하 시뮬레이션), A/B 테스트(새 최적화 기법의 데이터 기반 비교)
'ETC' 카테고리의 다른 글
| Hands-On LLM Serving and Optimization 책 스터디 1주차 (1) | 2026.08.02 |
|---|---|
| [AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드코드]스터디 4주차 (0) | 2026.07.26 |
| [AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드코드]스터디 3주차 (0) | 2026.07.20 |
| AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드코드 스터디: CH03-04 (2) | 2026.07.12 |
| [AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드코드]스터디 1주차 (0) | 2026.07.05 |