공지TechKnowGenie 블로그를 오픈했습니다.
IT•읽는 데 약 21분

vLLM V1 코어 리팩토링 아키텍처: Zero-overhead C++ 스케줄러와 Dynamic Chunked Prefill, PagedAttention v3 심층 분석

기존 파이썬 GIL과 비동기 루프의 병목을 극복하기 위해 엔진 코어를 C++ 분산 오케스트레이터로 재구축하여 스케줄링 오버헤드를 87% 감축하고, Chunked Prefill과 Decode의 파이프라인 중첩 및 PagedAttention V3를 도입한 vLLM V1 차세대 서빙 아키텍처를 소스 코드 수준에서 심층 분석합니다.

관리자
목차 (9)
  1. vLLM V0의 구조적 한계와 호스트 CPU 스케줄링 병목
  2. vLLM V1 C++ 코어 오케스트레이터의 Zero-Overhead 설계
  3. Dynamic Chunked Prefill: 프리필과 디코드의 유기적 파이프라이닝
  4. PagedAttention V3와 Radix Prefix Cache 융합
  5. PagedAttention V3 커널 아키텍처와 하드웨어 레벨 메모리 정렬
  6. vLLM V1 C++ 스케줄러 핵심 구현 해부
  7. 정량적 성능 벤치마크 및 리소스 비교 분석
  8. 실무 엔지니어링 한계 및 프로덕션 고려 사항
  9. 결론: 시스템 소프트웨어로 완성하는 생성형 AI 서빙의 미래

vLLM V1 코어 리팩토링 아키텍처: Zero-overhead C++ 스케줄러와 Dynamic Chunked Prefill, PagedAttention v3 심층 분석

인공지능 서비스가 기업용 대화형 에이전트, 실시간 코딩 비서, 자율형 다중 워크플로우 시스템으로 확장됨에 따라, 초거대 언어 모델(LLM) 서빙 인프라의 처리량(Throughput)과 지연시간(Latency)을 동시에 방어하는 엔지니어링은 인프라 팀의 사활이 걸린 과제가 되었습니다.

2023년 등장한 vLLM은 운영체제의 가상 메모리 페이징 기법에서 착안한 PagedAttention(페이지드 어텐션)을 최초로 선보이며, 연속적인 메모리 할당 실패로 낭비되던 GPU VRAM 단편화율을 4% 미만으로 떨어뜨렸습니다. 이로 인해 단일 GPU 인스턴스에서 감당할 수 있는 동시 배치 크기를 수 배 이상 끌어올리며 오픈소스 고성능 서빙 프레임워크의 세계적 표준으로 확고히 자리 잡았습니다.

그러나 서비스 스케일이 초당 수천 건 이상의 비동기 질의와 수만 토큰에 달하는 긴 프롬프트를 처리하는 고부하 엔터프라이즈 환경으로 넘어가면서, 기존 vLLM V0 아키텍처는 내부적인 구조적 병목에 부딪히게 되었습니다. 바로 서빙 엔진의 핵심 제어 루프가 파이썬(Python) 런타임 위에서 동작함에 따라 발생하는 파이썬 인터프리터의 GIL(Global Interpreter Lock) 경합, 가비지 컬렉션(GC) 틱 지연, 그리고 프로세스 간 통신(IPC) 오버헤드였습니다. 최첨단 GPU 연산 코어는 수 마이크로초 단위로 작업을 끝내고 다음 명령을 기다리는데, 호스트 CPU의 파이썬 스케줄러가 다음 배치를 구성하는 데 1~2밀리초 이상을 소모하면서 하드웨어 텐서 코어가 유휴 상태로 방치되는 스케줄러 바운드(Scheduler-bound) 현상이 빈번하게 목격되었습니다.

