본문으로 건너뛰기

© 2026 Molayo

HuggingFace헤드라인2026. 05. 07. 07:19

긴 프롬프트가 다른 요청을 차단하는 방법 - LLM 성능 최적화

요약

LLM의 성능 최적화는 'prefill' 단계(전체 프롬프트 처리)와 'decode' 단계(토큰 생성) 간의 균형을 맞추는 것이 핵심입니다. 특히, 매우 긴 프롬프트를 가진 요청이 들어올 경우, 이 요청이 시스템의 전반적인 처리를 차단하는 병목 현상('prefill-큐 차단')을 일으킵니다. 최근 vLLM 업데이트에서는 짧은 요청들이 긴 프롬프트에 의해 지연되는 문제를 완화하기 위해 '빠른 통로(fast lane)'를 제공하지만, 근본적으로는 전반적인 GPU 자원 관리와 아키텍처 분리가 필요합니다.

핵심 포인트

  • 긴 프롬프트가 prefill 큐를 차단하여 시스템의 모든 요청 처리를 지연시키는 문제가 발생한다.
  • 전통적인 chunked-prefill 방식은 긴 프롬프트에 취약하며, 짧은 요청들이 대기하는 시간이 길어질 수 있다.
  • 최신 vLLM 업데이트는 병렬 prefill을 허용하고 '빠른 통로(fast lane)'를 제공하여 짧은 요청의 지연 시간을 개선했다.
  • 근본적인 해결책으로는 긴 프롬프트 전용 추론 서버와 라우터를 분리하여 자원 활용과 성능 격리를 달성하는 것이 가장 효과적이다.

prefill 단계에서는 전체 프롬프트를 처리해야 하며, 이를 병렬 처리하여 GPU 활용도를 포화시킬 수 있습니다. 이후 출력 토큰 (decode 단계) 의 경우 단일 추가 토큰만 처리하면 되며, 이는 계산량이 적지만 순차적으로 수행되어야 합니다. 많은 요청이 동시 처리될 때, 낮은 지연 시간을 목표로 하는 어떤 전략도 새로 도착한 요청의 prefill 단계를 실행하면서 기존에 예약된 요청의 decode 단계가 여전히 진행 중이어야 합니다. 따라서 새로운 요청과 실행 중인 요청을 동시에 처리하려면 prefill 과 decode 단계를 신중하게 균형 잡아야 하며, 이는 다음과 같이 두 가지 주요 문제를 제기합니다. 하나는 쉽게 해결할 수 있는 문제이고, 다른 하나는 더 근본적인 결함입니다.

개별 decode 단계는 계산량이 적기 때문에 여러 요청의 decode 를 배치하여 throughput 을 증가시킬 수 있습니다. 그러나 prefill 에서는 이 접근 방식이 작동하지 않습니다. 모든 프롬프트 토큰을 병렬 처리하기 때문에 단일 prefill 단계만으로도 GPU 활용도를 포화시킬 수 있기 때문입니다. 따라서 vLLM 의 기본 chunked-prefill 전략에서 각 prefill chunk 는 단일 요청의 프롬프트 토큰만 포함합니다. 다음 요청은 이전 prefill 단계가 완료될 때까지 기다려야 자신의 prefill 단계를 시작할 수 있습니다.

다른 요청에 대한 prefill chunk 의 순차적 스케줄링은 문제를 제기합니다: 매우 긴 프롬프트를 가진 요청이 prefill 에 예약되면, 이후의 모든 요청은 긴 prefill 의 지속 시간 동안 처리가 시작될 때까지 기다려야 합니다. 긴 프롬프트는 prefill-큐를 차단합니다. (순차적 prefill 처리는 chunked-prefill 의 기본 특성이며, 이미 decode 단계에 동시 요청이 있을 때만 나타납니다. 따라서 이 이름이 붙었습니다.)

불행히도, 이 문제는 vLLM-side 우선순위 스케줄링 (본 시리즈의 첫 번째 글 참조) 으로 해결할 수 없으며, 더 정교한 upstream scheduler 로도 해결할 수 없습니다. 이유는 긴 프롬프트가 이후 요청이 존재하기 전에 예약될 수 있기 때문입니다. 따라서 스케줄러는 기다릴 것이 없습니다.

직접적인 해결책은 다른 요청의 prefill chunk 를 병렬로 처리하는 것입니다. 이는 단일 요청의 prefill chunk 만으로도 계산 능력을 포화시킬 수 있는 경우 자원 최적화가 되지 않을 수 있습니다. 추가적으로 병렬로 실행되는 prefill 은 prefill 지속 시간을 약간 늘리고 동시 decode-요청을 더욱 느리게 만들 가능성이 높습니다. 그러나 이것이 짧은 요청의 지연 시간을 줄이고 시스템을 더 반응성 있게 보이게 만든다면 이는 수용 가능한 것입니다. 그러나 다음 요청이 긴 프롬프트를 가진 경우 이 접근 방식은 실패합니다. 이러한 경우 두 계산 집중한 prefill 은 배치되어 심각한 느려짐을 초래합니다.

최근 vLLM 업데이트 중 하나에서 개선된 전략이 구현되었습니다: 이는 다른 요청들의 병렬 프레필 (prefill) 을 허용하지만, 동시에 처리되는 긴 프롬프트 요청의 수에는 제한을 둡니다. 예시 구성은 4 개의 요청을 위한 프레필 배치 (batching) 를 가능하게 할 수 있지만, 그 중 하나만 10,000 토큰 이상의 프롬프트 길이로 제한됩니다. 이러한 구성 하에서 긴 요청의 동작은 이전과 동일합니다: 긴 프롬프트는 순차적으로 처리됩니다. 짧은 요청은 이제 더 이상 이전 요청의 긴 프레필이 완료될 때까지 기다리지 않아도 되며, 짧은 프롬프트는 빠른 통로 (fast lane) 를 이용할 수 있습니다. 이러한 요청들은 더 이상 긴 대기 시간을 겪지 않으며, time-to-first-token 지표를 훨씬 낮게 보입니다.

