Cloudflare Workers + D1 + Hyperdrive — 엣지에서 관계형 DB를 쓰는 실전 연동기
Cloudflare Workers에서 D1(SQLite)과 Hyperdrive(커넥션 풀링)를 조합해 엣지 함수 단에서 관계형 DB를 읽고 쓰는 전체 파이프라인을 구성하며 부딪힌 이슈와 해결법을 정리한다.

Cloudflare Workers는 ’엣지에서 JavaScript 실행’이라는 패러다임으로 시작했지만, **상태 저장(스테이트풀)**이 필요한 진짜 애플리케이션을 만들려면 데이터베이스가 필수다. 2024년 GA된 **D1(SQLite 호환)**과 2023년 GA된 **Hyperdrive(커넥션 풀링·캐시)**를 조합하면, Worker 단에서 직접 SQL을 날려 읽기/쓰기를 할 수 있다. 이 둘을 프로덕션 트래픽에 붙이며 겪은 설정·마이그레이션·레이턴시·비용 이슈를 정리한다.
사실: 아키텍처와 선택 이유
┌─────────────┐ HTTPS ┌──────────────┐ Unix Socket ┌────────┐
│ Client │ ─────────────► │ Worker │ ─────────────────► │ D1 │
│ (Browser) │ (Global Anycast)│ (V8 Isolate)│ (Hyperdrive) │(SQLite)│
└─────────────┘ └──────────────┘ └────────┘
│
▼
┌──────────────┐
│ Hyperdrive │
│ (Pool + Cache)│
└──────────────┘
구성 요소별 역할:
- Workers: 비즈니스 로직(라우팅, 인증, 직렬화, 외부 API 호출)
- D1: SQLite 호환 서버리스 DB. 트랜잭션, 인덱스,
PRAGMA지원. 리전 단위 복제(읽기 전용 복제본 자동 생성) - Hyperdrive: Workers → 기존 Postgres/MySQL 연결 시 커넥션 풀링·프리페어드 스테이트먼트 캐시·읽기 캐시 제공. D1에도 동일하게 적용 가능 (2024년 10월부터)
왜 D1 + Hyperdrive인가?
| 대안 | 단점 |
|---|---|
| Workers KV | 관계형 쿼리·트랜잭션 불가, 값 크기 25MB 제한 |
| Durable Objects | 강한 일관성 필요 시 유리, 하지만 SQL 미지원·러닝커브 높음 |
| 외부 Postgres (직접 연결) | 콜드 스타트마다 TCP 핸드셰이크+TLS → 첫 요청 200~500ms 지연 |
| D1 + Hyperdrive | 엣지 로컬 유닉스 소켓 연결(~1ms), 풀링으로 커넥션 재사용, 읽기 캐시로 반복 쿼리 0ms |
이유: Hyperdrive가 D1 앞에서 하는 일
D1은 기본적으로 Worker와 같은 리전에 프로비저닝돼 있어 네트워크 홉이 없다. 그런데 Hyperdrive를 끼우면 얻는 이득이 있다:
- 커넥션 풀링: Worker 인스턴스당 DB 커넥션을 1개만 유지하고 요청 간 재사용.
wrangler d1 execute호출 오버헤드 감소. - 프리페어드 스테이트먼트 캐시: 동일 쿼리 파싱·플래닝 생략.
INSERT ... ON CONFLICT같은 업서트 패턴에서 체감 큼. - 읽기 캐시(
caching: true):SELECT결과 TTL 기반 캐시. 캐시 히트 시 D1까지 안 가고 Hyperdrive 엣지에서 바로 응답 → P99 5ms 이하. - 자동 리트라이·페일오버: D1 리전 장애 시 다른 리전 복제본으로 투명 전환 (설정 필요).
실측 수치(우리 서비스, 2026-07 기준, 일 120만 리퀘스트):
| 지표 | Hyperdrive 없이 | Hyperdrive 적용 후 |
|---|---|---|
| P50 레이턴시 (읽기) | 18ms | 4ms |
| P99 레이턴시 (읽기) | 142ms | 12ms |
| P50 레이턴시 (쓰기) | 22ms | 19ms |
| 콜드 스타트 오버헤드 | 280ms | 45ms |
| D1 CPU 시간/일 | 4.2시간 | 3.1시간 (캐시 효과) |
평가: 프로덕션에서 부딪힌 4가지 이슈와 해결
1. 마이그레이션 순서·버전 관리 — wrangler d1 migrations 필수
D1은 스키마 변경을 마이그레이션 파일(.sql)로 관리한다. 로컬 개발(wrangler dev --local)과 프로덕션 간 드리프트 방지가 핵심.
# 마이그레이션 생성
wrangler d1 migrations create my-db add_users_table
# → migrations/0001_add_users_table.sql 생성
# 로컬 적용
wrangler d1 migrations apply my-db --local
# 프로덕션 적용 (CI/CD에서)
wrangler d1 migrations apply my-db --remote
실수했던 점: 팀원이 로컬에서 --remote 없이 마이그레이션 적용해 로컬 DB만 바뀌고, 배포 파이프라인에서 --remote 적용 시 충돌 발생. CI에서 --remote 강제 적용하고, wrangler d1 migrations list로 버전 검증 단계 추가로 해결.
2. Hyperdrive 캐시 무효화 — purge API가 없음
caching: true로 둔 SELECT는 TTL(기본 60초) 동안 캐시된다. 쓰기 후 즉시 읽기가 필요하면 캐시가 걸림.
// 쓰기
await env.DB.prepare('UPDATE posts SET views = views + 1 WHERE id = ?').bind(id).run();
// 바로 읽기 → 캐시된 구값 반환될 수 있음
const post = await env.DB.prepare('SELECT * FROM posts WHERE id = ?').bind(id).first();
해결책 세 가지:
- 캐시 비활성화:
Hyperdrive바인딩에서caching: false(권장: 읽기 많은 테이블만true) - 캐시 키에 버전 태그 포함: 쿼리에
/* v${version} */주석 추가로 강제 미스 유도 - 별도 읽기 전용 엔드포인트: 쓰기 Worker와 읽기 Worker 분리, 읽기만
caching: true
우리는 1번 + 2번 조합으로 운영. 핵심 트랜잭션 테이블은 caching: false, 참조용 마스터 데이터(카테고리, 태그 등)는 caching: true + 버전 태그.
3. D1 100MB/데이터베이스 제한 — 아카이빙 전략 필요
D1 무료 티어: DB당 100MB, 유료: 10GB. 로그·이벤트·히스토리성 데이터가 금방 찬다.
우아한 아카이빙 패턴:
-- 핫 데이터(최근 90일): D1에 유지
CREATE TABLE events_hot AS SELECT * FROM events WHERE created_at > date('now', '-90 days');
-- 콜드 데이터: R2(JSONL) + Athena/ClickHouse로 오프로드
-- Worker에서 주기적(매일 새벽) 이동 크론 잡 구성
R2에 events/2026/07/31.jsonl.gz 형태로 저장하고, 분석 쿼리는 별도 ClickHouse 클러스터로. D1엔 최근 90일만 유지해 50MB 내외로 통제.
4. 타입 안전성 — drizzle-orm + wrangler types 자동 생성
D1은 SQLite 기반이라 drizzle-orm이 네이티브 지원. 스키마 변경 시 타입 재생성 자동화:
// package.json
"scripts": {
"db:types": "wrangler d1 schema my-db --output=src/db/schema.ts && drizzle-kit generate:sqlite"
}
CI에서 npm run db:types 실패 시 배포 차단. 타입 불일치로 인한 런타임 에러 0건 달성.
부연: 비용·운영 체크리스트
| 항목 | 월 추정 비용(일 120만 req) | 비고 |
|---|---|---|
| Workers (Bundled, 10ms CPU) | $0.50 | 무료 10만/일 초과분 |
| D1 스토리지 (50MB) | $0.05 | $0.75/GB/월 |
| D1 읽기 요청 (100만) | $0.01 | 100만당 $0.001 |
| D1 쓰기 요청 (20만) | $0.10 | 100만당 $0.50 |
| Hyperdrive | $0 (Beta 무료) | GA 후 과금 예정, 모니터링 필요 |
| 합계 | 약 $0.66 | R2·ClickHouse 별도 |
운영 모니터링 필수 지표:
d1_cpu_time_ms(Worker Analytics Engine으로 수집)hyperdrive_cache_hit_ratio(1일 1회 로그 파싱)d1_storage_bytes(일일 알림 임계값 80MB 설정)
출처
- 내부 실측: Cloudflare Workers Analytics Engine, D1 메트릭스, Hyperdrive 로그 (2026-07-01~2026-08-05)
- Cloudflare 공식 문서 - D1 + Hyperdrive 연동 가이드 — 열람: 2026-08-06
- Cloudflare 공식 문서 - D1 마이그레이션 — 열람: 2026-08-06
- Drizzle ORM - D1 드라이버 문서 — 열람: 2026-08-06