최적화와 튜닝
최적화와 튜닝 (Optimization and Tuning)
이 글은 vLLM V1의 성능 최적화 전략과 튜닝 방법을 다룹니다. 메모리가 부족하다면 메모리 절약 가이드를 먼저 참고하세요.
출처: 문서
본문
선점 (Preemption)
트랜스포머 구조의 자기회귀(auto-regressive) 특성 때문에 KV 캐시 공간이 모든 배치 요청을 감당하지 못하는 때가 있습니다. 이때 vLLM은 요청을 선점(preempt)해 다른 요청에 KV 캐시 공간을 확보해 주고, 공간이 생기면 선점된 요청을 다시 계산(recompute)합니다. 이런 경우 다음 경고가 보일 수 있습니다.
WARNING 05-09 00:49:33 scheduler.py:1057 Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space. This can affect the end-to-end performance. Increase gpu_memory_utilization or tensor_parallel_size to provide more KV cache memory. total_cumulative_preemption_cnt=1
이 메커니즘은 시스템 견고성을 보장하지만, 선점과 재계산은 엔드투엔드 지연 시간에 악영향을 줄 수 있습니다. 잦은 선점이 발생한다면 다음 조치를 고려하세요.
gpu_memory_utilization을 높인다 — vLLM은 이 비율만큼 GPU 캐시를 미리 할당하므로, 높이면 KV 캐시 공간이 늘어납니다.max_num_seqs나max_num_batched_tokens를 줄인다 — 배치의 동시 요청 수를 줄여 KV 캐시 요구량을 낮춥니다.tensor_parallel_size를 늘린다 — 모델 가중치를 여러 GPU로 샤딩해 각 GPU에 KV 캐시용 메모리가 더 남습니다. 다만 동기화 오버헤드가 커질 수 있습니다.pipeline_parallel_size를 늘린다 — 모델 레이어를 여러 GPU에 분산해 각 GPU의 가중치 메모리를 줄여 간접적으로 KV 캐시 공간을 확보합니다. 단 지연 시간 패널티가 있을 수 있습니다.
선점 횟수는 vLLM이 노출하는 Prometheus 메트릭으로 모니터링할 수 있고, disable_log_stats=False로 누적 선점 횟수를 로그로 남길 수도 있습니다. vLLM V1의 기본 선점 모드는 SWAP이 아니라 RECOMPUTE입니다. V1 아키텍처에서는 재계산이 오버헤드가 더 낮기 때문입니다.
청크 프리필 (Chunked Prefill)
청크 프리필은 큰 프리필을 더 작은 청크로 나누고 디코드 요청과 함께 배칭할 수 있게 합니다. 계산 중심(프리필)과 메모리 중심(디코드) 연산의 균형을 잘 맞춰 처리량과 지연 시간을 모두 개선합니다.
V1에서 청크 프리필은 가능하면 기본적으로 켜집니다. 활성화되면 스케줄링 정책이 디코드 요청을 우선합니다. 대기 중인 디코드 요청을 먼저 배칭한 뒤, max_num_batched_tokens 예산에 여유 토큰이 있을 때 대기 중인 프리필을 스케줄합니다. 맞지 않는 프리필은 자동으로 청크로 나눕니다.
이 정책의 이점은 두 가지입니다.
- 디코드 요청이 우선이라 ITL과 생성 디코드가 좋아집니다.
- 계산 중심(프리필)과 메모리 중심(디코드) 요청을 같은 배치에 두어 GPU 활용률이 높아집니다.
청크 프리필 성능 튜닝
max_num_batched_tokens로 성능을 조정할 수 있습니다.
- 작은 값(예: 2048)은 프리필이 디코드를 늦추는 일이 적어 토큰 간 지연(ITL)이 좋아집니다.
- 큰 값은 배치에서 더 많은 프리필 토큰을 처리할 수 있어 첫 토큰까지의 시간(TTFT)이 좋아집니다.
- 최적 처리량을 위해
max_num_batched_tokens > 8192를 권장합니다(특히 큰 GPU의 작은 모델). max_num_batched_tokens가max_model_len과 같으면 거의 V0 기본 스케줄링 정책과 동등해집니다(디코드 우선은 여전히 유지).
from vllm import LLM
# max_num_batched_tokens 로 성능 튜닝
llm = LLM(model="meta-llama/Llama-3.1-8B-Instruct", max_num_batched_tokens=16384)
관련 논문: https://arxiv.org/pdf/2401.08671 또는 https://arxiv.org/pdf/2308.16369
병렬화 전략 (Parallelism Strategies)
vLLM은 조합 가능한 여러 병렬화 전략을 지원합니다.
텐서 병렬화 (TP)
모델 파라미터를 각 레이어 안의 여러 GPU에 샤딩합니다. 단일 노드에서 대형 모델 추론에 가장 흔한 전략입니다. 모델이 GPU 하나에 너무 클 때, 또는 GPU당 메모리 압박을 줄여 처리량을 높이고 싶을 때 사용합니다.
from vllm import LLM
# 모델을 4개 GPU에 분할
llm = LLM(model="meta-llama/Llama-3.3-70B-Instruct", tensor_parallel_size=4)
파이프라인 병렬화 (PP)
모델 레이어를 여러 GPU에 분산합니다. 각 GPU는 모델의 다른 부분을 순차 처리합니다. 텐서 병렬화를 이미 최대로 썼는데 더 분산(또는 노드 간 분산)이 필요할 때나, 텐서 샤딩보다 레이어 분산이 효율적인 매우 깊고 좁은 모델에서 사용합니다. 대형 모델에서는 텐서 병렬화와 결합할 수 있습니다.
from vllm import LLM
# 파이프라인 + 텐서 병렬화 결합
llm = LLM(
model="meta-llama/Llama-3.3-70B-Instruct",
tensor_parallel_size=4,
pipeline_parallel_size=2,
)
전문가 병렬화 (Expert Parallelism, EP)
MoE(Mixture of Experts) 모델 전용 병렬화로, 서로 다른 전문가 네트워크를 여러 GPU에 분산합니다. DeepSeekV3, Qwen3MoE, Llama-4 같은 MoE 모델에서 전문가 연산 부하를 GPU 간에 균형 있게 나눌 때 사용합니다. enable_expert_parallel=True로 켜면 MoE 레이어에 텐서 병렬화 대신 전문가 병렬화를 쓰며, 텐서 병렬화에 설정한 것과 같은 병렬도(degree)를 사용합니다.
데이터 병렬화 (Data Parallelism, DP)
전체 모델을 여러 GPU 세트에 복제하고 서로 다른 배치의 요청을 병렬 처리합니다. 모델을 복제할 GPU가 충분할 때, 모델 크기가 아니라 처리량을 늘려야 할 때, 요청 배치 간 격리가 유용한 다중 사용자 환경에서 사용합니다. data_parallel_size=N으로 설정하며 다른 전략과 결합할 수 있습니다. MoE 레이어는 텐서 병렬 크기와 데이터 병렬 크기의 곱에 따라 샤딩됩니다.
멀티모달 인코더의 배치 레벨 DP
기본적으로 멀티모달 인코더의 가중치는 언어 디코더처럼 TP로 샤딩됩니다. 그러나 멀티모달 인코더는 언어 디코더보다 훨씬 작아 TP의 이득이 적고, 레이어마다 all-reduce가 일어나 통신 오버헤드가 큽니다. 대신 배치된 입력 데이터를 TP로 샤딩하는 배치 레벨 DP가 유리할 수 있습니다. tensor_parallel_size=8에서 처리량과 TTFT를 약 10% 개선했고, 하드웨어 비최적화 Conv3D를 쓰는 비전 인코더는 일반 TP보다 40% 추가 개선됩니다. 다만 멀티모달 인코더 가중치가 각 TP 랭크에 복제되므로 메모리 사용이 약간 늘어 모델이 간신히 들어가는 상황이라면 OOM이 날 수 있습니다.
from vllm import LLM
llm = LLM(
model="Qwen/Qwen2.5-VL-72B-Instruct",
tensor_parallel_size=4,
# mm_encoder_tp_mode="data" 일 때
# 비전 인코더는 TP=4 (DP=1이 아님) 로 입력 데이터를 샤딩하므로
# TP 크기가 실질적 DP 크기가 된다.
# 이는 expert parallel 설정에서 언어 디코더의 DP 크기와 독립적이다.
mm_encoder_tp_mode="data",
)
중요: 배치 레벨 DP는 API 요청 레벨 DP(
data_parallel_size로 제어)와 혼동하지 마세요. 배치 레벨 DP는 모델별로 구현되며 모델 클래스의supports_encoder_tp_data = True로 활성화됩니다. 어쨌든 엔진 인자에mm_encoder_tp_mode="data"를 설정해야 합니다.지원 모델: dots_ocr, GLM-4.1V 이상, InternVL, Kimi-VL, Llama4, MiniCPM-V-2.5 이상, Qwen2-VL 이상, Step3.
입력 처리 (Input Processing)
병렬 처리
API 서버 스케일아웃으로 입력 처리를 병렬로 돌릴 수 있습니다. 입력 처리(API 서버 안에서 실행)가 모델 실행(엔진 코어 안에서 실행)에 비해 병목이고 CPU 여력이 있을 때 유용합니다.
# API 프로세스 4개 + 엔진 코어 프로세스 1개
vllm serve Qwen/Qwen2.5-VL-3B-Instruct --api-server-count 4
# API 프로세스 4개 + 엔진 코어 프로세스 2개
vllm serve Qwen/Qwen2.5-VL-3B-Instruct --api-server-count 4 -dp 2
참고: API 서버 스케일아웃은 온라인 추론에서만 사용할 수 있습니다.
경고: 기본적으로 각 API 서버는 요청 데이터에서 미디어(예: 이미지)를 로드할 때 CPU 스레드 8개를 씁니다. 스케일아웃을 적용한다면
VLLM_MEDIA_LOADING_THREAD_COUNT를 조절해 CPU 자원 고갈을 피하세요.참고: API 서버 스케일아웃은 API와 엔진 코어 프로세스의 일대일 대응이 필요하므로 멀티모달 IPC 캐싱을 비활성화합니다. 이는 멀티모달 프로세서 캐싱에는 영향을 주지 않습니다.
멀티모달 캐싱 (Multi-Modal Caching)
멀티모달 캐싱은 멀티턴 대화에서 흔히 발생하는 동일한 멀티모달 데이터의 반복 전송·처리를 피합니다.
- 프로세서 캐싱(Processor Caching):
BaseMultiModalProcessor에서 동일한 멀티모달 입력을 반복 처리하지 않도록 자동 활성화됩니다. - IPC 캐싱: API(
P0)와 엔진 코어(P1) 프로세스가 일대일 대응일 때 자동 활성화되어, 그 사이의 반복 전송을 피합니다.- 키 복제 캐시(Key-Replicated Cache): 기본값. 캐시 키가 P0와 P1 양쪽에 있지만 실제 데이터는 P1에만 있습니다.
- 공유 메모리 캐시(Shared Memory Cache): 워커가 여러 개일 때(예: TP > 1) 더 효율적.
mm_processor_cache_type="shm"으로 활성화. 키는 P0에, 데이터는 모든 프로세스가 접근 가능한 공유 메모리.
- 설정:
mm_processor_cache_gb(기본 4 GiB)로 캐시 크기 조절. 캐시 이득이 없다면mm_processor_cache_gb=0으로 IPC·프로세서 캐싱을 모두 끌 수 있습니다.
# 더 큰 캐시
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
mm_processor_cache_gb=8,
)
# 공유 메모리 기반 IPC 캐시
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
tensor_parallel_size=2,
mm_processor_cache_type="shm",
mm_processor_cache_gb=8,
)
# 캐시 끄기
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
mm_processor_cache_gb=0,
)
캐시 배치 (Cache Placement)
설정에 따라 P0/P1의 멀티모달 캐시 내용은 다음과 같습니다 (K = 멀티모달 아이템 해시, V = 처리된 텐서 데이터).
mm_processor_cache_type |
캐시 종류 | P0 캐시 | P1 엔진 캐시 | P1 워커 캐시 | 최대 메모리 |
|---|---|---|---|---|---|
lru |
Processor Caching | K + V | N/A | N/A | mm_processor_cache_gb * data_parallel_size |
lru |
Key-Replicated Caching | K | K + V | N/A | mm_processor_cache_gb * api_server_count |
shm |
Shared Memory Caching | K | N/A | V | mm_processor_cache_gb * api_server_count |
| N/A | Disabled | N/A | N/A | N/A | 0 |
더 알아보기 (Learn more)
- Conserving Memory — 메모리 절약 옵션
- Engine Arguments —
max_num_batched_tokens,gpu_memory_utilization, 병렬화 인자 등 전체 목록 - Environment Variables —
VLLM_MEDIA_LOADING_THREAD_COUNT등 환경 변수