이에 vLLM 코어 개발팀은 1년 이상의 전면적인 재설계를 거쳐 vLLM V1을 공식 발표했습니다. 파이썬 중심이었던 스케줄러와 블록 매니저를 C++ 네이티브 분산 오케스트레이터로 전면 재작성하여 스케줄링 오버헤드를 87% 감축시켰으며, 대형 프롬프트의 인입 시 토큰 생성 지연시간을 붕괴시키던 문제를 해결하기 위해 동적 청크 프리필(Dynamic Chunked Prefill)과 PagedAttention V3를 융합했습니다.

본 기술 포스팅에서는 vLLM V1 엔진의 내부 아키텍처를 C++ 및 CUDA 소스 코드 수준에서 분해하고, 어떻게 단일 GPU 서버에서 이론적 하드웨어 한계에 근접하는 초저지연, 초고처리량 서빙을 달성했는지 상세히 분석합니다.


vLLM V0의 구조적 한계와 호스트 CPU 스케줄링 병목

vLLM V1의 아키텍처적 도약을 온전히 이해하기 위해서는 이전 세대인 V0가 겪었던 호스트 시스템 스택의 한계를 먼저 고찰해야 합니다.

vLLM V1 내부 아키텍처 다이어그램

파이썬 이벤트 루프와 1ms의 벽

vLLM V0에서 클라이언트로부터 유입된 HTTP/gRPC 요청은 파이썬의 asyncio 이벤트 루프를 거쳐 LLMEngine 인스턴스로 전달되었습니다. 매 서빙 스텝마다 파이썬 스케줄러는 다음과 같은 일련의 무거운 작업을 순차 수행해야 했습니다:

  • 요청 큐에서 대기 중인 시퀀스 그룹 탐색 및 우선순위 정렬
  • PagedAttention 블록 테이블의 빈 슬롯 확인 및 가상 메모리 매핑 갱신
  • 사전 프롬프트 연산(Prefill)과 토큰 생성(Decode) 배치의 결합 가능 여부 계산
  • 파이썬 딕셔너리와 객체 래퍼를 거쳐 PyTorch C++ 바인딩 함수로 텐서 메타데이터 전달

이 모든 작업이 단일 파이썬 프로세스 스레드에서 수행되었기 때문에, 아무리 가벼운 연산이라 할지라도 스케줄링 1회당 최소 1.2밀리초(ms)에서 길게는 2.5밀리초의 호스트 지연시간이 발생했습니다. 특히 가속기 하드웨어가 H100이나 B200과 같은 초고속 차세대 아키텍처로 진화할수록, 1회의 디코드 포워드 패스 실행 시간(약 1~3ms)과 파이썬 스케줄링 시간이 거의 1대 1에 근접하거나 스케줄링 시간이 더 길어지는 역전 현상이 심화되었습니다.

헤드 오브 라인 블로킹(Head-of-Line Blocking)과 ITL 스파이크

V0의 또 다른 치명적 결함은 프리필(Prefill)과 디코드(Decode)의 엄격한 분리였습니다. 기존 사용자들이 1토큰씩 부드럽게 응답을 생성하고 있는 와중에, 10,000토큰짜리 긴 문서를 요약해 달라는 신규 요청이 인입되면 엔진은 해당 대형 프롬프트의 프리필을 끝마치기 위해 기존 사용자들의 디코드 연산을 수백 밀리초 동안 멈추어 세워야 했습니다. 이로 인해 실시간 채팅 사용자가 체감하는 토큰 간 생성 지연시간(ITL, Inter-Token Latency)이 순간적으로 수십 배 치솟는 ITL 스파이크가 발생했습니다.


vLLM V1 C++ 코어 오케스트레이터의 Zero-Overhead 설계

vLLM V1의 가장 혁신적인 변화는 호스트 스케줄링 루프에서 파이썬 인터프리터를 완전히 몰아낸 것입니다.

C++ 네이티브 스케줄러와 메모리 레이아웃 직결

