본문 바로가기

AI 개발

Cloudflare가 LLM 추론을 두 단계로 쪼갠 이유 — Workers AI 인프라 완전 해부

반응형

LLM 서빙의 핵심 병목은 오랫동안 알려져 있었다. GPU 한 대에서 입력 처리와 토큰 생성을 같이 돌리면 두 작업이 서로 발목을 잡는다. Cloudflare는 이 문제를 Prefill-Decode 분리 아키텍처와 Rust로 만든 자체 추론 엔진 Infire로 풀었다. 결과는 인터토큰 레이턴시 3배 개선, vLLM 대비 처리량 7% 이상 향상. 에이전트 워크플로우 전용으로 설계된 이 인프라의 내부를 완전히 뜯어봤다.


핵심 요약

→ Cloudflare Workers AI는 에이전트 워크플로우를 1순위 워크로드로 설계 — 대규모 시스템 프롬프트·툴 정의·MCP 컨텍스트가 누적되는 입력 토큰 처리 속도가 핵심
→ PD Disaggregation: 입력 처리(Prefill)와 토큰 생성(Decode)을 별도 서버로 분리 — 각 단계에 최적화된 하드웨어와 스케일링 독립 적용 가능
→ Infire — Rust로 작성한 자체 추론 엔진: 멀티 GPU 지원, vLLM 대비 GPU 메모리 오버헤드 감소, 콜드 스타트 20초 이하, 토큰/초 처리량 최대 20% 향상
→ 구성 튜닝 후 성과: P90 TTFT(첫 토큰 시간) 낙폭, 인터토큰 레이턴시 3배 개선
→ x-session-affinity 헤더 — 세션 어피니티로 캐시된 KV를 같은 리전에서 재사용, 에이전트 반복 호출 비용 대폭 절감
→ Speculative Decoding에 NVIDIA EAGLE-3 드래프트 모델 활용 — Kimi K2.5 같은 초대형 모델에서 토큰/초 처리량 추가 향상
→ 개발자 관점 핵심: 에이전트 루프 설계 시 x-session-affinity와 프롬프트 캐싱을 활용하면 Workers AI 비용을 크게 줄일 수 있음


1. LLM 추론의 두 단계 — 왜 쪼개야 하나

LLM 요청 처리에는 두 단계가 있다. Prefill은 프롬프트 토큰을 처리해 KV 캐시를 채우고, Decode는 출력 토큰을 하나씩 생성한다. Prefill은 컴퓨팅 집약적이고, Decode는 메모리 대역폭 집약적이다.

# LLM 추론 두 단계의 특성 차이

Prefill (입력 처리)
├── 작업: 모든 입력 토큰을 병렬 처리 → KV Cache 생성
├── 병목: GPU 연산 코어 (Compute-bound)
├── 특성: 배치 처리 효율적, 행렬 곱셈 집약
├── 결정 지표: TTFT (Time To First Token)
└── 최적 하드웨어: 연산 코어 많은 GPU (H100 SXM)

Decode (토큰 생성)
├── 작업: 이전 토큰 참조하며 다음 토큰 하나씩 생성
├── 병목: GPU 메모리 대역폭 (Memory-bound)
├── 특성: 순차적, KV Cache를 매 스텝 읽어야 함
├── 결정 지표: ITL (Inter-Token Latency)
└── 최적 하드웨어: 메모리 대역폭 높은 GPU (H100 NVL)
# 같은 GPU에서 두 단계를 같이 돌리면 생기는 문제

[단일 GPU 서버]
Prefill 실행 중 → GPU 코어 100% 사용, 메모리 대역폭 유휴
Decode 실행 중 → 메모리 대역폭 100% 사용, GPU 코어 유휴

문제:
→ Prefill이 끝나야 Decode 시작 가능 (서로 블로킹)
→ 각 단계가 상대방 단계에 최적화된 자원을 낭비
→ 신규 요청의 Prefill이 기존 Decode를 방해 (배치 경쟁)
→ 전체 GPU 활용률이 이론적 최대치의 절반도 안 됨

2. PD Disaggregation — Cloudflare의 해법

PD Disaggregation에서는 각 단계별로 별도의 추론 서버를 운영한다. 먼저 요청이 Prefill 단계로 전송돼 Prefill을 수행하고 KV 캐시에 저장한다. 그 다음 같은 요청이 Decode 서버로 전송되는데, Prefill 서버에서 KV 캐시를 전송하는 방법과 함께 Decode를 시작하는 정보가 포함된다.

# PD Disaggregation 아키텍처

[클라이언트 요청]
       ↓
