vLLM을 사용하여 NVIDIA B300 GPU에서 GLM-5.2 제공

NVIDIA B300 GPU에서 vLLM으로 GLM-5.2 제공

vLLM은 disaggregated Prefill/Decode (P/D) 토폴로지를 사용하여 24개의 NVIDIA B300 GPU(8-GPU 서버 3대)에 GLM-5.2-NVFP4를 성공적으로 배포했습니다. 피크 처리량보다는 Service Level Agreement (SLA) 준수를 최적화함으로써, 팀은 평균 Time Per Output Token (TPOT)을 거의 40 ms에서 17 ms로 줄여, 16K에서 256K 토큰 사이의 컨텍스트 길이에 대해 평균 TTFT ≤ 2.5 s 및 평균 TPOT ≤ 20 ms의 생산 목표를 달성했습니다.

피크 처리량보다 SLA 준수 우선시

공동 배치 serving에서, prefill 청크는 decode 배치와 interleaving될 수 있어, 긴 프롬프트가 기존 요청의 inter-token latency를 증가시킬 수 있습니다. vLLM은 P/D disaggregation을 사용하여 decode critical path에서 prefill 작업을 제거함으로써, TPOT이 decode batch 구성에 solely 결정되도록 보장합니다.

이 배포의 생산 요구 사항은 다음과 같습니다:

  • 컨텍스트 길이: 16K–256K 토큰.
  • 평균 TTFT (첫 번째 토큰까지 시간): ≤ 2.5 s.
  • 평균 TPOT (출력 토큰당 시간): ≤ 20 ms (약 50 토큰/초).
  • 처리량: 두 지연 제약 조건이 충족된 후에만 최대화됩니다.

GLM-5.2는 40B 활성 파라미터를 가진 744B 파라미터 MoE 모델로, DSA 희소 어텐션과 MTP 추측 디코딩을 활용합니다.

디코드 성능 최적화

초기 구성에서는 16K 토큰 입력에 대해 평균 TPOT이 거의 40 ms였습니다. SLA 한도 내로 가져오기 위해 다음과 같은 최적화가 구현되었습니다:

혼합 배치를 위한 speculative padding

프로파일링 결과, Prefill 노드에서 Decode 노드로 요청이 전송될 때, 해당 요청의 첫 번째 Decode 단계는 단 하나의 토큰만 필요하지만, Multi-Token Prediction (MTP)을 사용하는 기존 요청은 1 + N 토큰이 필요하다는 것이 밝혀졌습니다. 이 불일치는 혼합 배치를 생성하여, 시스템이 빠른 CUDA Graph 경로에서 비용이 많이 드는 piecewise 또는 eager 실행으로 폴백되도록 강제합니다.