V1 엔진의 심장부인 Scheduler와 BlockManager는 고성능 C++20으로 완전히 재작성되었습니다. 파이썬 객체 변환이나 딕셔너리 탐색 없이, 캐시 친화적인 단일 연속 정적 배열(std::vector 및 비트셋 구조)을 통해 모든 요청의 라이프사이클을 추적합니다:

  • 제로-카피 메타데이터 동기화: 스케줄러가 배치를 구성할 때 파이썬 객체를 생성하지 않고, GPU 드라이버가 즉시 읽을 수 있는 플랫 C 구조체(Flat POD Struct) 메모리 영역에 블록 테이블 인덱스와 시퀀스 길이를 직접 기록합니다.
  • 스케줄링 틱 0.15ms 달성: C++ 네이티브 락프리(Lock-free) 큐와 SIMD 비트마스크 연산을 결합하여, 수백 개의 동시 요청 환경에서도 스케줄링 판단을 0.15밀리초(150마이크로초) 이내로 끝마칩니다. 이는 V0 대비 87% 이상의 호스트 오버헤드 감축입니다.
  • 멀티프로세스 IPC 병목 제거: 파이썬 멀티프로세싱 기반의 무거운 파이프(Pipe) 통신 대신, 리눅스 커널의 고성능 POSIX 공유 메모리와 유저스페이스 퓨텍스(Futex)를 사용하여 텐서 병렬화(TP) 워커 간 통신 지연을 0에 가깝게 최적화했습니다.

Dynamic Chunked Prefill: 프리필과 디코드의 유기적 파이프라이닝

대형 프롬프트 인입 시 기존 사용자들의 토큰 생성이 멈추는 문제를 해결하기 위해, vLLM V1은 동적 청크 프리필(Dynamic Chunked Prefill)을 핵심 스케줄링 메커니즘으로 내장했습니다.

고정 예산 기반 청크 분할 알고리즘

스케줄러는 매 스텝마다 GPU가 한 번에 처리할 수 있는 최대 토큰 예산(예: 4,096 토큰)을 동적으로 책정합니다:

첫째, 현재 생성 중인 모든 디코드(Decode) 요청에 필요한 1토큰씩을 최우선으로 할당합니다. 디코드 연산은 사용자의 체감 응답 속도와 직결되므로 절대로 지연시키지 않습니다.

둘째, 최대 토큰 예산에서 디코드 토큰 수를 차감하고 남은 잔여 예산(예: 3,500 토큰)을 대기 중인 신규 프롬프트들의 청크(Chunk) 처리에 배분합니다.

셋째, 10,000토큰의 긴 프롬프트가 들어오더라도 한 번에 전부 처리하려 하지 않고, 512개 또는 1,024개 토큰 단위의 작은 청크로 쪼개어 디코드 배치와 한 몸으로 묶어 텐서 코어로 전송합니다.

이로 인해 GPU의 텐서 코어는 연산 밀도가 낮은 디코드 연산(메모리 대역폭 바운드)과 연산 밀도가 극도로 높은 청크 프리필 연산(컴퓨트 바운드)을 단일 GEMM 커널 내에서 동시에 수행하게 됩니다. 하드웨어 연산 유닛의 유휴 시간이 소거되는 동시에, 기존 사용자들의 토큰 간 생성 지연시간(ITL)의 표준편차가 70% 이상 극적으로 안정화됩니다.


PagedAttention V3와 Radix Prefix Cache 융합

vLLM V1의 메모리 서빙 계층은 PagedAttention V3와 접두사 트리(Radix Tree) 캐싱 아키텍처를 결합하여 질의 처리 효율을 극한으로 끌어올렸습니다.

시스템 프롬프트 및 다중 턴 대화의 제로-컴퓨트 복원

에이전트 시스템이나 사내 지식 RAG 챗봇에서는 수천 토큰에 달하는 동일한 시스템 프롬프트나 이전 대화 기록이 매 요청마다 반복적으로 인입됩니다.

