--- id: backend-geo-replication title: Geo Replication — Multi-region / CDN / Edge category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [backend, geo, multi-region, edge, vibe-coding] tech_stack: { language: "TS / Cloudflare / AWS", applicable_to: ["Backend"] } applied_in: [] aliases: [multi-region, geo-replicate, latency, CDN, edge function, R2, D1] --- # Geo Replication > 사용자 가까이 = 빠름. **CDN (정적) → Edge function (동적, low-latency) → DB (가장 어려움)**. Read replica 글로벌 분산. Write 는 보통 single region. ## 📖 핵심 개념 - Latency 기여도: DB > network round-trip > CDN miss. - CDN: 정적 파일 — Cloudflare / Cloudfront. - Edge function: 50+ region 에서 코드 실행 — Workers / Lambda@Edge. - Multi-region DB: read replica / global DB (Spanner / CockroachDB). ## 💻 코드 패턴 ### CDN cache ``` Static assets (JS / image / font) → Cloudflare / Cloudfront / Vercel Edge Network → 매 region cache, 자동. ``` ```ts // Cache-Control 강력 res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); // hash filename (app.abc123.js) → immutable safe ``` ### Edge function ```ts // Cloudflare Worker export default { async fetch(req: Request, env: Env): Promise { const url = new URL(req.url); // KV (read replica 가까이) const cached = await env.CACHE.get(url.pathname); if (cached) return new Response(cached, { headers: { 'cache-control': 'max-age=60' } }); // Origin 으로 fetch (US east 가정) const r = await fetch(`https://origin.example.com${url.pathname}`); const text = await r.text(); await env.CACHE.put(url.pathname, text, { expirationTtl: 60 }); return new Response(text); }, }; ``` ### Cloudflare D1 / Durable Objects (글로벌 SQLite) ```ts const r = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(id).first(); // D1 = read replica 글로벌, write 는 primary ``` ### Read replica 글로벌 (RDS / Aurora) ``` Primary (us-east-1) ├── Read replica (eu-west-1) └── Read replica (ap-northeast-1) ``` ```ts function getReader(region: string): Pool { if (region === 'eu') return euReader; if (region === 'asia') return asiaReader; return usReader; } const region = req.cf?.continent ?? 'NA'; const r = await getReader(region).query('SELECT ...'); ``` ⚠️ Replication lag — 강 일관성 필요한 read 는 primary. ### Global DB (Spanner / CockroachDB / YugabyteDB) ```sql -- 자동 멀티 region replication -- Write 도 가까운 region 에서 가능 CREATE TABLE orders (...) LOCALITY REGIONAL BY ROW; ``` 비싸고 복잡. Truly global business 에만. ### User-affinity routing ```ts // 사용자가 EU 면 EU region 으로 항상 function regionFor(user: User): Region { return user.dataResidency ?? geoip(user.ip); } // DNS GeoDNS 또는 Anycast LB ``` ### GDPR — 데이터 거주 ``` EU 사용자 → EU region DB only 다른 region 으로 절대 복제 X ``` ```ts // Per-tenant region const dbForTenant = (t: Tenant) => pools[t.region]; ``` ### Backup geo ```bash # Cross-region backup (재해 대비) aws s3 sync s3://primary-backup s3://eu-backup --source-region us-east-1 --region eu-west-1 ``` ### Static + dynamic 분리 (Vercel-style) ``` /api/* → 가장 가까운 edge function /_next/static → CDN /data → 동적 → primary region ``` ### Latency-based routing ``` Route 53 latency-based 또는 Cloudflare Argo ``` 자동으로 가까운 endpoint 로. ## 🤔 의사결정 기준 | 상황 | 추천 | |---|---| | 정적 사이트 | CDN 만 | | Mostly read API | Edge function + CDN | | 글로벌 사용자 + 동적 | Edge + global read replica | | Strong consistency 글로벌 | Spanner / CockroachDB | | GDPR 거주 | Region-pinned DB | | 작은 / 시작 | Single region OK | ## ❌ 안티패턴 - **Single region prod + 글로벌 사용자**: 200ms+ latency. - **Cross-region transaction 매번**: 큰 latency. - **Replica lag 모니터링 없음**: 분 단위 stale. - **CDN 안 써서 정적 매번 origin**: 비싸고 느림. - **Edge function 에 DB 직접 connect (TCP)**: 매 invocation 소켓. HTTP / connection pool. - **GDPR 무시 — 글로벌 복제**: 법적 위반. - **Failover 안 테스트**: 진짜 disaster 시 작동 X. ## 🤖 LLM 활용 힌트 - 정적 = CDN 자동. - 동적 read = edge + KV / read replica. - Write = primary 만 + outbox. - GDPR 시작부터 region-pin. ## 🔗 관련 문서 - [[DB_Read_Replica_Patterns]] - [[Backend_API_Gateway_BFF]] - [[Web_HTTP_Cache_Headers]]