[토큰 인식 로드 밸런서]  ← Cloudflare 자체 개발
  - 인플라이트 토큰 수 추적
  - Prefill/Decode 풀에 부하 균등 분배
  - 스트리밍 SSE 응답 재작성
       ↓              ↓
[Prefill 서버 풀]    [Decode 서버 풀]
 - 컴퓨팅 최적화     - 메모리 최적화
 - KV Cache 생성     - 토큰 스트리밍
       ↓              ↑
   KV Cache 전송 ────┘
   (RDMA 또는 고속 네트워크)

# 각 풀 독립 스케일링
입력 헤비 워크로드 (RAG, 에이전트)
  → Prefill 서버 3× 스케일 업
  → Decode 서버 1× 유지

출력 헤비 워크로드 (소설 생성)
  → Prefill 서버 1× 유지
  → Decode 서버 3× 스케일 업

3. Infire — Rust로 만든 자체 추론 엔진

Infire는 Cloudflare의 분산 글로벌 네트워크라는 고유한 과제를 지원하도록 설계된 Rust로 작성한 LLM 추론 엔진이다. GPU, 네트워크 I/O, 메모리 활용률을 최대화하는 다양한 기술을 적용해 더 적은 GPU로 더 많은 요청을 처리하고 CPU 오버헤드를 크게 낮춘다.

# Infire 3단 구성

[OpenAI 호환 HTTP 서버]
  - OpenAI API 형식 그대로 사용 가능
  - 스트리밍 SSE 지원

[Batcher (배치 스케줄러)]
  - Continuous Batching: 배치 단위 아닌 이터레이션 단위 스케줄링
  - Chunked Prefill: 긴 프롬프트를 청크로 쪼개 Decode와 인터리빙
  - GEMM 크기 최대화로 Tensor Core 활용률 향상

[Inference Engine]
  - JIT CUDA 커널 컴파일 (PTX): 모델·GPU 조합에 최적화
  - Fine-grained CUDA Graphs: 반복 실행 경로 오버헤드 제거
  - Paged KV Cache: 컨텍스트 길이에 따른 메모리 동적 할당
# Infire 성능 수치

vLLM 0.10.0 대비 처리량:  +7% (무부하 H100 NVL 기준)
고부하 인프라 기준:         더 큰 폭 개선
콜드 스타트 시간:          20초 이하 (초대형 모델 포함)
토큰/초 처리량:            하드웨어 대비 최대 +20%
메모리 오버헤드:           vLLM 대비 감소 → 더 큰 컨텍스트 윈도우 가능

4. Speculative Decoding — EAGLE-3 적용

Cloudflare는 Kimi K2.5에 NVIDIA의 EAGLE-3 드래프트 모델을 활용한 Speculative Decoding을 적용해 고품질 추론을 유지하면서 토큰/초 처리량을 향상시켰다.

# Speculative Decoding 작동 원리

기존 방식
메인 모델이 토큰을 하나씩 생성 → 순차적 병목

Speculative Decoding
  ↓
[소형 드래프트 모델 (EAGLE-3)]
  → 다음 N개 토큰을 빠르게 추측 (병렬)
  ↓
[메인 모델 (Kimi K2.5)]
  → 드래프트 토큰 검증 (병렬로 한 번에)
  → 맞으면 채택, 틀리면 드래프트 이후 토큰 재생성
  ↓
결과: 메인 모델 호출 횟수 감소 → 실효 토큰/초 향상

# 왜 EAGLE-3인가
→ 드래프트 모델이 메인 모델의 내부 표현(hidden states)을 활용
→ 일반 소형 모델보다 채택률이 훨씬 높음
→ Kimi K2.5 같은 1조 파라미터급 모델에서 효과 극대화

5. 에이전트 워크플로우 최적화 — x-session-affinity

에이전트 애플리케이션처럼 긴 컨텍스트를 다루는 경우 효율적인 프롬프트 캐싱이 필수 — x-session-affinity 헤더로 미리 계산된 입력 텐서가 있는 리전으로 요청을 라우팅해 처리량을 향상시킨다.

# Workers AI 에이전트 루프에서 x-session-affinity 활용

import httpx

# 첫 번째 요청 — 세션 초기화
response = httpx.post(
    "https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/kimi/k2.5",
    headers={
        "Authorization": f"Bearer {CF_API_TOKEN}",
        "Content-Type": "application/json",
        # x-session-affinity 헤더 없이 첫 요청
    },
    json={
        "messages": [
            {"role": "system", "content": LARGE_SYSTEM_PROMPT},  # 수천 토큰
            {"role": "user", "content": "첫 번째 질문"}
        ]
    }
)

# 응답 헤더에서 세션 ID 추출
session_id = response.headers.get("cf-session-affinity")