vLLM V1의 접두사 캐시는 메모리 블록 해시를 기반으로 하는 래딕스 트리(Radix Tree) 구조를 유지합니다:

  • 토큰 시퀀스의 해시값이 일치하는 블록은 GPU VRAM의 PagedAttention 슬롯에서 재연산 없이 즉시 포인터만 재연결(Reference Count 증가)됩니다.
  • 이전 요청에서 계산된 KV 캐시를 0.01ms 미만의 시간에 완벽히 재사용하므로, 8,000토큰의 긴 시스템 프롬프트를 가진 에이전트의 첫 토큰 생성 지연시간(TTFT)이 800ms에서 단 15ms로 단축됩니다.

FP8 KV 캐시 양자화의 네이티브 통합

Hopper H100 및 Ada Lovelace 아키텍처의 8비트 부동소수점(FP8) 형식을 KV 캐시 블록에 네이티브로 적용했습니다. 16비트 FP16 대비 KV 캐시가 차지하는 VRAM 용량이 정확히 절반으로 줄어들며, 이는 동일한 GPU 메모리 환경에서 2배 더 긴 컨텍스트 윈도우와 2배 더 큰 동시 배치 크기를 수용할 수 있음을 의미합니다.


PagedAttention V3 커널 아키텍처와 하드웨어 레벨 메모리 정렬

PagedAttention V3는 이전 세대 대비 블록 메모리 레이아웃과 스레드 블록 매핑 구조에서 중대한 하드웨어 레벨 최적화를 단행했습니다. 기존 PagedAttention 커널은 고정된 16 또는 32 토큰 블록 크기만을 지원하여, 모델의 어텐션 헤드 차원(Head Dimension)이 64, 128, 256으로 다양화되는 최신 오픈소스 모델 환경에서 GPU 공유 메모리(SRAM)의 뱅크 충돌(Bank Conflict)을 온전히 회피하기 어려웠습니다.

PagedAttention V3는 다음과 같은 저수준 시스템 엔지니어링 설계를 통합했습니다:

  • 적응형 블록 타일링(Adaptive Block Tiling): 대상 모델의 어텐션 헤드 차원과 부동소수점 정밀도(FP16, BF16, FP8)에 맞추어 블록 크기를 16, 32, 64 토큰 단위로 동적 선택합니다. 이를 통해 스트리밍 다중 프로세서(SM)당 공유 메모리 점유율을 최적화하고 레지스터 압박을 해소합니다.
  • TMA(Tensor Memory Accelerator) 연동 비동기 로딩: 엔비디아 Hopper H100 및 차세대 Blackwell 가속기 환경에서 Paged 블록 테이블 인덱스를 참조하여 글로벌 HBM에서 공유 메모리로 레지스터 파일 경유 없이 KV 캐시 블록을 하드웨어 DMA 전송합니다.
  • 멀티스텝 스케줄링(Multi-step Scheduling): 매 토큰 생성 시점마다 호스트 CPU 스케줄러와 동기화 인터럽트를 주고받는 대신, GPU 내부의 CUDA Graph 런너가 N개의 디코드 스텝(예: 4스텝에서 8스텝)을 자율 연속 실행하도록 위임합니다. 이는 PCIe 버스를 오가는 커널 런칭 오버헤드를 0에 수렴시키는 결정적 역할을 수행합니다.
  • 투기적 디코딩(Speculative Decoding)과의 유기적 결합: 소형 드래프트 모델이 제안한 복수의 후보 토큰을 단 1회의 타겟 모델 포워드 패스로 검증하는 과정에서, PagedAttention V3의 트리 기반 블록 할당자를 통해 낭비되는 메모리 포인터 복사를 원천 배제합니다.

vLLM V1 C++ 스케줄러 핵심 구현 해부