물론 병렬 프레필은 대기 시간을 줄일 수 있지만, 동시 긴 프레필 작업 중에는 토큰당 출력 시간 (time-per-output-token) 이 여전히 높습니다. 이 점에서는 요청 병렬 프레필이 표준 체인크드 프레필과 동일한 동작 및 성능을 보이지만, 더 짧은 time-to-first-token 을 가집니다.

프레필과 디코드가 다른 요청에서 동일한 GPU 작업에서 실행될 경우, 격리된 디코드 단계보다 시간이 더 걸립니다. 사용자는 후속 요청의 토큰 생성이 중단되거나 느려지는 경험을 합니다. 특히, 긴 프롬프트를 가진 단일 요청은 이미 디코드 단계에 있는 모든 이전에 예약된 요청을 지연시킵니다.

이는 동일한 GPU 에서 프레필과 디코드를 병렬 처리하는 근본적인 결함입니다. 왜냐하면 다음과 같은 해결책이 거의 없습니다:

  • (a) 당신은 긴 프롬프트를 페널티화하고 기다리게 할 수 있습니다(예: 모든 짧은 고우선 요청이 완료될 때까지). 이는 해당 요청의 지연 시간 증가라는 비용이 따르며, 근본 원인을 해결하지는 않습니다. 특히 요청 병렬 프레필이 활성화되면, 긴 프롬프트 요청 이후 예약된 짧은 프롬프트 요청에도 지연 효과가 발생합니다. 또한, 높은 부하 시에는 긴 프롬프트 요청이 합리적인 시간 내에 예약될 확률이 매우 작습니다. TNG 에서 우리는 매우 낮은 우선순위로 예약된 배치 요청을 위한 API 에서 유사한 전략을 구현했습니다.
  • (b) 당신은 긴 프롬프트 요청용 별도의 추론 서버와 부하 및 프롬프트 길이에 따라 요청을 전달하는 라우터를 가질 수 있습니다. 이 접근법은 더 많은 GPU 자원을 필요로 하지만, 짧은 컨텍스트 요청용 추론 서버는 GPU 메모리 요구 사항이 낮습니다 (예: Llama-3.3-70B 는 130k 토큰의 컨텍스트 길이를 위해 4 개의 H100 을 필요로 하지만, 두 번째 배포인 2 개의 H100 은 이미 <10k 토큰의 컨텍스트 길이의 요청을 처리할 수 있습니다). 그러나 자원 활용을 최적화하기 위해 복잡한 라우터 설계가 필요합니다. 예를 들어, 긴 프롬프트 요청이 없을 때 더 큰 추론 서버도 여전히 사용되어야 합니다.
  • (c) 당신은 프레필과 디코드를 위한 별도의 추론 엔진을 가질 수 있습니다. 이 분리된 프레필 아키텍처는 각 vLLM 배포를 결합하며, 각각은 오직 프레필 또는 오직 디코드를 실행합니다. 프레필 단계를 완료한 후 KV 캐시는 디코드 워커로 전달되어 작은 통신 오버헤드가 발생합니다. 그러나 프레필과 디코드는 서로 다른 GPU 에서 격리되어 실행되므로, 동시 프레필에 의해 디코드가 직접적으로 방해받지 않습니다.

이론적 동시 처리 (단독 요청과 동일함) 와 실제 동시 처리, 그리고 분리된 프리필 전략의 차이는 다음 측정치로 보여집니다:

프리필과 디코드를 분리하면 다른 요청의 존재 시 토큰 생성 속도가 느려지는 것을 상당 부분 제거합니다. 이는 매우 매력적인 전략입니다. 단점으로는 두 번째 전체 크기 vLLM 배포가 필요하다는 점 (예: Llama-3.3-70B 의 경우 최대 컨텍스트 길이를 130k 토큰으로 지원하려면 프리필 워커를 위해 4 개의 H100 GPU 와 디코드 워커를 위해 또 다른 4 개의 H100 GPU 가 필요합니다) 이 있습니다. 또한 불균형 GPU 활용도라는 단점이 있습니다: 프리필은 계산 집약적이지만 디코드는 그렇지 않으므로, 프리필 워커는 디코드 워커보다 먼저 GPU 활용도를 포화시킬 가능성이 높습니다. 반면에 대규모 클러스터는 부하 패턴에 따라 다른 수의 프리필과 디코드 워커로 구성될 수 있습니다.

분리된 프리필은 총 트래픽을 증가시키려는 것이 아니라, 총 "좋은 성능" (즉, 지연 목표치를 만족하는 요청의 비율) 을 높이는 데 목적이 있습니다. 따라서 개별 요청의 지연에 민감하지 않은 애플리케이션에서는 GPU 자원의 최적 사용법이 아닙니다.

또한 주의할 점: vLLM 의 분리된 프리필 기능은 아직 실험적이며, 일부 최적화와 기능은 아직 접근 불가능합니다. 예를 들어, 현재 컨텍스트 길이에 대한 하한 제한이 있으며, 디코드 워커는 CUDA 그래프를 일관되게 사용하지 않아 위의 그림에서 긴 프롬프트 요청의 느린 디코드가 발생합니다. 다행히도 이는 근본적인 장애물이 아니며 vLLM 의 향후 버전에서 해결될 가능성이 높습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Hugging Face Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
2

댓글

0