vLLM 배치 튜닝, max_num_seqs와 max_num_batched_tokens를 나눠 조정하는 법

여러 GPU와 냉각 장치가 연결된 로컬 AI 추론 서버 구성

AI를 활용하여 생성한 이미지입니다.

vLLM 서버가 갑자기 느려지거나 GPU 메모리 부족으로 요청을 선점할 때 gpu_memory_utilization만 올리는 식으로 끝내기 어렵습니다. 실제로는 한 번에 묶는 요청 수와 한 배치에서 처리할 토큰 수가 KV 캐시를 얼마나 차지하는지 함께 봐야 해요. max_num_seqs와 max_num_batched_tokens를 같은 종류의 손잡이로 보면 튜닝 방향이 꼬입니다.

두 옵션은 무엇을 제한할까

max_num_seqs는 한 번에 실행할 시퀀스 수를 제한하는 값으로 이해하면 좋아요. 동시 요청이 많을 때 상한을 낮추면 KV 캐시를 덜 요구하지만, 대기열이 길어질 수 있어요. 반면 max_num_batched_tokens는 한 스케줄링 배치에서 처리할 토큰량을 조절하는 손잡이에 가까워요. 입력이 긴 요청을 많이 받는 서버에서는 이 값을 바꿀 때 prefill과 decode가 서로 방해하는 정도가 달라질 수 있습니다.

vLLM 문서는 메모리 부족으로 선점이 일어날 때 max_num_seqs나 max_num_batched_tokens를 줄이는 방법을 제시해요.[1] 둘 다 줄이면 당장 메모리 압박은 완화될 수 있지만, 처리량과 첫 토큰 지연 시간이 함께 나빠질 수 있어서 한 번에 하나씩 바꿔야 합니다.

증상 먼저 볼 값 예상되는 변화
동시 요청이 많을 때 KV 캐시 부족 max_num_seqs 동시 실행량 감소, 대기 증가 가능
긴 입력에서 첫 토큰이 늦음 max_num_batched_tokens prefill 배치 크기와 TTFT 변화
처리량이 낮고 GPU가 자주 놀음 두 값과 요청 길이 분포 배치가 너무 보수적인지 확인
반복적인 선점·재계산 메모리 여유와 시퀀스 상한 캐시 상한을 낮추거나 모델 병렬화 검토

먼저 측정 조건을 고정하세요

배치 튜닝은 단일 요청을 빠르게 만드는 작업이 아니에요. 동시 요청 수, 입력 토큰 길이, 출력 상한, 스트리밍 여부가 달라지면 같은 값도 전혀 다른 결과를 냅니다. 최소한 다음 조건을 기록한 뒤 실험하세요.

  • 모델과 양자화 방식, GPU 수와 GPU별 메모리
  • 입력 토큰 길이의 중앙값과 긴 요청 구간
  • 동시 요청 수와 출력 토큰 상한
  • TTFT, TPOT, 전체 완료 시간, 선점 발생 여부

짧은 프롬프트만 반복하면 긴 컨텍스트에서 생기는 KV 캐시 문제를 놓쳐요. 반대로 긴 요청만 넣으면 실제 서비스의 평균 지연을 과장할 수 있습니다. 대표 요청을 짧은 구간과 긴 구간으로 나누고, 같은 부하를 각 설정에 반복해서 넣는 편이 낫습니다.

메모리 부족이면 max_num_seqs부터 좁혀요

선점이나 캐시 부족이 명확할 때는 max_num_seqs를 작은 폭으로 낮춰 동시 실행 상한을 줄이는 것이 첫 단계예요. 예를 들어 현재 값에서 25%만 낮춘 뒤, 같은 부하로 선점 횟수와 p95 지연을 다시 비교하세요. 수치 하나를 정답처럼 제시하기보다, 메모리 여유와 서비스의 동시성 목표 사이에서 경계를 찾는 방식이 안전합니다.

이 값을 너무 낮추면 GPU가 충분히 바쁘지 않은데 요청이 대기할 수 있어요. 따라서 GPU 사용률만 보고 성공했다고 판단하지 말고, 처리된 출력 토큰 수와 요청 완료율을 함께 봐야 합니다. 여러 GPU를 쓰는 환경에서는 tensor_parallel_size를 늘려 가중치를 나누는 방법도 있지만, vLLM 문서는 GPU 간 동기화 오버헤드가 커질 수 있다고 경고해요.[1]

긴 입력이 병목이면 max_num_batched_tokens를 따로 봅니다

vLLM 문서는 chunked prefill 성능을 max_num_batched_tokens로 조절할 수 있다고 설명하고, 예시로 16,384를 사용해요.[1] 이 숫자를 모든 모델과 GPU에 그대로 복사하면 안 돼요. 배치 토큰 상한이 커지면 긴 입력을 한 번에 더 밀어 넣을 수 있지만, decode 중인 요청이 기다리거나 메모리 여유가 줄 수 있습니다.

긴 입력의 TTFT가 너무 길다면 이 값을 조금 올리고, 기존 요청의 TPOT와 p95를 함께 측정하세요. 반대로 생성 중인 답변이 자주 끊기거나 지연이 출렁이면 값을 낮춰 prefill이 decode를 덜 방해하도록 조정해 볼 수 있어요. 한 번의 실험에서 두 옵션을 동시에 바꾸면 어느 값이 효과를 냈는지 알 수 없습니다.

실험 순서와 되돌리기

  1. 현재 실행 인자와 메트릭을 파일로 보관해 기준선을 남겨요.
  2. 선점·OOM이 문제면 max_num_seqs만 낮춰 같은 부하를 재현해요.
  3. 긴 입력 TTFT가 문제면 max_num_batched_tokens만 바꿔 비교해요.
  4. 처리량, TTFT, TPOT, p95, 선점 횟수를 함께 기록해요.
  5. 개선이 없으면 원래 값을 복원하고 요청 길이 제한이나 모델 병렬화를 따로 검토해요.

vLLM의 최신 엔진 인자 문서는 실행 옵션의 기준점이에요.[2] 버전에 따라 인자 이름이나 기본 동작이 달라질 수 있으므로, 운영 서버에서 복사한 실제 실행 명령과 해당 버전의 문서를 함께 보관하세요. 문서의 예시값은 출발점이지 성능 보증값이 아닙니다.

특히 운영 환경에서는 평균 처리량만 보고 값을 고르면 안 돼요. 짧은 요청은 빨라졌는데 긴 요청의 p95가 크게 늘었다면 사용자 체감은 나빠진 것입니다. 요청 길이별 결과를 나누고, 서비스가 허용하는 최대 대기 시간 안에서 선점과 처리량이 함께 안정되는 지점을 선택하세요.

실험 결과는 값만 남기지 말고 모델 버전과 요청 길이 구간까지 함께 저장하세요. 나중에 GPU를 바꾸거나 모델을 교체했을 때 과거 수치를 그대로 비교하지 않도록 기준을 분리할 수 있습니다.

출처

  1. vLLM 공식 문서: Optimization and Tuning
  2. vLLM 공식 문서: Engine Arguments

함께 읽을 글