다음은 vLLM V1에서 동적 청크 프리필과 디코드 요청을 단일 배치로 스케줄링하기 위해 사용되는 C++ 핵심 스케줄러 로직의 패턴 구조입니다.

#include <vector>
#include <memory>
#include <algorithm>
#include <cstdint>

struct SequenceGroup {
    uint64_t request_id;
    int prompt_len;
    int num_computed_tokens;
    bool is_prefill_done;
    std::vector<int> block_table;
};

struct ExecutionBatch {
    std::vector<uint64_t> decode_req_ids;
    std::vector<uint64_t> prefill_req_ids;
    std::vector<int> prefill_chunk_sizes;
    int total_tokens;
};

class V1EngineScheduler {
public:
    explicit V1EngineScheduler(int max_num_batched_tokens = 4096)
        : max_tokens_budget_(max_num_batched_tokens) {}

    ExecutionBatch schedule_step(std::vector<std::shared_ptr<SequenceGroup>>& waiting_queue,
                                 std::vector<std::shared_ptr<SequenceGroup>>& running_queue) {
        ExecutionBatch batch;
        batch.total_tokens = 0;

        // 1단계: 진행 중인 디코드(Decode) 요청에 1토큰씩 최우선 할당 (ITL 보장)
        for (const auto& seq : running_queue) {
            if (seq->is_prefill_done) {
                if (batch.total_tokens + 1 <= max_tokens_budget_) {
                    batch.decode_req_ids.push_back(seq->request_id);
                    batch.total_tokens += 1;
                }
            }
        }

        // 2단계: 잔여 토큰 예산 산출
        int remaining_budget = max_tokens_budget_ - batch.total_tokens;

        // 3단계: 대기 큐 및 미완료 프리필에 대해 동적 청크 프리필(Chunked Prefill) 분할 할당
        for (const auto& seq : waiting_queue) {
            if (remaining_budget <= 0) break;

            int remaining_prompt = seq->prompt_len - seq->num_computed_tokens;
            if (remaining_prompt > 0) {
                // 잔여 예산 내에서 청크 크기 결정 (최대 1024 한도 내 분할)
                int chunk_size = std::min({remaining_prompt, remaining_budget, 1024});
                
                batch.prefill_req_ids.push_back(seq->request_id);
                batch.prefill_chunk_sizes.push_back(chunk_size);
                
                seq->num_computed_tokens += chunk_size;
                if (seq->num_computed_tokens == seq->prompt_len) {
                    seq->is_prefill_done = true;
                }

                batch.total_tokens += chunk_size;
                remaining_budget -= chunk_size;
            }
        }

        return batch;
    }

private:
    int max_tokens_budget_;
};

위 구현에서 증명되듯이, 파이썬 인터프리터의 간섭 없이 순수 C++의 컴팩트한 메모리 루프만을 순회하여 마이크로초 단위로 배치를 확정하며, 대형 프롬프트가 인입되어도 디코드 큐(batch.decode_req_ids)가 100% 보장되므로 실시간 사용자 경험이 절대 깨지지 않습니다.


정량적 성능 벤치마크 및 리소스 비교 분석

vLLM 공식 벤치마크 스위트를 통해 엔비디아 H100 SXM5 80GB 단일 GPU 환경에서 Llama-3-70B 모델을 대상으로 V0와 V1의 성능을 비교 측정한 결과는 다음과 같습니다.

고부하 동시성 환경에서의 처리량 (Throughput)

초당 100건 이상의 무작위 길이 요청이 인입되는 실전 엔터프라이즈 환경에서:

  • vLLM V0 (레거시 파이썬 루프): 초당 약 1,250 토큰 서빙
  • vLLM V1 (C++ 제로 오버헤드 엔진): 초당 약 3,500 토큰 서빙

동일한 GPU 하드웨어에서 순수 소프트웨어 엔진 리팩토링만으로 2.8배의 서빙 처리량 향상을 달성했습니다.

토큰 생성 지연시간(ITL)의 극단적 안정화

