Multi-Region Foundation (30min)
오준석 (Junseok Oh), Sr. Solutions Architect, AWS
총 150min 세션
:::click
Scalability (10x Traffic Spikes)
정의: 모든 읽기가 최신 쓰기 결과를 반환
AWS 서비스: Aurora DSQL, DynamoDB (strongly consistent read)
Latency: 높음 (cross-region quorum 필요)
Use Case: 금융 트랜잭션, 재고 관리, 결제 처리
정의: 읽기가 최대 N초 또는 N버전 이내의 데이터 반환
AWS 서비스: Cosmos DB (Azure), 커스텀 구현 필요
Latency: 중간 (설정된 bound 내에서 유연)
Use Case: 리더보드, 분석 대시보드, 실시간에 근접한 데이터
정의: 같은 세션 내에서는 자신의 쓰기를 항상 읽음
AWS 서비스: DynamoDB (with session affinity)
Latency: 낮음 (local read 가능)
Use Case: 사용자 프로필, 쇼핑 카트, 개인 설정
정의: 충분한 시간이 지나면 모든 복제본이 동일해짐
AWS 서비스: S3, DynamoDB Global Tables, ElastiCache
Latency: 가장 낮음 (local read, async replication)
Use Case: 로그, 메트릭, 콘텐츠 캐시, 비핵심 데이터
10.x.0.0/20 (AZ-a)10.x.16.0/20 (AZ-b)10.x.32.0/20 (AZ-c)10.x.48.0/20 (AZ-a)10.x.64.0/20 (AZ-b)10.x.80.0/20 (AZ-c)10.x.96.0/20 (AZ-a)10.x.112.0/20 (AZ-b)10.x.128.0/20 (AZ-c)| Decision | Choice | Rationale |
|---|---|---|
| Data Pattern | Write-Primary / Read-Local | No conflict, Aurora handles forwarding |
| Cross-region | Transit Gateway | ECMP, centralized routing, scalability |
| Ingress | CloudFront-only | No direct ALB, WAF integration, global edge |
| IAM | IRSA everywhere | Least privilege, no shared node role |
| Node Provisioning | Karpenter 6-pool | Workload-specific, cost/availability balance |
| Service Discovery | DNS-based | Simpler ops, sufficient for current scale |
| Autoscaling | KEDA + HPA dual | Event-driven + metric-driven scaling |
| GitOps | ArgoCD App-of-apps | Declarative, audit trail, multi-cluster |
| Encryption | Per-service KMS | Isolation, granular rotation, blast radius |
| Network | 3-tier subnets | Security segmentation, compliance |
Data Sync & Replication (30min)
오준석 (Junseok Oh), Sr. Solutions Architect, AWS
| Workload Type | Data Store | Replication | Services |
|---|---|---|---|
| ACID 트랜잭션 (강한 일관성) | Aurora PostgreSQL Global DB | ≤1s async | order, payment, inventory, user-account, shipping |
| 유연한 스키마 (문서 모델) | DocumentDB Global Cluster | ≤2s async | product-catalog, user-profile, wishlist, review |
| 실시간 캐시 (밀리초 응답) | ElastiCache Valkey Global | <1s async | cart, session, rate-limiting, leaderboard |
| 전문 검색 (한국어 nori) | OpenSearch 2.17 | Cross-cluster | search, analytics, notification-logs |
| 이벤트 스트리밍 (비동기) | MSK Kafka 3.6 | MSK Replicator | event-bus, saga orchestration |
| 정적 자산 (객체) | S3 + CRR | Async | CDN assets, Tempo traces |
원칙: 각 데이터 스토어는 워크로드 특성에 최적화된 용도로 사용. 모든 것을 하나의 DB에 넣지 않는다.
| Parameter | Value |
|---|---|
| Engine | PostgreSQL 15.4 |
| Instance Class | r6g.2xlarge (Writer) |
| Replication Lag | ≤1 second (typical) |
| RPO | ~1 second |
| Failover RTO | <1 minute (planned) |
| Max Secondary Regions | 5 |
| Storage | Auto-scaling, encrypted |
order-service — 주문 CRUDpayment-service — 결제 트랜잭션inventory-service — 재고 관리user-account-service — 사용자 계정shipping-service — 배송 추적returns-service — 반품 처리
| Operation | Local Region | With Write Forwarding | Overhead |
|---|---|---|---|
| Simple INSERT | 5-10ms | 65-90ms | +60-80ms (RTT) |
| Batch INSERT (100 rows) | 50-100ms | 110-180ms | +60-80ms |
| UPDATE with index | 3-8ms | 63-88ms | +60-80ms |
| Transaction (3 statements) | 15-30ms | 195-270ms | +180-240ms (3 RTT) |
| Constraint | Detail |
|---|---|
| Read-after-write | 복제 지연(≤1s)까지 기다려야 최신 데이터 확인 가능 |
| Transaction isolation | 각 statement마다 RTT 추가, 긴 트랜잭션은 비효율적 |
| DDL 불가 | CREATE TABLE, ALTER TABLE 등은 Primary에서 직접 실행 |
| Temp table 불가 | 임시 테이블 사용 불가 |
Best Practice: Write-heavy 서비스는 Primary 리전에, Read-heavy 서비스는 양 리전에 배치
::: tab Primary Cluster (us-east-1)
:::
::: tab Secondary Cluster (us-west-2)
:::
| Collection | Index | Purpose |
|---|---|---|
| products | { productId: 1 } unique | PK lookup |
| products | { category.slug: 1 } | 카테고리 필터 |
| products | { brand: 1 }, { rating: -1 } | 브랜드 필터, 평점 정렬 |
| user_profiles | { userId: 1 } unique | 사용자 조회 |
| reviews | { productId: 1 }, { rating: -1 } | 상품별 리뷰, 평점순 |
| notifications | { userId: 1, sentAt: -1 } | 최근 알림 조회 |
| Parameter | Value |
|---|---|
| Engine | Valkey 7.2 |
| Node Type | cache.r7g.xlarge |
| Shards | 3 (num_node_groups) |
| Replicas/Shard | 2 |
| Cross-region lag | < 1 second |
| Encryption | At-rest (KMS) + In-transit (TLS) |
| Key Pattern | TTL | Data Type | Access Pattern |
|---|---|---|---|
product:{id} | 1h | Hash | Cache-Aside: DB 조회 후 캐시 |
cache:categories | 24h | String (JSON) | Refresh-Ahead |
cart:{userId} | 7d | Hash | Write-Through: 즉시 반영 |
session:{sessionId} | 2h | Hash | Write-Through |
ratelimit:api:{userId} | 60s | String (counter) | Increment + EXPIRE |
stock:{productId} | - (no TTL) | String (counter) | DECR on purchase |
leaderboard:popular | - (no TTL) | Sorted Set | ZINCRBY on view |
search-history:{userId} | 30d | List | LPUSH + LTRIM(50) |
promo:flash-sale | 24h | Hash | Write-Through |
| Pattern | When to Use | Implementation |
|---|---|---|
| Cache-Aside | 읽기 빈번, 쓰기 적은 데이터 | App이 캐시 miss 시 DB 조회 → SET |
| Write-Through | 즉시 일관성 필요 | App이 DB + 캐시 동시 갱신 |
| Event-Driven | 비동기 일관성 OK | Kafka 이벤트로 캐시 무효화 |
| TTL-Based | 결과적 일관성 OK | 자연 만료 후 DB에서 재로드 |
| Category | Topics | Partitions | Retention |
|---|---|---|---|
| Order | order.created/confirmed/shipped/delivered | 6 each | 7d |
| Payment | payment.completed/refunded/failed | 6 each | 7d |
| Inventory | inventory.reserved/released/restocked | 4 each | 7d |
| Notification | notification.email/push/sms | 3 each | 3d |
| Infrastructure | dlq.all, saga.orchestrator | 1, 6 | 30d, 7d |
::: option-a MSK Replicator Enabled
복제 대상: 모든 토픽 (regex: .*)
Consumer Offset: 동기화 가능
Compression: GZIP
Latency: 수백 ms ~ 수 초
:::
::: option-b MSK Replicator Disabled
Secondary MSK: 독립 클러스터 (빈 토픽)
DR 시나리오: Producer가 Secondary로 전환
:::
| Data Store | Replication Method | Typical Lag | RPO | Risk Level |
|---|---|---|---|---|
| Aurora Global DB | Storage-level async | ≤ 1s | ~1s | 🟢 Low |
| DocumentDB Global | Oplog-based async | ≤ 2s | ~2s | 🟡 Medium |
| ElastiCache Global | Async replication | < 1s | ~1s | 🟢 Low |
| MSK Replicator | Topic-level async | 100ms ~ 5s | ~5s | 🟡 Medium |
| OpenSearch | Cross-cluster (manual) | Minutes | Minutes | 🔴 High |
| S3 CRR | Object-level async | ≤ 15min | ~15min | 🔴 High |
| Scenario | Uncommitted Data | Impact | Mitigation |
|---|---|---|---|
| Aurora Failover | ≤1s of writes | 최근 주문/결제 유실 | Idempotent retry + DLQ |
| DocumentDB Failover | ≤2s of writes | 프로필/리뷰 업데이트 유실 | Event sourcing + replay |
| ElastiCache Failover | ≤1s of writes | 세션/장바구니 유실 | Session reconstruction |
| MSK Failover | In-flight events | 이벤트 순서 보장 불가 | Consumer idempotency |
핵심: 모든 서비스는 idempotent하게 설계하여 재시도 시 중복 처리를 방지해야 합니다.
:::card-grid
:::card highlight
각 데이터 스토어는 워크로드 특성에 맞게 선택. Aurora(ACID), DocumentDB(문서), ElastiCache(캐시), MSK(이벤트)
:::
:::card
모든 쓰기는 Primary 리전으로 라우팅. 읽기는 양 리전에서 서비스. Aurora Write Forwarding으로 Secondary에서도 쓰기 가능.
:::
:::card
모든 크로스리전 복제는 비동기. RPO는 1초(Aurora)부터 15분(S3)까지 다양. 강한 일관성이 필요하면 Primary에서 처리.
:::
:::card highlight
Failover, 복제 지연, 네트워크 파티션 — 모든 상황에서 안전하려면 서비스의 idempotent 설계가 필수.
:::
:::
Global Traffic Management with Route53, CloudFront & WAF
| Record | Type | Routing |
|---|---|---|
mall.example.com | CNAME | → CloudFront |
api-internal.example.com | A | Latency (2 regions) |
/health
HTTPS:443
30s
3
us-east-1, us-west-2, eu-west-1
| Service | Monthly Cost | Pricing Model | Notes |
|---|---|---|---|
|
|
$50 - $500 | Requests + Data transfer | Traffic-dependent |
|
|
$0 | ACL + Rules + Requests | Currently disabled in prod |
|
|
$36 + LCU | $18/NLB + LCU charges | 2 regions × $18 base |
|
|
~$5 | Hosted zones + Queries | $0.50/zone + $0.40/M queries |
Disaster Recovery 현황 분석과 자동화 전략 (30min)
| Component | DR Capability | Failover Type | Risk Level |
|---|---|---|---|
| Auto failover | Auto | LOW | |
| NO DR (single region) | None | CRITICAL | |
| Global Cluster | Manual CLI | HIGH | |
| Global Datastore | Manual CLI | MEDIUM | |
| NO DR (per-region) | None | CRITICAL | |
| Per-region (rebuild) | Hours | HIGH | |
| Cross-Region Replication | Auto CRR | LOW | |
| Karpenter auto-provision | Auto | LOW |
CRITICAL: DSQL + MSK — 리전 장애 시 완전한 데이터 손실
| Component | RTO | RPO | Recovery Notes |
|---|---|---|---|
| Traffic Routing | 1-2 min | 0 | Health check interval + DNS TTL |
| Aurora DSQL | N/A | Total Loss | No cross-region replica exists |
| DocumentDB | 5-15 min | < 1 min | Manual switchover-global-cluster |
| ElastiCache | 1-5 min | < 1 sec | Manual promote secondary |
| MSK | N/A | Total Loss | Replicator disabled, no offset sync |
| S3 | Instant | < 15 min | CRR replication lag |
| EKS | 2-5 min | 0 | Karpenter node replacement |
Impact: 6 services affected
Current Behavior:
Graceful Degradation (recommended):
Impact: 7 services affected
Manual Failover Steps:
RTO: 5-15 minutes
RPO: < 1 minute
Impact: cart service (session + cache)
Manual Promotion:
RTO: 1-5 minutes
Cart data: Temporary loss (rebuild from DB)
Region failure = Total data loss for 6 core services
production-docdb-global.cluster-xxx.us-east-1.docdb.amazonaws.com
production-docdb-global.cluster-yyy.us-west-2.docdb.amazonaws.com
Cross-Region Monitoring, Cost Optimization, Production Readiness
Dual Export: Tempo (S3 장기 저장) + X-Ray (managed, 서비스 맵)
Head Sampling: 요청 시작 시 샘플링 결정
문제: 에러/지연 발생 전에 결정 → 중요 트레이스 누락
Tail Sampling: 전체 트레이스 완료 후 결정
장점: 에러/지연 여부 확인 후 선택적 저장
| Policy | Rate | Condition |
|---|---|---|
| errors | 100% | status_code = ERROR |
| slow | 100% | latency > 500ms |
| default | 10% | probabilistic |
Retention: 30 days hot, 90 days warm
Compression: zstd (60% savings)
| Tier | Days | Cost/GB |
|---|---|---|
| S3 Standard | 0-30 | $0.023 |
| S3 IA | 30-90 | $0.0125 |
| Glacier IR | 90-365 | $0.004 |
| Delete | 365+ | - |
Tempo metrics_generator가 span 데이터에서 자동으로 서비스 의존성 그래프 생성
1. TraceID Injection
2. Grafana Derived Fields
| Category | Service | Spec | Cost/mo |
|---|---|---|---|
| Compute | EKS Control Plane | x2 regions | $146 |
| Karpenter EC2 | m6i/c6i.xlarge variable | $2,800-4,200 | |
| Bootstrap Node Group | t3.medium x2 regions | $240 | |
| Database | Aurora DSQL | us-east-1 only (serverless) | $200-500 |
| DocumentDB | r6g.large x4 (Global) | $1,480 | |
| ElastiCache | r6g.large x4 (Valkey) | $880 | |
| OpenSearch | r6g.large x4 + master x3 | $1,560 | |
| Messaging | MSK | kafka.m5.large x3 x2 regions | $1,620 |
| Network | NAT Gateway | x4 (2 per region) | $270 |
| Transit Gateway | x2 regions + attachments | $146 | |
| NLB | x2 regions | $36+ |
| Optimization | Savings | Effort | Notes |
|---|---|---|---|
| Karpenter Spot Expansion | 30-40% EC2 | L | worker-tier, batch-tier NodePool에 Spot 우선 설정 |
| DocumentDB Downsize | $370/mo | L | r6g.large → r6g.medium (현재 CPU <20%) |
| MSK Serverless | 50-70% | M | 저트래픽 시 유리 (현재 provisioned 유휴) |
| OpenSearch Scale-down | $520/mo | L | dedicated master 제거 (현재 search 미사용) |
| Reserved Instances 1yr | 30-40% DB | L | DocumentDB, ElastiCache, OpenSearch |
| NAT → NAT Instance | $200/mo | M | t4g.micro + ASG (HA 구성) |
| Percentile | Target | Status |
|---|---|---|
| p50 | < 100ms | TBD |
| p95 | < 300ms | TBD |
| p99 | < 500ms | TBD |
| Endpoint | p95 |
|---|---|
| GET /products | < 200ms |
| GET /products/:id | < 150ms |
| POST /orders | < 500ms |
| POST /payments | < 500ms |
| GET /search | < 300ms |
| GET /seller/dashboard | < 400ms |
총 7개 Gap | P0 해결 없이는 Production 불가