4.6 KiB
4.6 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| backend-geo-replication | Geo Replication — Multi-region / CDN / Edge | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
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, 자동.
// Cache-Control 강력
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
// hash filename (app.abc123.js) → immutable safe
Edge function
// Cloudflare Worker
export default {
async fetch(req: Request, env: Env): Promise<Response> {
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)
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)
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)
-- 자동 멀티 region replication
-- Write 도 가까운 region 에서 가능
CREATE TABLE orders (...) LOCALITY REGIONAL BY ROW;
비싸고 복잡. Truly global business 에만.
User-affinity routing
// 사용자가 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
// Per-tenant region
const dbForTenant = (t: Tenant) => pools[t.region];
Backup geo
# 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.