effidevFlutter · Cloudflare 엣지 · 클라우드 비용 최적화
한국어

Cloudflare 스토리지 총정리: KV vs D1 vs Hyperdrive vs R2 선택 기준과 비용 완전 비교

Cloudflare 스토리지 총정리: KV vs D1 vs Hyperdrive vs R2 비교

Cloudflare Workers 아키텍처 위에서 애플리케이션을 구축할 때 개발자가 가장 고민하는 선택은 **“데이터를 어디에 저장해야 하는가?”**이다. Cloudflare는 서버리스 엣지 인프라에 최적화된 4가지 핵심 스토리지 제품군을 제공한다.

  1. Workers KV: 초저지연 읽기에 특화된 글로벌 결과적 일관성(Eventual Consistency) Key-Value 저장소
  2. Cloudflare D1: 엣지 서버리스 SQLite 기반의 관계형 RDBMS
  3. Cloudflare Hyperdrive: 기존 온프레미스/클라우드 PostgreSQL 데이터베이스에 대한 커넥션 풀링 및 엣지 쿼리 캐시 레이어
  4. Cloudflare R2: 이그레스(Egress) 송신 비용이 $0인 S3 호환 대용량 오브젝트 스토리지

각 솔루션은 레이턴시, 트랜잭션 일관성 모델, 데이터 용량, 그리고 오퍼레이션 비용(Read/Write/Storage) 면에서 극단적인 차이를 보인다. 잘못된 스토리지 선택은 예기치 못한 API 레이턴시 증가나 청구서 폭탄으로 직결될 수 있다.

이 글에서는 Cloudflare 4대 스토리지 솔루션의 아키텍처적 차이, 레이턴시 벤치마크, 트랜잭션/일관성 특성, 비용 계산 모델, 그리고 워크로드별 의사결정 트리(Decision Tree)를 명확하게 정리한다.

핵심 요약

  • Workers KV: 읽기 비중 99% 이상인 정적 자산, 설정값, 리다이렉트 규칙에 최적 (에지 읽기 2~5ms), 단 쓰기 변경사항의 전 세계 전파에는 최대 60초 소요될 수 있음.
  • Cloudflare D1: 에지 관계형 DB로 테넌트 데이터, 사용자 프로필, 세션 저장에 최적 (ACID 트랜잭션 지원), 단 DB당 10GB 제한과 단일 Writer 병목 고려 필요.
  • Cloudflare Hyperdrive: Supabase, Neon, AWS RDS/Aurora 등 기존 PostgreSQL DB를 에지 Worker와 연결할 때 커넥션 맺는 시간(300ms -> 15ms)과 반복 쿼리를 획기적으로 줄여줌.
  • Cloudflare R2: 이미지, 비디오, 대용량 로그 백업 등 바이너리 파일 저장에 최적. AWS S3와 달리 이그레스(Egress) 네트워크 비용이 $0이라는 파격적 이점.

4대 스토리지 솔루션 핵심 비교표

항목 Workers KV Cloudflare D1 Cloudflare Hyperdrive Cloudflare R2
데이터 모델 Key-Value Relational (SQLite) PostgreSQL Proxy / Cache Object Storage (Blob)
일관성 모델 Eventual Consistency Strong Consistency (ACID) Origin DB 일관성 상속 Strong Consistency
읽기 지연 (p50) 2ms ~ 5ms (PoP Edge) 5ms ~ 15ms (Edge) 10ms ~ 25ms (Cached) 25ms ~ 50ms
최대 용량 키당 25MB, 계정 무제한 DB당 10GB (샤딩 가능) Origin DB 스펙 의존 오브젝트당 5TB, 무제한
트랜잭션 지원 미지원 지원 (SQLite Transaction) 지원 (PostgreSQL ACID) 미지원
Egress 비용 $0 $0 $0 $0 (Egress Free)
주요 유스케이스 캐시, 토큰, 리다이렉트 사용자 DB, 메타데이터 기존 PostgreSQL 에지 연결 미디어, 백업, 아카이브

레이턴시 및 일관성(Consistency) 아키텍처 분석

1. Workers KV: 읽기 중심 최적화

KV는 전 세계 300개 이상의 PoP 에지 노드 메모리와 SSD에 데이터를 복제한다. kv.get()은 네트워크 이동 없이 Worker가 실행 중인 동일 PoP에서 즉시 처리되므로 2ms 이하의 초저지연을 자랑한다. 그러나 kv.put() 쓰기 작업은 중앙 저장소를 거쳐 글로벌 에지로 전파(Propagate)되기 때문에 **결과적 일관성(Eventual Consistency)**을 띤다. 주식 잔고나 실시간 수량 체크처럼 엄격한 일관성이 필요한 데이터에는 절대 사용해서는 안 된다.

2. Cloudflare D1: 에지 관계형 데이터베이스

D1은 SQLite 기반으로 ACID 트랜잭션을 보장한다. 읽기는 지리적으로 가까운 Read Replica에서 수행되고 쓰기는 Primary 데이터베이스로 전송된다. 테넌트 데이터나 유저 세션 관리 등 관계형 데이터 구조가 필요한 서비스에 완벽하다.