# 이후 요청 — 같은 세션 ID로 KV 캐시 재사용
for follow_up in follow_up_questions:
    response = httpx.post(
        "https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/kimi/k2.5",
        headers={
            "Authorization": f"Bearer {CF_API_TOKEN}",
            "Content-Type": "application/json",
            "x-session-affinity": session_id,  # 캐시된 KV 재사용
            # → 시스템 프롬프트 Prefill 비용 절감
            # → Cloudflare가 캐시 재사용 시 할인 적용
        },
        json={
            "messages": [
                {"role": "system", "content": LARGE_SYSTEM_PROMPT},
                # 이전 대화 히스토리 포함...
                {"role": "user", "content": follow_up}
            ]
        }
    )
# x-session-affinity 효과

미사용 시
→ 매 요청마다 대형 시스템 프롬프트 전체를 Prefill
→ TTFT 높음, 비용 전액 청구

사용 시
→ 동일 리전에 KV 캐시 있으면 Prefill 스킵
→ TTFT 대폭 감소
→ Cloudflare가 캐시 히트 시 할인 적용 (OpenCode 등에서 검증)

6. 초대형 모델 서빙 — Kimi K2.5 사례

Kimi K2.5 같은 대형 언어 모델은 1조 파라미터가 넘고, 이는 약 560GB의 모델 웨이트에 해당한다. 일반적인 H100은 약 80GB의 VRAM을 가지며, 실행하려면 GPU 메모리에 모델 웨이트를 로드해야 한다.

# 1조 파라미터 모델 서빙 과제

모델 크기: ~560GB (Kimi K2.5 기준)
H100 VRAM: 80GB × 7대 = 560GB → 딱 맞음 (여유 없음)

→ 텐서 병렬화 (Tensor Parallelism): 모델 레이어를 여러 GPU에 분산
→ 전문가 병렬화 (Expert Parallelism): MoE 모델의 전문가 레이어 분산
→ 파이프라인 병렬화: 레이어 그룹을 순차 GPU에 할당

# Infire의 멀티 GPU 지원 (2026년 추가)
→ 세 가지 병렬화 모드 모두 지원
→ GPU 메모리 오버헤드 감소로 기존에 불가능했던 하드웨어에서도 실행 가능
→ 콜드 스타트 20초 이하 (드라이브 속도가 유일한 병목)

7. 아키텍처 선택 가이드 — 언제 뭘 쓰나

# 워크로드별 최적 설정

에이전트 워크플로우 (Workers AI 최적화 타겟)
├── 특성: 입력 토큰 매우 많음 (시스템 프롬프트 + 히스토리 누적)
├── 최적: PD Disaggregation + x-session-affinity
└── 이유: Prefill 서버 집중 스케일, 캐시 재사용으로 TTFT 최소화

RAG 파이프라인
├── 특성: 긴 컨텍스트 입력, 짧은 출력
├── 최적: Prefill 서버 더 많이 + 프롬프트 캐싱
└── 이유: 문서 청크 Prefill 비용이 전체의 80% 이상

콘텐츠 생성 (소설·보고서)
├── 특성: 짧은 입력, 매우 긴 출력
├── 최적: Decode 서버 더 많이 + Speculative Decoding
└── 이유: 토큰 생성 속도가 UX의 전부

실시간 챗봇
├── 특성: 짧은 입력, 짧은 출력, 낮은 레이턴시 요구
├── 최적: Chunked Prefill (단일 노드) + Continuous Batching
└── 이유: PD 분리의 KV 전송 네트워크 레이턴시가 오히려 불리

# PD Disaggregation이 불리한 경우
→ 프롬프트 512 토큰 미만 (Prefill 자체가 빠름)
→ 동시 요청 10개 미만 (배칭 효과 없음)
→ TTFT가 최우선인 콜드 요청 (KV 전송 50~200ms 추가)

✅ 결론

✅ PD Disaggregation은 에이전트 워크플로우처럼 입력 토큰이 많은 워크로드에서 처리량·레이턴시 동시 개선
✅ Infire는 vLLM 대비 처리량 7%+, 콜드 스타트 20초 이하, 메모리 효율 향상
✅ x-session-affinity 헤더 하나로 에이전트 루프 비용 대폭 절감 가능
✅ Speculative Decoding + EAGLE-3로 초대형 모델에서도 실용적인 속도 확보

❌ PD Disaggregation은 짧은 프롬프트·저동시성 환경에선 오버엔지니어링
❌ KV 캐시 네트워크 전송(50~200ms)이 TTFT에 추가 레이턴시 발생
❌ 로드 밸런서 복잡도 증가 — 직접 구현 시 스트리밍 SSE 재작성 등 엣지 케이스 많음


 

반응형