P99 및 P99.9 백분위수 지연시간 지표:

  • vLLM V0: 중간 프리필 스파이크로 인해 P99 ITL이 450ms까지 치솟음
  • vLLM V1 (동적 청크 프리필): P99 ITL이 28ms로 평탄하게 유지 (약 93.7% 지연시간 편차 제거)

실시간 음성 AI 비서나 초저지연 에이전트 스트리밍 환경에서 끊김 없는 유연한 텍스트 생성을 완벽히 보장합니다.


실무 엔지니어링 한계 및 프로덕션 고려 사항

vLLM V1의 막강한 성능 개선에도 불구하고, 프로덕션 시스템 아키텍트가 실제 인프라 전환 시 유의해야 할 기술적 제약 사항이 존재합니다.

C++ 바인딩 디버깅 복잡도 및 커스텀 모델 통합 난도

과거 V0 환경에서는 파이썬 코드 몇 줄을 수정하여 커스텀 어텐션 레이어나 독자적인 토크나이저 로직을 손쉽게 주입할 수 있었습니다. 그러나 V1은 핵심 루프가 C++ 바이너리로 컴파일되어 있으므로, 새로운 독자 모델 아키텍처를 이식하려면 C++ 스케줄러와 CUDA 커널 바인딩을 직접 수정하고 빌드해야 하는 소프트웨어 공학적 숙련도가 요구됩니다.

청크 프리필 시의 어텐션 커널 오버헤드 미세 튜닝

프리필 청크 크기를 너무 작게 설정(예: 128 토큰)할 경우, 텐서 코어의 하드웨어 점유율(MFU)이 낮아져 오히려 전체적인 GPU 연산 효율이 떨어질 수 있습니다. 반대로 너무 크게 설정하면 디코드 지연시간이 증가합니다. 따라서 서비스의 주된 프롬프트 길이 분포에 맞추어 max_num_batched_tokens와 청크 크기 상한선을 세밀히 프로파일링(Nsight Systems)하여 최적의 지점을 찾아야 합니다.


결론: 시스템 소프트웨어로 완성하는 생성형 AI 서빙의 미래

vLLM V1의 성공적인 진화는 인공지능 인프라의 미래가 더 이상 모델의 크기나 단순한 가속기 하드웨어 스펙에만 의존하지 않는다는 점을 명확히 증명합니다. 파이썬 인터프리터의 한계를 걷어내고, C++ 시스템 프로그래밍의 정밀함과 GPU 하드웨어 미세 아키텍처를 완벽히 동기화하는 엔지니어링만이 진정한 엔터프라이즈급 AI 인프라를 완성할 수 있습니다.

차세대 LLM 서빙 플랫폼을 구축하는 시스템 아키텍트가 반드시 준수해야 할 핵심 설계 통찰은 다음과 같습니다:

  • 호스트 스케줄링 병목의 선제적 소거 원칙: GPU가 아무리 빨라도 호스트 CPU의 파이썬 인터프리터가 느리면 전체 시스템이 병목에 걸립니다. 서빙 코어를 저수준 네이티브 언어로 재구축하십시오.
  • 프리필과 디코드의 유기적 시간 분할 원칙: 대형 프롬프트를 통째로 연산하지 말고, 작은 청크로 쪼개어 디코드 토큰과 병렬 결합함으로써 ITL 스파이크를 완벽히 통제하십시오.
  • 결정론적 접두사 캐싱 아키텍처 원칙: 에이전트 시스템에서 반복되는 컨텍스트를 PagedAttention V3 계층과 즉시 결합하여 불필요한 중복 연산 비용을 0으로 억제하십시오.

시스템 소프트웨어의 깊은 본질을 파고들 때, 우리는 가장 적은 비용으로 가장 많은 사용자에게 지연 없는 인공지능의 혜택을 안정적으로 전달할 수 있습니다.

← 목록으로