AWS가 오픈소스 추론 엔진 vLLM에 KV 캐시를 옮기는 방식 두 가지를 기여했다고 밝혔다. 하나는 대화가 길어지는 다중 턴 에이전트에서 디코드 노드가 계산해 둔 KV를 프리필 노드로 되돌려 보내는 양방향 전송이고, 다른 하나는 프리필 노드가 계산을 마치는 대로 KV를 디코드 노드에 밀어 넣는 푸시 방식 전송이다.
AWS는 Amazon EC2 P5en 인스턴스 2대(프리필 1, 디코드 1)를 AWS Elastic Fabric Adapter(EFA)로 이은 환경에서, 테스트한 가장 긴 프롬프트 기준으로 양방향 전송이 첫 토큰 시간(TTFT)을 Qwen3-32B에서 최대 1.6배, zai-org/GLM-5-FP8에서 최대 3.3배 줄였다고 밝혔다. 푸시 방식은 Qwen3-32B에서 풀(pull) 방식과 견줘 TTFT가 최대 3배, 토큰당 출력 시간(TPOT)이 최대 30% 나아졌다고 한다. AWS는 결과가 워크로드와 설정에 따라 달라진다고 밝혔다.
양방향 전송은 vLLM v0.21.0 이상에서 NixlConnector를 쓰고, 프리필·디코드 서버 양쪽에 bidirectional_kv_xfer를 켠 뒤 KV 캐시 인식 라우터를 두면 쓸 수 있다. 푸시 방식은 프리필·디코드 서버를 NixlConnector 대신 NixlPushConnector로 설정하면 된다. 두 기능 모두 AWS Trainium 클러스터에서 먼저 만들어 검증한 뒤 특정 가속기에 묶이지 않는 기능으로 vLLM에 기여했고, 이번 수치는 GPU 클러스터에서 잰 것이다.1,2
프리필·디코드 분리와 KV 전송 부담
대규모 언어 모델 추론은 두 단계로 나뉜다. 프리필은 입력 프롬프트를 처리해 KV 캐시를 만들고, 디코드는 그 캐시로 토큰을 한 개씩 생성한다. 두 단계는 필요한 연산·메모리·확장 특성이 달라서, 서로 다른 엔진 인스턴스에서 돌리는 P-D 분리 구성이 쓰인다. 이렇게 하면 각 단계를 독립적으로 확장하고 최적화할 수 있어 자원 활용률, 처리량, 부하 시 지연이 개선될 수 있다. 다만 디코드가 시작되려면 프리필 인스턴스의 KV 캐시를 먼저 옮겨야 하고, KV 전송이 느리면 TTFT가 길어진다.
vLLM이 KV 블록을 옮기는 방법 중 하나가 NVIDIA의 NIXL(NVIDIA Inference Xfer Library) 커넥터다. 이 커넥터는 RDMA(원격 직접 메모리 접근)를 지원하는 네트워크를 쓰며, AWS EFA는 지원 인스턴스에서 GPUDirect RDMA와 Neuron Direct RDMA를 제공한다. 호스트 메모리를 거치지 않고 GPU나 Trainium 장치 메모리끼리 바로 전송할 수 있다.
기본 동작은 풀 방식이다. 프리필이 끝나면 라우터가 프리필 블록 ID 같은 출처 정보를 디코드 인스턴스에 전달하고, 디코드 인스턴스가 목적지 블록을 할당하고 전송을 준비한 뒤 NIXL READ로 KV를 가져온다. 이 과정이 프리필 뒤에 순서대로 일어나 첫 토큰까지 걸리는 경로가 길어진다.2
양방향 전송: 디코드의 KV를 프리필이 재사용
다중 턴 에이전트는 추론하고 도구를 호출하고 이전 결과를 반영하며 맥락을 쌓는다. 턴마다 클라이언트가 시스템 지시, 이전 프롬프트, 도구 결과, 모델 응답을 포함한 대화 이력을 다시 보내므로 길어진 맥락이 반복해서 처리된다. 기존 분리 서빙은 KV를 프리필에서 디코드로만 보내서 비효율이 두 가지 생긴다.
하나는 응답을 만든 뒤 디코드 노드에 프롬프트와 새로 생성한 토큰의 KV가 남는데, 다음 턴에서 프리필 노드가 이를 가져오지 못해 이전 응답 토큰의 KV를 다시 계산한다는 점이다. 다른 하나는 세션 상태를 디코드 노드만 유지해서 프리필 노드에서 활성 세션의 캐시가 밀려날 가능성이 커진다는 점이다. 캐시를 완전히 놓치면 프리필 노드가 시스템 지시, 이전 요청, 도구 결과, 모델 응답까지 대화 전체의 KV를 다시 계산해야 하고, 대화가 길수록 가속기 자원을 더 쓰며 TTFT가 늘어난다.
양방향 전송은 이후 턴에서 디코드 노드가 이미 계산한 KV를 프리필 노드로 돌려보내 공유 맥락의 재계산을 피하는 방식이다. 이를 위해 AWS는 NIXL KV 커넥터를 확장해 프리필 노드도 원격 KV 블록을 받을 수 있게 했다. 프리필 노드는 새 프롬프트 토큰의 KV를 직접 계산해 완전한 프롬프트 블록을 내줄 수 있지만, 디코드 노드는 완전한 KV를 만들 능력이나 효율이 부족해 이미 캐시한 블록만 내줄 수 있다. 그래서 두 노드는 각자 역할과 메타데이터 계산 로직을 유지하고, 실제 전송인 NIXL READ만 P→D와 D→P 양쪽에서 공통으로 쓴다.
- 디코드 노드가 생성이 끝난 뒤 재사용 가능한 KV 블록을 보관한다.
- 디코드 노드가 스트리밍 응답에 블록 메타데이터를 실어 보낸다.
- 라우터가 그 메타데이터를 저장해 다음 프리필 요청에 쓴다.
- 프리필 노드가 로컬 캐시 일치를 적용한 뒤 원격에서 재사용할 수 있는 KV를 확인한다.
- 재사용 가능한 토큰 수가 기준치 이상이면 비동기 수신을 대기열에 넣는다.
- 나머지 구간을 계산하기 전에 D→P NIXL READ로 KV를 받아 온다.
턴을 넘어 KV 재사용을 조율하려면 KV 캐시 인식 라우터가 필요하다. vLLM은 커넥터 쪽 지원만 포함하고, 이 글의 흐름을 구현한 예제 프록시는 vLLM GitHub에 있어 환경에 맞게 고쳐 쓸 수 있다. 라우터는 클라이언트가 주는 conversation_id를 디코드 노드의 kv_transfer_params에 연결하는 메모리 내 매핑을 가진 가벼운 상태 유지형 제어 계층이다. KV 텐서가 아닌 블록 위치 정보만 저장하고, 디코드 노드에 따로 묻지 않고 응답 스트림에서 메타데이터를 얻는다. 첫 턴에서는 캐시 조회가 빗나가 표준 P→D 흐름을 타고, 이후 턴에서는 conversation_id로 메타데이터를 꺼내 프리필이 디코드의 KV를 재사용하며, 생성이 끝나면 다음 턴을 위해 메타데이터를 갱신한다.
조정할 수 있는 설정은 두 가지다. 디코드 인스턴스는 보통 생성이 끝나면 요청의 블록을 바로 해제하지만, 양방향 모드에서는 decoder_kv_blocks_ttl(기본 480초) 동안 블록을 보관하고 위치와 만료 시각을 알린다. 이 시간 안에 다음 턴이 오면 프리필 노드가 KV를 재사용하고, 늦게 오면 일반 프리필로 돌아간다. TTL은 고정값이고 갱신되지 않으므로 턴 사이 예상 간격에 맞춰 KV 재사용과 가속기 메모리 사용량의 균형을 잡아야 한다. AWS는 하트비트로 갱신하는 임대 방식을 디코드 쪽에도 넣어 대화가 멈추면 곧바로 블록을 회수하는 방안을 다음 개선 과제로 꼽았다.
다른 하나는 kv_recompute_threshold로, 기본값이 64토큰이다. 재사용할 앞부분이 짧으면 인터커넥트와 조율 비용이 재계산 시간을 넘을 수 있어서, 계산할 토큰 수가 기준치보다 적으면 프리필 노드가 직접 재계산하고 기준치 이상이면 디코드 노드에서 KV를 가져온다. 모델 계산 시간, KV 크기, 인터커넥트 성능에 따라 값을 조정하면 된다.1
양방향 전송 측정 결과
AWS는 Qwen3-32B와 GLM-5-FP8을 P5en 1P1D 구성에서 시험했다. 프리필 노드의 로컬 캐시가 밀려났거나 라우터가 대화의 KV가 없는 다른 프리필 노드를 고른 상황을 흉내 내려고, 프리필 노드에서 --no-enable-prefix-caching으로 프리픽스 캐싱을 껐다.
기능을 끄면 프리필 인스턴스가 매 턴 늘어난 맥락 전체를 다시 계산해 TTFT가 가파르게 오른다. Qwen3-32B는 프롬프트 2k에서 158ms, 24k에서 778ms였고, GLM-5-FP8은 2k에서 500ms, 20k에서 2,334ms였다. 기능을 켜면 디코드 인스턴스에 남은 KV를 재사용해 같은 구간에서 Qwen3-32B는 122ms에서 460ms로 올랐고, GLM-5-FP8은 358ms에서 702ms로 올랐다. 가장 긴 프롬프트에서 Qwen3-32B는 약 1.6배, GLM-5-FP8은 최대 3.3배 낮은 값이다.1
| 모델 | 구간 | 끔 | 켬 |
|---|---|---|---|
| Qwen3-32B | 2k → 24k | 158ms → 778ms | 122ms → 460ms |
| GLM-5-FP8 | 2k → 20k | 500ms → 2,334ms | 358ms → 702ms |
KV를 옮기는 시간이 새로 들지만 줄어드는 계산량이 더 크다. 전송 시간은 Qwen3-32B가 약 30~130ms, GLM-5-FP8이 약 29~110ms이다. 그 결과 전체 프리필 시간은 켰을 때 Qwen3-32B 128~414ms, GLM-5-FP8 316~541ms로, 재계산만 하는 경우의 Qwen3-32B 153~744ms, GLM-5-FP8 500~2,331ms보다 훨씬 짧다. 더 큰 GLM-5-FP8은 토큰당 재계산 시간이 길어서 KV를 재사용하는 이득이 더 커, 절대값과 비율 모두에서 격차가 Qwen3-32B보다 크다.1
푸시 방식: 전송 준비를 프리필과 겹친다
푸시 커넥터는 프리필이 끝난 뒤에 하던 전송 조율과 준비를 첫 토큰 경로 밖으로 뺀다. 디코드 인스턴스가 프리필이 KV를 계산하는 동안 미리 목적지 블록을 등록하므로, 프리필 쪽 블록이 준비되는 순간 전송이 시작된다. 풀 방식의 ID 확인 왕복이 사라지는 셈이다. 전송 준비도 디코드가 아니라 프리필 쪽 백그라운드 스레드에서 한다. NIXL 디스크립터를 만들고 전송을 제출하는 이 작업이 디코드 인스턴스의 토큰 생성 구간을 차지하지 않으니, TTFT가 줄고 디코드 인스턴스의 출력 처리량이 오른다고 AWS는 설명했다.
프로토콜은 세 단계다. 먼저 디코드 쪽이 원격 프리필이 필요한 요청의 로컬 블록을 할당하면서 자신의 식별 정보와 방금 확보한 블록 위치를 담은 등록 정보를 같은 엔진 스텝 안에서 NIXL 알림으로 프리필 인스턴스에 보낸다. 프리필 쪽에서는 등록 정보와 프리필 완료가 어느 순서로 도착해도 처리한다. 등록이 먼저면 프리필이 끝날 때까지 기다리고, 프리필이 먼저 끝나면 등록이 올 때까지 블록을 붙잡아 두며, 나중에 일어난 쪽이 전송을 일으킨다. 요청은 ID로 짝지으며, 선점되거나 재시도된 요청도 맞게 연결한다.
짝이 맞으면 프리필 쪽이 필요하면 디코드 인스턴스와 연결을 만들고, NIXL WRITE로 KV 블록을 디코드의 등록 메모리에 직접 쓴다. 텐서 병렬 랭크별로 목적지를 지정하며, 양쪽의 내부 블록 배치와 블록 크기가 달라도 각자 전송 시점에 자기 물리 배치로 위치를 대응시킨다. 각 WRITE에는 완료 알림이 붙고, 디코드 쪽은 쓰기를 하는 프리필 랭크마다 하나씩 오는 알림이 모두 도착해야 KV를 받은 것으로 보고 디코드로 넘어간다.
백그라운드 스레드는 연결을 만들거나 재사용하고, KV 블록 ID를 메모리 디스크립터에 대응시키고, 이어진 블록을 더 큰 전송 구간으로 합쳐 NIXL WRITE를 제출한다. 프리필 메인 루프는 블록을 넘기고 곧바로 모델 실행으로 돌아간다. 두 방식은 같은 NIXL·EFA/RDMA 데이터 경로를 쓰지만, 풀은 메타데이터 중계와 디코드 쪽 준비를 프리필 뒤에 하고 푸시는 이를 프리필과 겹쳐 처리한다.
라우팅에서는 맞바꾸는 부분이 있다. 풀 방식은 프리필이 끝난 뒤 디코드 인스턴스를 고를 수 있어 부하를 보는 라우팅이나 서비스 품질 관리에 유연하다. 푸시는 목적지 준비를 겹치려고 디코드 인스턴스를 더 일찍 정한다. 대신 비슷한 부하에서는 프롬프트 KV와 목적지 등록이 갖춰지는 대로 전송이 시작되니 프리필 인스턴스가 KV 블록을 더 빨리 내놓을 수 있다.2
푸시 방식 측정 결과
AWS는 Qwen3-32B를 P5en 1P1D 구성에서 입력 길이 1k~16k, 초당 요청 수(QPS) 1~8로 바꿔 가며 시험했다. 출력은 128토큰이다. P→D 전송 성능만 가르려고 디코드 노드에서 --no-enable-prefix-caching으로 프리픽스 캐싱을 껐고, 매 요청마다 디코드 노드가 KV 캐시 전체를 프리필 노드에서 받도록 했다. 프롬프트가 겹치면 디코드 노드의 로컬 캐시가 전송을 건너뛰게 해 비교가 왜곡되기 때문이다.
부하가 낮고 프롬프트가 짧으면 두 방식의 TTFT는 거의 같다. QPS와 입력 길이가 커지면 풀 방식이 급격히 나빠져 8 QPS, 16k에서 약 1,744ms에 이르고, 푸시는 약 540ms로 3배가량 낮다. 풀 방식은 NIXL 디스크립터 게시를 디코드 워커의 엔진 루프 안에서 동기로 처리해 토큰 생성이 막히는데, 푸시는 이 작업을 백그라운드 스레드로 옮겼기 때문이라고 AWS는 설명했다.
TPOT도 같은 양상이다. 부하가 가벼울 때는 풀과 푸시 모두 5.6~5.8ms 안팎이다. 부하와 입력 길이가 오르면 풀은 4~8 QPS, 16k에서 약 10.4ms까지 올라가고 푸시는 약 7ms에 머문다.2
| 지표 | 풀 | 푸시 |
|---|---|---|
| TTFT (8 QPS) | 약 1,744ms | 약 540ms |
| TPOT (4~8 QPS) | 약 10.4ms | 약 7ms |
어떤 방식을 고를까
AWS는 디코드 노드를 일찍 정해도 되고 TTFT를 낮추는 것이 우선이면 푸시 커넥터를, 양방향 KV 전송이 필요하거나 부하를 보는 라우팅을 위해 프리필 뒤에 디코드 인스턴스를 정해야 하면 풀 커넥터를 권했다. vLLM은 두 방식을 모두 지원한다. 양방향 전송은 현재 풀 방식 쪽 기능이다.
두 시험 모두 1P1D에 프리픽스 캐싱을 끈 조건이며, AWS는 다른 지원 구성에서도 쓸 수 있지만 하드웨어, 모델, 워크로드, 네트워크에 따라 성능이 달라진다고 밝혔다. 재현 방법은 환경 설정, vLLM 프리필·디코드 서버 실행, 벤치마크 실행, 결과 수집을 담은 GitHub 안내서에 정리돼 있다.1,2
AWS는 푸시 방식의 백그라운드 NIXL 스레딩 모델을 풀 방식 커넥터에도 적용해 풀 모드에서도 같은 최적화를 얻는 방안을 검토 중이며, 이를 시험하는 풀 리퀘스트를 열었다고 밝혔다. 푸시 방식 글의 공동 저자 Nicolò Lucchesi는 Mistral의 Inference Foundation 팀을 이끄는 Research Engineer이자 vLLM 메인테이너다.2
두 기능이 겨냥하는 병목은 서로 다르다. 양방향 전송은 대화 이력이 쌓일수록 커지는 재계산 비용을 줄이고, 푸시는 요청이 몰릴 때 전송 준비가 디코드 루프를 막는 문제를 줄인다.1,2