3. Cloudflare Hyperdrive: PostgreSQL 에지 가속기

Worker에서 AWS RDS나 Neon 같은 외부 PostgreSQL에 직접 연결하면 TCP/TLS 핑 왕복(Handshake)으로 인해 최초 쿼리에 200~400ms의 지연이 발생한다. Hyperdrive는 에지 PoP에 **커넥션 풀(Connection Pool)**을 유지하고 SQL 쿼리 응답을 지능적으로 캐싱하여 레이턴시를 10ms 내외로 단축시킨다.

4. Cloudflare R2: 이그레스 비용 $0의 S3 대체제

R2는 S3 API 표준을 완벽히 지원한다. S3를 사용할 때 가장 무서운 항목이 GB당 $0.09에 달하는 이그레스(Egress) 다운로드 비용인데, R2는 이그레스 비용이 완전히 $0이다. 미디어 스트리밍이나 파일 다운로드 서비스 구축 시 비용을 90% 이상 절감할 수 있다.

비용 모델 및 가격 비교 (Pricing Structure)

100만 회 읽기/쓰기 및 100GB 저장 용량을 기준으로 한 가격 계산 비교는 다음과 같다.

서비스 저장 용량 비용 읽기(Read) 비용 쓰기(Write) 비용 Egress 비용
Workers KV $0.50 / GB / 월 $0.50 / 1,000만 회 $5.00 / 100만 회 $0
Cloudflare D1 $0.75 / GB / 월 $0.001 / 1,000만 행 읽기 $1.00 / 100만 행 쓰기 $0
Hyperdrive 무료 (Free) Worker 요청에 포함 Worker 요청에 포함 $0
Cloudflare R2 $0.015 / GB / 월 $0.36 / 1,000만 회 (Class B) $4.50 / 100만 회 (Class A) $0
(참고) AWS S3 $0.023 / GB / 월 $0.40 / 1,000만 회 $5.00 / 100만 회 $90.00 / 1TB

R2와 AWS S3를 비교해보면, 월 1TB의 파일이 다운로드될 때 S3는 $90의 이그레스 비용이 청구되지만 R2는 $0이다.

스토리지 선택 의사결정 트리 (Decision Tree)

어떤 스토리지를 선택해야 할지 고민된다면 다음 조건문을 따라가자.

1. 저장하려는 데이터가 이미지, 비디오, PDF 같은 대용량 바이너리 파일인가?
   └── YES ──> [Cloudflare R2]
   └── NO

2. 이미 AWS RDS, Supabase, Neon 등 외부 PostgreSQL DB를 사용 중인가?
   └── YES ──> [Cloudflare Hyperdrive]
   └── NO

3. SQL JOIN, 외래키, ACID 트랜잭션이 필요한 구조화된 데이터인가?
   └── YES ──> [Cloudflare D1]
   └── NO

4. 읽기 비중이 99% 이상이며, 전 세계 엣지에서 2ms 초저지연 조회가 필요한가?
   └── YES ──> [Workers KV]

스토리지 조합 실전 TypeScript 코드 예시

실제 에지 서비스에서는 단일 스토리지보다 여러 스토리지를 조합(Hyperdrive + KV 또는 D1 + R2)하는 패턴이 일반적이다.

export interface Env {
  CACHE_KV: KVNamespace;
  HYPERDRIVE: Hyperdrive;
  MY_BUCKET: R2Bucket;
}

import { Client } from "pg";

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const productId = url.searchParams.get("id");

    if (!productId) return new Response("Missing id", { status: 400 });

    // [Pattern 1] KV를 활용한 1차 에지 캐시 조회 (2ms)
    const cacheKey = `prod:${productId}`;
    const cachedData = await env.CACHE_KV.get(cacheKey);
    if (cachedData) {
      return new Response(cachedData, {
        headers: { "Content-Type": "application/json", "X-Cache": "HIT-KV" },
      });
    }

    // [Pattern 2] KV Cache Miss 시 Hyperdrive를 통한 PostgreSQL 초고속 쿼리 (12ms)
    const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
    await client.connect();

    const result = await client.query("SELECT id, name, image_key FROM products WHERE id = $1", [productId]);
    await client.end();

    if (result.rows.length === 0) {
      return new Response("Not Found", { status: 404 });
    }

    const product = result.rows[0];

    // [Pattern 3] R2에서 이미지 파일 메타데이터 및 공개 URL 구성
    const productPayload = JSON.stringify({
      ...product,
      imageUrl: `https://pub-r2.company.com/${product.image_key}`,
    });

    // KV에 1시간 동안 캐싱 처리
    await env.CACHE_KV.put(cacheKey, productPayload, { expirationTtl: 3600 });

    return new Response(productPayload, {
      headers: { "Content-Type": "application/json", "X-Cache": "MISS" },
    });
  },
};

결론

각 제품의 특성을 이해하고 적재적소에 조합하면 비용을 90% 이상 감축하면서 전 세계 사용자에게 50ms 미만의 쾌적한 응답 속도를 제공할 수 있다.