08. KV 전송과 계층화 — KV는 누구 것이고 어디에 얼마나 머무는가
이 장의 핵심 질문
- KV 캐시를 "옮긴다·저장한다"고 할 때, 그 KV의 소유자(ownership)·수명(lifetime)·계층(tier) 을 왜 분리해 봐야 하는가?
- backpressure(백프레셔)는 무엇을 막는 장치이고, 없으면 무슨 일이 생기는가?
- "KV를 전송할 것인가, 다시 계산할 것인가"는 어떤 조건에서 어느 쪽이 유리한가?
앞 장과의 연결 — 07장에서 PD 분리가 KV를 "네트워크 페이로드"로 만들었고, 일방향(P→D) 프로토콜 탓에 멀티턴에서 KV 재사용이 어렵다고 했다. 이 장은 그 KV를 어떻게 옮기고, 어디에 얼마나 두며, 언제 버리거나 재계산하는지를 다룬다.
먼저: KV를 "데이터 자산"으로 보기
선수 과정 ②에서 KV 캐시는 "decode를 빠르게 하려고 이미 계산한 key·value를 저장해 둔 것"이었다. 분산 서빙에서는 KV를 관리해야 할 데이터 자산으로 봐야 한다. 자산에는 세 가지 질문이 따른다: 누구 것인가(ownership), 언제까지 유효한가(lifetime), 어디에 두는가(tier). 이 셋을 섞으면 KV 관리가 뒤죽박죽이 된다.
일상 비유: 도서관의 책(KV)을 생각하자. 어느 분관 소유인가(ownership), 대출 기한이 언제까지인가(lifetime), 열람실·서고·외부 창고 중 어디에 두는가(tier)는 별개의 결정이다. 그리고 반납 창구가 밀리면 새 반납을 잠시 막아야 한다(backpressure).
세 축으로 KV 분리하기
1) ownership — KV는 누구 것인가
분산 서빙에서 KV는 여러 컴포넌트를 오간다. 어느 시점에 어느 노드가 그 KV의 주인인지가 명확해야 한다.
- PD 분리(07장)에서 KV는 P가 생산하고 D가 소비한다(일방향). 생산 시점엔 P가, 전송 후엔 D가 주인이다.
- 외부 KV 계층을 두면, KV의 주인이 특정 엔진 인스턴스가 아니라 공유 풀이 될 수 있다. 그러면 여러 요청·인스턴스가 같은 KV를 참조할 수 있다(예: 공통 프리픽스 재사용).
ownership이 불명확하면 같은 KV를 두 곳이 관리하거나(중복), 아무도 관리 안 해 유실되는(누수) 문제가 생긴다.
2) lifetime — KV는 언제까지 유효한가
KV는 무한정 두지 않는다. 언제 만들어져 언제 버려지는지가 lifetime이다.
- 요청 단위 — 한 요청이 끝나면 그 KV는 보통 폐기된다.
- 세션/멀티턴 — 대화가 이어지면 KV를 남겨 다음 턴에서 재사용하고 싶다(하지만 07장의 일방향 문제로 쉽지 않다).
- 프리픽스 공유 — 여러 요청이 공유하는 공통 앞부분(시스템 프롬프트 등)의 KV는 더 오래 살려 재사용한다(prefix caching).
lifetime이 길수록 재사용 이득이 크지만, 그만큼 메모리를 오래 점유한다. 이 절충이 tier 결정으로 이어진다.
3) tier — KV는 어디에 두는가 (계층화)
KV를 담을 저장 계층은 하나가 아니다. 빠르지만 작은 곳부터 느리지만 큰 곳까지 계층(tier)을 이룬다.
| tier | 특성 | 역할 |
|---|---|---|
| GPU 메모리(HBM) | 가장 빠름, 가장 작고 비쌈 | 지금 당장 decode 중인 KV |
| CPU 메모리(호스트 RAM) | 중간 | HBM에서 밀려난, 곧 쓸 수 있는 KV |
| 원격/외부 저장(다른 노드·스토리지) | 느림, 큼 | 오래 살릴 KV, 공유 풀, 프리픽스 캐시 |
KV 계층화(KV tiering) 는 이 계층 사이로 KV를 올리고 내리며(promote/evict), "지금 쓸 것은 빠른 곳에, 나중 것은 느린 곳에" 배치하는 것이다. 운영체제의 메모리 계층·캐시 개념과 같은 발상이다.
flowchart TB
subgraph TIERS["KV tier — 빠름↔큼 절충"]
HBM["GPU HBM<br/>지금 decode 중"]
CPU["CPU RAM<br/>곧 쓸 KV"]
EXT["원격/외부 저장<br/>공유·프리픽스·장기"]
end
HBM -->|"evict (밀어냄)"| CPU
CPU -->|"promote (올림)"| HBM
CPU -->|"오래 살릴 것"| EXT
EXT -->|"재사용 시"| CPU
classDef fast fill:#e9d8fd,stroke:#7c3aed,color:#000
classDef mid fill:#cfe2ff,stroke:#2563eb,color:#000
classDef slow fill:#c4f1f4,stroke:#0891b2,color:#000
class HBM fast
class CPU mid
class EXT slow
📌 핵심 — ownership·lifetime·tier는 별개의 결정이다. "KV를 외부에 둔다"는 tier 결정이지 ownership 결정이 아니다. "멀티턴에 재사용한다"는 lifetime 결정이지 tier 결정이 아니다. 이 셋을 분리해 말할 수 있으면 KV 관리 설계를 정확히 읽을 수 있다.
backpressure — 밀리면 막아야 한다
backpressure(백프레셔) 는 하류(downstream)가 처리 속도를 못 따라갈 때, 상류(upstream)에게 "잠깐 멈춰라/천천히 보내라"는 신호를 거꾸로 보내는 흐름 제어 장치다.
KV 맥락에서 왜 필요한가:
- P가 KV를 D로 계속 보내는데 D가 소비를 못 따라가면, 전송 큐와 D의 메모리가 넘친다.
- KV tier가 가득 차면, 새 KV를 받을 자리가 없다.
backpressure는 이럴 때 P의 새 prefill 수용을 늦추거나 멈춰서 시스템 전체가 무너지는 것을 막는다. 상수도에서 하류 수조가 차면 상류 밸브를 잠그는 것과 같다.
⚠️ 경계 혼동 주의 — backpressure는 성능 기능이 아니라 안정성 기능 — backpressure를 "느리게 만드는 것"으로 오해하기 쉽지만, 그 목적은 과부하 시 붕괴(cascading failure)를 막는 것이다. backpressure가 없으면 부하가 임계점을 넘는 순간 큐·메모리가 폭발해 시스템 전체가 죽는다(10장의 saturation과 직결). "왜 일부러 요청을 막나"가 아니라 "막지 않으면 전부 잃는다"로 읽어야 한다.
전송할 것인가, 재계산할 것인가
PD 분리에서 D가 KV를 얻는 방법은 하나가 아니다. 근본적 절충이 있다.
- 전송(transfer) — P가 만든 KV를 네트워크로 D에 보낸다. 장점: 재계산 안 함. 단점: 네트워크 대역폭·전송 지연(07장의 임계 경로 비용).
- 재계산(recompute) — KV를 보내는 대신 D가 프롬프트를 다시 prefill해 KV를 새로 만든다. 장점: 네트워크 전송 없음. 단점: 연산 중복(같은 prefill을 두 번).
어느 쪽이 유리한가는 조건에 달렸다:
- 긴 프롬프트 → KV가 커서 전송 비용이 크지만, 재계산도 그만큼 비싸다. 네트워크가 빠르면 전송이, 느리면 재계산이 유리할 수 있다.
- 네트워크가 느릴 때 → 재계산이 상대적으로 유리해진다.
- 연산 여유가 없을 때(D가 바쁨) → 전송이 유리하다(D의 연산을 아낌).
또한 KV 전송량 자체를 줄이는 접근도 있다: KV의 정밀도를 토큰별로 다르게(중요 토큰은 고정밀, 덜 중요한 토큰은 저정밀·양자화) 보내 전송량을 줄이는 연구가 활발하다(선수 과정 ①의 정밀도, ②의 양자화 개념이 여기서 KV 전송에 적용된다).
⚖️ 절충 — 전송 vs 재계산 vs 전송량 축소 — 세 접근은 각각 다른 자원을 쓴다: 전송은 네트워크, 재계산은 연산, 전송량 축소(양자화)는 품질을 일부 내주고 네트워크를 아낀다. "무엇이 최선"은 네트워크 대역폭·연산 여유·품질 허용치·프롬프트 길이에 달렸고 일반해가 없다(조건 의존).
🔬 증거 읽기 — KV 전송 최적화 주장 검증 — "KV 전송으로 TTFT를 M% 줄였다" 또는 "KV 양자화로 전송량 N% 감소"라는 주장을 만나면 확인하라:
- (a) 어떤 모델·프롬프트 길이인가 — KV 양자화 내성은 모델 의존이 크다(어떤 모델은 저정밀 KV에서 급격히 품질이 무너지고, 어떤 모델은 견딘다).
- (b) 품질 손실을 함께 보고했나 — 전송량만 줄이고 품질 저하를 숨긴 주장인지.
- (c) 어떤 네트워크·tier 구성인가 — 전송 이득은 대역폭에 강하게 의존.
전송량·TTFT 이득과 품질은 같은 조건에서 함께 봐야 하며, 모델이 다르면 옮길 수 없다(15장).
외부 KV 계층 — 07장 일방향 문제의 완화책
07장에서 PD 분리의 일방향 프로토콜 탓에 멀티턴 KV 재사용이 어렵다고 했다. 이를 완화하는 대표 접근이 외부/공유 KV 계층이다: 엔진 인스턴스 밖에 KV를 두는 별도 계층을 만들어, 여러 요청·턴·인스턴스가 그 KV를 참조·재사용하게 한다.
이때 앞의 세 축이 다시 등장한다: 외부 계층의 KV는 ownership이 공유 풀로 이동하고, lifetime이 요청을 넘어 길어지며, tier로서 원격 저장에 놓인다. 그리고 이 계층이 가득 차면 backpressure로 유입을 조절한다. 즉 이 장의 네 개념이 외부 KV 계층 하나에 모두 작동한다.
⚠️ 경계 혼동 주의 — KV 계층(데이터 관리)과 서빙 계층(제어 경로)은 다르다 — "KV 계층화"는 KV라는 데이터를 저장 계층에 배치하는 것이고, 12장의 "서빙 계층(Dynamo·llm-d)"은 요청 제어·경로를 담당하는 소프트웨어 층이다. 둘 다 "layer/계층"이라 불리지만 다루는 대상이 다르다. 층을 섞지 말라.
이 장에서 배운 것
- KV를 데이터 자산으로 보면 세 질문이 따른다: ownership(누구 것), lifetime(언제까지), tier(어디에). 이 셋은 별개의 결정이다.
- KV 계층화(tiering) 는 HBM→CPU→원격 계층 사이로 KV를 올리고 내려, "지금 쓸 것은 빠른 곳, 나중 것은 느린 곳"에 둔다.
- backpressure는 하류가 밀릴 때 상류를 멈추는 안정성 장치다. 성능을 깎는 게 아니라 과부하 붕괴를 막는다.
- KV를 얻는 법은 전송 vs 재계산 vs 전송량 축소(양자화) 로 갈리며, 각각 네트워크·연산·품질을 쓴다. 최적은 조건 의존이다.
- KV 양자화 내성은 모델 의존이 크다. 전송량 이득은 품질 손실과 함께 봐야 한다.
- 외부/공유 KV 계층은 07장 일방향 문제의 완화책이며, 이 장의 네 개념이 모두 작동한다.
🔎 이 장의 '지지하지 않는 결론' + 'unknown으로 남겨야 할 것'
- 지지하지 않는 결론 — "KV는 항상 전송하는 게 낫다"거나 "KV 양자화는 항상 안전하다"는 지지되지 않는다. 전송/재계산의 우열은 네트워크·연산 조건에, 양자화 안전성은 모델에 달렸다.
- unknown으로 남길 것 — 특정 배포의 KV tier 구성·전송 대역폭·재사용률·양자화 정책은 공개되지 않으면
unknown. "이 모델은 INT4 KV를 견딘다/못 견딘다" 같은 주장은 그 모델·조건의 측정 없이는 일반화하지 않는다.
✍️ 확인 문제
- "KV를 외부 공유 계층에 둔다"는 결정을 ownership·lifetime·tier 세 축으로 분해하면 각각 무엇이 바뀌는가? 이 셋을 뭉쳐 "그냥 KV를 밖에 저장한다"고만 말하면 무엇을 놓치는가?
- (안정성 유형) backpressure를 끄면 부하가 임계점을 넘는 순간 무슨 일이 벌어지는가? "요청을 일부러 막는 것"이 왜 전체를 지키는 것인지, 10장의 saturation 개념을 예고하며 설명하라.
- (조건/모델 의존 유형) 어떤 팀이 "KV를 INT4로 양자화해 전송량을 4분의 1로 줄였다"고 자랑한다. 이 주장을 다른 모델·다른 배포에 그대로 적용하면 안 되는 이유를 "KV 양자화 내성의 모델 의존성"과 "품질 손실을 함께 봐야 함"으로 답하라.
다음 장에서는 요청이 여러 복제본·풀로 흩어진 시스템에서 "어디로 보낼지"를 정하는 세 개의 제어 루프 — 라우팅·로드밸런싱·오토스케일링 — 을 입력·출력·시간축으로 분리한다.
다음 → 09. Routing·load balancing·autoscaling — 세 제어 루프를 섞지 않기