이 문제를 해결하기 위해, vLLM은 Decode 측에 speculative padding을 구현하여, 새로운 요청의 첫 번째 단계에 더미 토큰을 추가하여 1 + N 형태와 일치시켰습니다. 이 최적화(PR #45237에 병합됨)는 평균 TPOT을 40 ms에서 22 ms로 감소시켰습니다.

Model Runner V2 (MRV2)

Model Runner V2(VLLM_USE_V2_MODEL_RUNNER=1)를 활성화하면 TPOT이 11% 감소했습니다. 주요 개선 사항은 다음과 같습니다:

  • 워밍업 커널: 콜드 스타트 latency 스파이크를 방지하기 위해 시작 워밍업에 GLM-5.2 DSA indexer prefill-metadata 커널이 추가되었습니다(PR #47285).
  • Local Argmax Reduction: Multi-GPU MTP는 이제 local argmax reduction을 사용합니다(PR #46448), 이로 인해 TP 통신량이 전체 어휘 로짓에서 약 2 × TP 크기로 감소합니다.
  • 동적 speculative 길이: 전체 CUDA Graph는 이제 동적 speculative 길이를 지원합니다(PR #45953), eager 폴백을 줄입니다.

통신 및 그래프 구성

  • All-to-All 백엔드: 기본 EP 백엔드를 flashinfer_nvlink_two_sided 백엔드로 교체하여 TPOT이 4% 감소했습니다.
  • CUDA Graph 모드: Decode 인스턴스는 --max-num-batched-tokens 1024와 함께 FULL_DECODE_ONLY 모드를 사용하며, 이는 시작 컴파일 시간을 줄이면서 전체 그래프 커버리지를 제공합니다.
  • MTP 구성: Decode 측은 실행 비용을 상쇄하기 위해 num_speculative_tokens=3를 사용하고, Prefill 측은 빠른 KV 캐시 handoff를 우선시하기 위해 num_speculative_tokens=1를 사용합니다.

Prefill 병렬 처리 및 용량 트레이드오프

Prefill에 대한 병렬 처리 전략을 평가할 때, 팀은 GPU당 처리량(TGS)을 비교했습니다. TP1 DP4 EP는 GPU당 가장 효율적인 구성이 아니었습니다(TP1 DP2 EP가 8% 더 효율적이었음), 하지만 GLM-5.2의 1M 토큰 컨텍스트 기능을 위해 충분한 KV-cache 용량을 확보하기 위해 TP1 DP4 EP가 선택되었습니다.

MTP 수용률 안정화

고 concurrency 상황에서 speculative decoding이 효과적으로 유지되도록 하기 위해, vLLM은 IndexerCache(PR #44420)를 구현했습니다. 이 메커니즘은 DSA indexer가 생성한 Top-K 희소 인덱스를 재사용하여, 시스템이 MTP 드래프트 단계마다 indexer를 다시 실행하지 않도록 방지합니다.

추가적인 안정성 수정 사항은 다음과 같습니다:

  • Indexer 초기화: Top-K 레이어를 건너뛸 때 정규화 루프와 초기화가 개선되었습니다(PR #45895).
  • 공유 인덱스 버퍼: 배치 요청에 대한 레이아웃을 최적화하여 최종 쿼리 토큰에 대한 인덱스만 유지하도록 했습니다(PR #47238).
  • Post-Final-Norm 숨은 상태: MTP 루프가 post-final-norm 숨은 상태를 재사용하도록 보장했습니다(PR #47448).

AIME 2025(86.67), GPQA(92.89), LongBench V2(64.01)에서의 정확도 검증은 이러한 최적화가 출력 품질을 저하시키지 않았음을 확인했습니다.

프로덕션 옵저버빌리티 및 안정성

디스aggregated P/D 배포의 모니터링은 두 리소스 풀에 걸쳐 메트릭을 추적해야 합니다. 주요 메트릭에는 풀별 TTFT/TPOT 백분위수, MTP 수용률, 그리고 KV 전송 지연이 포함됩니다.

장기 안정성 테스트 중에 팀은 vLLM 프로세스의 RSS가 수 시간 동안 선형적으로 증가하는 호스트 메모리 누수를 발견했습니다. 근본 원인은 SingleTypeKVCacheManager.new_block_ids(PR #35219)에서의 일관되지 않은 게팅 메커니즘이었으며, 이는 non-Mamba 모델에 대한 블록 할당을 기록했지만 결코 배출하지 않았습니다. 이 문제는 모든 스케줄링 단계에서 take_new_block_ids()를 무조건적으로 배출함으로써 수정되었습니다.

배포 레시피

하드웨어 및 토폴로지

  • 하드웨어: 3 × 8 B300 GPU(총 24대).
  • 모델: GLM-5.2-NVFP4.
  • 토폴로지: 4개의 Prefill 노드(TP1 DP4 EP, 16 GPU)와 1개의 Decode 노드(TP1 DP8 EP, 8 GPU).
  • KV 전송: NIXL.

구성 명령어

Prefill 노드:

export VLLM_USE_V2_MODEL_RUNNER=1
vllm serve /mnt/model/glm/GLM-5.2-NVFP4 --trust-remote-code --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_producer"}' --chat-template-content-format=string -ep -tp 1 -dp 4 --tool-call-parser glm47 --enable-auto-tool-choice --reasoning-parser glm45 --gpu-memory-utilization 0.92 --enable-prompt-tokens-details --speculative-config='{"method":"mtp","num_speculative_tokens":1}' --shutdown-timeout 300 --fingerprint-mode=none

Decode 노드:

export VLLM_USE_V2_MODEL_RUNNER=1
vllm serve /mnt/model/glm/GLM-5.2-NVFP4 --trust-remote-code --chat-template-content-format=string --kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_consumer"}' --compilation-config '{"cudagraph_mode":"FULL_DECODE_ONLY"}' --max-num-batched-tokens 1024 -ep -tp 1 -dp 8 --tool-call-parser glm47 --enable-auto-tool-choice --reasoning-parser glm45 --gpu-memory-utilization 0.90 --enable-prompt-tokens-details --all2all-backend=flashinfer_nvlink_two_sided --speculative-config='{"method":"mtp","num_speculative_tokens":3}' --shutdown-timeout 300 --fingerprint-mode=none

Sources