Dasis AI Blog
← 목록으로

Databricks에서 오픈소스 LLM 추론 속도를 높이는 프롬프트 캐싱

· DASIS Team · #LLM #Databricks #프롬프트캐싱

Databricks에서 오픈소스 LLM 추론 속도를 높이는 프롬프트 캐싱

프롬프트 캐싱(Prompt Caching)을 Databricks 오픈소스 LLM 서빙에 적용하면 반복 추론의 TTFT(Time to First Token)를 최대 수 배 단축할 수 있다. 이 글은 Databricks 공식 블로그에서 발표한 프롬프트 캐싱 구현 방식을 기술적으로 분해하고, 실제 적용 시 고려해야 할 설정 포인트까지 다룬다.


왜 프롬프트 캐싱이 필요한가

LLM 추론에서 가장 많은 연산 비용이 드는 단계는 prefill이다. 입력 토큰 전체를 어텐션 레이어에 통과시키며 KV(Key-Value) 캐시를 생성하는 과정인데, 시스템 프롬프트나 긴 컨텍스트 문서가 반복 요청마다 동일하게 포함된다면 이 연산도 매번 반복된다.

RAG 파이프라인, 챗봇, 코드 어시스턴트처럼 고정된 시스템 프롬프트 또는 문서 컨텍스트를 수백~수천 번 재사용하는 워크로드에서 이 비용은 누적적으로 크다. 프롬프트 캐싱은 이 KV 캐시를 요청 간에 재사용해 prefill 연산을 건너뛰는 방식으로 문제를 해결한다.


프롬프트 캐싱이란

프롬프트 캐싱은 이전 요청에서 생성된 KV 캐시를 GPU 메모리(또는 CPU/디스크)에 보존하고, 동일한 프롬프트 접두사(prefix)가 다시 들어올 때 재계산 없이 해당 캐시를 그대로 사용하는 기술이다.

혼동하기 쉬운 개념을 먼저 정리한다.

개념 설명
KV 캐시 (세션 내) 단일 요청의 autoregressive 생성 중 이전 토큰의 K·V를 재사용. 모든 LLM에 기본 적용.
프롬프트 캐싱 (요청 간) 서로 다른 요청 사이에서 공통 prefix의 KV를 재사용. 추가 구현 필요.
시맨틱 캐싱 의미적으로 유사한 쿼리의 최종 응답(output)을 캐싱. 프롬프트 캐싱과 다름.

프롬프트 캐싱은 입력 단에서 작동하고, 시맨틱 캐싱은 출력 단에서 작동한다. 둘은 상호 보완적이다.


동작 원리

Prefix 매칭과 KV 캐시 재사용

프롬프트 캐싱의 핵심은 prefix 단위의 KV 캐시 저장과 조회다. 요청이 들어오면 서빙 엔진은 현재 입력의 토큰 시퀀스가 캐시된 prefix와 얼마나 겹치는지 확인한다. 매칭된 prefix 길이만큼 prefill 연산을 건너뛰고, 나머지 토큰만 새로 처리한다.

요청 A: [시스템 프롬프트 500토큰] + [사용자 입력 A]
         └─────────────────────┘
              KV 캐시 저장

요청 B: [시스템 프롬프트 500토큰] + [사용자 입력 B]
         └─────────────────────┘
              캐시 히트 → prefill 건너뜀
              사용자 입력 B만 새로 처리

vLLM의 Automatic Prefix Caching (APC)

Databricks는 오픈소스 서빙 엔진으로 vLLM을 활용한다. vLLM은 Automatic Prefix Caching(APC) 기능을 제공하며, 블록 단위(기본 16토큰)로 KV 캐시를 해시하고 저장한다. 동일한 블록 시퀀스가 재요청되면 자동으로 캐시에서 불러온다.

처리 흐름은 다음과 같다.

graph TD A[요청 수신] --> B{Prefix 블록 해시 조회} B -->|캐시 히트| C[캐시된 KV 블록 로드] B -->|캐시 미스| D[전체 prefill 실행] C --> E[미매칭 suffix만 prefill] D --> F[KV 캐시 저장] E --> G[Decode 단계 시작] F --> G

캐시 저장 계층

vLLM은 캐시 저장 계층을 세 단계로 구성한다.

  1. GPU HBM (L1): 가장 빠름. GPU 메모리 용량 한계 내에서 hot 블록 보관.
  2. CPU DRAM (L2): GPU 메모리가 가득 차면 LRU 정책으로 CPU로 오프로드. GPU 재적재 시 PCIe 전송 비용 발생.
  3. 디스크 (L3): 장기 보존이 필요한 prefix를 저장. 접근 지연이 가장 크므로 히트율이 충분히 높을 때만 효과적.

Databricks Model Serving 환경에서는 이 계층 구조가 자동으로 관리되며, 사용자는 별도 캐시 만료 로직을 직접 구현하지 않아도 된다.


성능 수치

Databricks 블로그에서 제시한 벤치마크 결과는 다음과 같다.

  • 캐시 히트 시 TTFT: 캐시 미스 대비 최대 수 배 단축
  • 처리량(throughput): 동일 하드웨어에서 캐시 미스 대비 높은 요청 처리 가능
  • 효과가 가장 큰 워크로드: 시스템 프롬프트 길이 1,000토큰 이상, 반복 요청 비율이 높은 경우

정확한 수치는 모델 크기, GPU 메모리, 배치 구성에 따라 달라지므로 직접 벤치마킹이 필요하다.


트레이드오프

효과적인 상황

  • 시스템 프롬프트, 문서 컨텍스트, Few-shot 예시 등 고정 prefix가 길고 반복되는 워크로드
  • RAG에서 동일 문서를 여러 사용자가 쿼리하는 패턴
  • 챗봇처럼 대화 히스토리가 누적되면서 공통 prefix가 길어지는 경우
  • 멀티턴 대화에서 이전 턴이 prefix로 재사용되는 구조

효과가 제한적인 상황

  • 요청마다 prefix가 달라지는 워크로드 (캐시 히트율 낮음)
  • 짧은 프롬프트 (100토큰 미만): 절약 연산량이 작아 오버헤드 대비 이득이 미미
  • GPU 메모리가 매우 타이트한 환경: 캐시 저장 자체가 OOM 위험 요인

메모리 vs 속도 트레이드오프

프롬프트 캐싱은 GPU 메모리를 KV 캐시 보관에 추가로 소비한다. 메모리 여유가 없으면 배치 크기를 줄이거나 캐시를 CPU로 내려야 하는데, CPU 오프로드 시에는 PCIe 전송 지연이 TTFT 개선 효과를 일부 상쇄한다. GPU 메모리 용량과 캐시 히트율을 함께 측정하면서 최적점을 찾아야 한다.


실전 설정

vLLM APC 활성화

vLLM 서버 시작 시 --enable-prefix-caching 플래그를 추가하는 것으로 APC를 켤 수 있다.

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Meta-Llama-3-8B-Instruct \
    --enable-prefix-caching \
    --gpu-memory-utilization 0.9

CPU 오프로드 설정

GPU 메모리가 부족하면 CPU 스왑을 활성화한다.

python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Meta-Llama-3-8B-Instruct \
    --enable-prefix-caching \
    --swap-space 16  # CPU 스왑 크기(GiB)

Prefix 설계 원칙

캐시 히트율을 높이려면 변하지 않는 내용을 프롬프트 앞쪽에 배치해야 한다. vLLM은 블록 단위 해시로 prefix를 매칭하기 때문에, 동일한 내용이더라도 위치가 달라지면 캐시 미스가 발생한다.

# 좋은 예: 고정 시스템 프롬프트 → 고정 문서 → 가변 사용자 입력
messages = [
    {"role": "system", "content": FIXED_SYSTEM_PROMPT},   # 캐시됨
    {"role": "user",   "content": FIXED_DOCUMENT},         # 캐시됨
    {"role": "user",   "content": user_query},             # 매 요청마다 다름
]

# 나쁜 예: 가변 내용이 앞에 오면 뒤의 고정 내용도 캐시 미스
messages = [
    {"role": "user", "content": user_query},               # 가변 → 캐시 불가
    {"role": "system", "content": FIXED_SYSTEM_PROMPT},   # 앞이 달라서 미스
]

캐시 히트율 모니터링

vLLM은 /metrics 엔드포인트에서 Prometheus 형식의 메트릭을 제공한다. 아래 두 지표를 함께 추적하면 캐시 효과를 정량적으로 확인할 수 있다.

vllm:gpu_prefix_cache_hit_rate   # GPU 레벨 히트율
vllm:cpu_prefix_cache_hit_rate   # CPU 레벨 히트율

히트율이 50% 미만이면 prefix 설계를 재검토하거나 워크로드가 캐싱에 적합한지 다시 평가한다.

Databricks Model Serving에서의 적용

Databricks Model Serving에서 vLLM 기반 커스텀 모델을 배포할 때는 서빙 설정 파일에 vLLM 실행 인수를 전달하는 방식으로 APC를 활성화한다.

from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

# vLLM 서빙 엔진 인수를 extra_pip_requirements 또는
# served_entities의 environment_vars를 통해 전달
# 정확한 API는 Databricks 버전에 맞게 확인할 것

요약

프롬프트 캐싱은 KV 캐시를 요청 간에 재사용해 prefill 연산 비용을 줄이는 기술로, 고정 prefix가 길고 반복 요청이 잦은 워크로드에서 TTFT를 크게 단축한다. vLLM의 APC 기능은 --enable-prefix-caching 플래그 하나로 활성화되며, Databricks 환경에서 오픈소스 모델 서빙에 바로 적용할 수 있다. 효과를 극대화하려면 프롬프트 구조를 "고정 내용 앞, 가변 내용 뒤"로 설계하고 캐시 히트율을 Prometheus 메트릭으로 지속 모니터링해야 한다. GPU 메모리 여유가 충분한지 함께 검토하지 않으면 OOM이나 성능 역전이 발생할 수 있다.


더 읽을 자료