Multi-Region Architecture Deep Dive

두 리전에서 하나의 서비스처럼 동작하는 아키텍처 설계

Block 1: Multi-Region Foundation | 30분

오늘 세션 구성

총 150min 세션

1
Multi-Region Foundation 30분
2
Data Sync & Replication 30분
3
Traffic Routing & Edge 30분
4
DR & Failover Automation 30분
5
Observability & Operations 30분
질문은 각 Block 종료 시에 받겠습니다.

멀티리전, 목적부터 정한다

리전 규모 장애 격리가용성
Multi-AZ는 AZ 장애를 막고, 멀티리전은 리전 전체에 영향을 주는 드문 이벤트를 막습니다
사용자 근접 지연성능
CDN이 못 줄이는 동적 API 읽기를 사용자와 가까운 리전에서 처리
데이터 레지던시규제
국가, 산업 규제로 특정 리전 안에 데이터를 보관해야 하는 경우
배포 blast radius 축소운영
한 리전씩 순차 배포하면 잘못된 변경의 영향 범위가 리전 하나로 제한
공짜가 아닙니다: 인프라 이중화, 리전 간 데이터 전송 요금, 일관성 설계, 페일오버 연습까지 비용이 늘어납니다. 목표 RTO, RPO가 이 비용을 정당화하는지 먼저 확인하세요.

Active-Active냐, Passive냐

Active-Active
  • 모든 리전이 동시에 트래픽 처리, 사용자는 가까운 리전으로
  • 리전 하나를 잃어도 다른 리전이 이미 서비스 중
  • 쓰기를 양쪽에서 받으면 충돌 해결 또는 동기 합의가 필요
  • 각 리전이 전체 부하를 흡수할 용량을 유지해야 함
Active-Passive
  • Primary만 트래픽 처리, secondary는 대기 또는 축소 운영
  • DR 전략 스펙트럼: Backup & Restore, Pilot Light, Warm Standby
  • 단방향 복제라 충돌이 없고 구현이 단순
  • 페일오버 절차와 승격 시간이 RTO를 결정
이 세션의 선택: 읽기는 Active-Active, 쓰기는 Active-Passive. 두 리전 모두 트래픽을 받되 쓰기는 us-east-1 한 곳으로 모읍니다 (Write-Primary / Read-Local).

CAP은 장애 때, PACELC는 평소에

CAP: Partition이 나면
리전 간 연결이 끊긴 순간, 쓰기를 거부해 일관성(C)을 지키거나 각자 받아 가용성(A)을 지킨다
PACELC: Else, 평소에는
장애가 없어도 동기 복제는 리전 간 RTT만큼 느리다. 지연(L)과 일관성(C) 중 하나를 고른다
DynamoDB global tables (MREC)
기본 모드. 리전마다 로컬 쓰기, 비동기 복제, 충돌은 last writer wins
PA / EL
DynamoDB global tables (MRSC)
정확히 3개 리전(복제본 3 또는 2 + witness), 다른 리전 1곳 이상에 동기 복제 후 응답
PC / EC
Aurora DSQL multi-Region
peered cluster 2개 + witness Region, 양쪽 읽기, 쓰기 모두 강한 일관성
PC / EC
Aurora Global Database
writer는 primary 1곳, secondary는 비동기 읽기 전용(일반적으로 lag 1초 미만)
쓰기 C / 읽기 L

일관성은 데이터마다 고른다

보장
어느 리전에서 읽어도 마지막으로 커밋된 쓰기가 보임
대가
쓰기, 강한 읽기 지연이 참여 리전 간 RTT에 비례
AWS 예
DynamoDB MRSC, Aurora DSQL multi-Region, Aurora write forwarding GLOBAL 모드
적합
결제 승인, 재고 차감처럼 중복이나 역전이 치명적인 데이터

아키텍처 한눈에 보기

Edge (global)
Amazon Route 53Route 53
Amazon CloudFrontCloudFront
AWS WAFWAF
↓ VPC origin (private) ↓
us-east-1PRIMARY, writer
Elastic Load Balancinginternal ALB
→
Amazon EKSEKS: order, payment, catalog, cart
us-west-2SECONDARY, reader
Elastic Load Balancinginternal ALB
→
Amazon EKSEKS: 동일 서비스 세트
↓ 리전별 데이터 계층, primary → secondary 복제 ↓
Amazon Aurora
Aurora PostgreSQL Global DB
order, payment
Amazon DocumentDB
DocumentDB Global Cluster
catalog
Amazon ElastiCache
ElastiCache Valkey
Global Datastore
Amazon MSK
MSK
이벤트
Amazon DynamoDB
DynamoDB Global Tables
idempotency
Amazon OpenSearch Service
OpenSearch
검색
Amazon S3
S3
이미지, 아카이브

쓰기는 한 곳, 읽기는 가까운 곳

us-east-1 (primary)
쓰기writer instance
읽기로컬 reader
접속global writer endpoint
→ 비동기 복제storage 기반, 일반적으로 1초 미만
← write forwardingsecondary에서 받은 쓰기를 primary로 전달
us-west-2 (secondary)
쓰기forwarding 또는 primary 직접
읽기로컬 reader
접속cluster reader endpoint
충돌 없음
writer가 하나라 충돌 해결 로직이 필요 없음
서부 쓰기는 느리다
forwarding된 쓰기는 리전 간 RTT를 그대로 부담, SERIALIZABLE 격리 미지원
연결 상한
forwarding 세션은 primary writer max_connections의 기본 25%까지만 허용

리전마다 독립된 EKS 클러스터

클러스터는 리전 단위
EKS 컨트롤 플레인은 리전 서비스. 리전마다 독립 클러스터를 두고 서로 의존하지 않게 설계
버전을 맞춘다
두 리전 모두 같은 Kubernetes 버전. 2026-10 기준 최신은 1.37 (EKS 출시 2026-10-01)
GitOps로 같은 매니페스트
하나의 Git 저장소에서 두 클러스터로 배포, 리전 차이는 overlay 값(endpoint, ARN)으로만
이미지도 리전마다
ECR 리전 간 복제로 각 리전에서 로컬 pull. 다른 리전 레지스트리에 의존하지 않음
IAM은 Pod Identity
IAM role은 글로벌, association은 클러스터마다 생성. 리전별 리소스 ARN 범위 확인
흡수 용량 계획
한 리전이 빠지면 나머지가 전체 부하를 받는다. 페일오버 순간 스케일아웃에 기대지 않도록 여유 확보

CIDR은 겹치지 않게, 티어는 셋으로

10.0.0.0/16
us-east-1 VPC
10.1.0.0/16
us-west-2 VPC
10.2~10.15
향후 리전, 환경 예약
겹치면 못 붙인다
VPC peering은 CIDR이 하나라도 겹치면 생성 불가, TGW도 목적지가 모호해짐
IPAM으로 할당
Amazon VPC IPAM pool에서 리전별로 나눠주면 중복을 사전에 차단
Pod IP도 계산
VPC CNI는 Pod마다 VPC IP를 쓰므로 노드 수가 아니라 Pod 수로 산정

리전 간 연결, 세 가지 선택지

static route만
peering attachment를 향한 static route를 TGW route table에 직접 추가 (BGP 전파 없음)
암호화, 백본
리전 간 트래픽은 AWS 백본에서 AES-256으로 암호화, 인터넷을 거치지 않음
리전을 넘지 못하는 것
SG 참조, Route 53 Resolver 기반 상대 리전 private DNS 해석은 peering 너머로 동작하지 않음
상한
TGW 쌍당 peering 1개, TGW당 peering 기본 50개, MTU 8500
# us-east-1 TGW route table (us-west-2는 대칭)
10.0.0.0/16 → vpc attachment (local VPC, propagation)
10.1.0.0/16 → peering attachment (static, us-west-2)

NAT 대신 endpoint, 손익분기 계산

Gateway endpoint (무료)
S3, DynamoDB. ECR 이미지 레이어도 S3에서 받으므로 항상 생성
Interface endpoint (EKS 필수군)
ecr.api, ecr.dkr, sts, eks-auth(Pod Identity), logs
gateway endpoint의 한계
peered VPC의 다른 리전, TGW, 온프렘에서는 사용할 수 없음. 리전마다 따로 생성
3,000 GB
5개
3 AZ
-
NAT 경유 처리 요금
-
Interface endpoint 요금
-
손익분기 트래픽
us-east-1, 월 730시간 기준: NAT 처리 $0.045/GB, endpoint $0.01/AZ-hour + $0.01/GB. NAT 시간 요금은 다른 egress가 있어 유지된다고 가정, 리전 1개 기준

이번 블록의 아키텍처 결정

영역결정대가, 주의점
데이터 패턴Write-Primary / Read-Local, 데이터별 일관성 선택서부 쓰기는 리전 간 RTT 부담
진입CloudFront → VPC origin → internal ALBVPC에 IGW 필요, ALB SG는 CloudFront prefix list 또는 VPC origin SG만 허용
컴퓨트리전별 독립 EKS, 같은 버전, GitOps 배포흡수 용량을 평소에 확보
네트워크겹치지 않는 /16, 3-tier, public 티어엔 NAT만Pod IP까지 포함해 CIDR 산정
리전 간TGW peering + static routeSG 참조, DNS 해석 불가. 리전 3개 이상이면 Cloud WAN 검토
AWS APIGateway endpoint 항상, EKS 필수 interface endpoint리전마다 생성, 손익분기 확인
IAMEKS Pod Identityassociation은 클러스터마다

Key Takeaways

1목적이 패턴을 정한다
가용성, 지연, 레지던시 중 무엇이 목표인지가 Active-Active와 Active-Passive를 가른다
2평소의 지연이 진짜 비용
PACELC 관점에서 데이터마다 Strong, Session, Eventual을 고른다
3쓰기는 한 곳에 모은다
Write-Primary / Read-Local은 충돌을 없애는 대신 서부 쓰기 지연을 받아들인다
4네트워크는 처음에 정한다
겹치지 않는 CIDR, private 진입, TGW static route는 나중에 바꾸기 가장 어렵다

Knowledge Check

Q1: Aurora PostgreSQL write forwarding의 기본 consistency_mode인 SESSION의 의미는?
Q2: Transit Gateway inter-Region peering에 대해 옳은 것은?
Q3: CloudFront VPC origin 뒤 internal ALB의 SG 설정으로 옳은 것은?

Thank You

Block 1: Multi-Region Foundation 완료

← 목차로 돌아가기 다음: Data Sync & Replication →

Block 2: Data Sync & Replication

쓰기는 어디서 받고, 복제는 얼마나 늦으며, 장애 때 무엇을 잃는가

서비스마다 맞는 저장소가 다르다

CloudFront→ VPC origin→ internal ALB→ EKS 서비스 (private subnet)→ 데이터 계층은 모두 private 연결로만 접근
Amazon AuroraAurora PostgreSQL Global DB
order, payment, inventory: ACID 트랜잭션, 단일 writer
Amazon DocumentDBDocumentDB Global Cluster
catalog, user-profile, review: 유연한 문서 스키마, 읽기 위주
Amazon ElastiCacheElastiCache for Valkey
cart, session, rate-limit: 밀리초 응답, 원본이 아닌 사본
Amazon MSKAmazon MSK
order.created 등 도메인 이벤트, saga 조율의 백본
Amazon DynamoDBDynamoDB Global Tables
payment idempotency key, 주문 상태 조회처럼 key 단위 접근
Amazon Aurora DSQLAurora DSQL (대안)
양 리전 쓰기와 RPO 0이 꼭 필요한 SQL 워크로드의 선택지
원칙
저장소마다 복제 모델, 지연, 장애 시 손실이 다릅니다. 서비스별로 "쓰기 위치"와 "허용 RPO"를 먼저 정하고 저장소를 고릅니다.

복제 모델은 세 가지, 대가는 지연

← 강한 일관성, 쓰기 지연 큼쓰기 지연 작음, 결과적 일관성 →
① 동기 multi-Region
  • 커밋 전에 다른 리전에 기록
  • Aurora DSQL, DynamoDB MRSC
  • RPO 0, 대신 쓰기마다 리전 간 왕복
② 단일 writer + 비동기 복제
  • 쓰기는 primary 한 곳
  • Aurora Global DB, DocumentDB Global, Valkey Global Datastore
  • 읽기는 로컬, 장애 시 lag만큼 손실 가능
③ multi-writer + 비동기
  • 모든 리전이 로컬 쓰기
  • DynamoDB MREC, MSK active-active
  • 충돌 해소 규칙(last writer wins)을 앱이 수용
설계 규칙
쓰기 경로는 일관성을, 읽기 경로는 지연을 우선합니다. 같은 서비스 안에서도 쓰기와 읽기의 모델이 다를 수 있습니다.

Aurora Global DB: 스토리지가 복제한다

us-east-1 (primary)
Writer 1대
Reader 최대 15 - s대
order, payment, inventory
→ 스토리지 복제
보통 1초 미만 →
us-west-2 (secondary)
Reader 최대 16대
로컬 읽기
write forwarding (선택)
s = secondary 리전 수. secondary가 늘면 primary의 reader 한도가 그만큼 줄어듭니다 (예: secondary 10개면 primary reader 5대).
secondary 최대 10개 리전
예전 자료의 "최대 5개"는 구버전 한도. 리전마다 클러스터는 1개
Aurora PostgreSQL 18.3 이상 지원
Global DB는 PG 11부터 18까지 지원. 2026-09 기준 최신 minor는 18.6, 17.11
global writer endpoint
switchover, failover 후에도 같은 이름이 새 primary를 가리킴. 앱 연결 문자열 변경 불필요
비동기라는 사실은 변하지 않음
RPO는 보통 초 단위의 0이 아닌 값입니다. 그래서 다음 슬라이드들의 write forwarding, switchover, RPO 상한 설정이 필요합니다.

Write Forwarding은 대신 전달한다

us-west-2
order-service
secondary reader endpoint
→ DML 전달 →
us-east-1
primary writer 실행, 커밋
→ 스토리지 복제 →
us-west-2
변경 반영 후 읽기
DML만 전달되고, 전달된 쓰기마다 리전 간 왕복이 붙습니다. statement가 많은 긴 트랜잭션보다 가끔 발생하는 짧은 쓰기에 적합하며, 지연 수치는 반드시 실측하세요.
한 줄 정리
write forwarding은 "secondary에서 쓰기 가능"이 아니라 "secondary가 대신 전달"입니다. write-heavy 서비스는 primary 리전에 둡니다.

Switchover만 RPO 0이다

동기화 후 전환 → RPO 0
대상 secondary가 완전히 따라잡을 때까지 기다린 뒤 primary를 read-only로 바꾸고 승격
보통 30초 미만
Aurora PostgreSQL 16.8, 15.12, 14.17, 13.20 이상에서 read/write 복구 시간
조건
모든 클러스터가 정상이고 major, minor 버전이 같아야 함. DR 훈련, 리전 순환, failback 용도
# --region 은 현재 primary 리전
# USW2_ARN: us-west-2 secondary 클러스터 ARN
aws rds switchover-global-cluster \
  --region us-east-1 \
  --global-cluster-identifier shop-global \
  --target-db-cluster-identifier "$USW2_ARN"

DSQL: 두 리전 모두 쓰고 동기 커밋

us-east-1
peered cluster
읽기, 쓰기
⇄ 동기 복제 ⇄
us-west-2
peered cluster
읽기, 쓰기
us-east-2 (witness)
전체 사본 없음, 쓰기 로그로 내구성과 quorum 제공
multi-Region 클러스터는 같은 Region set 안에서만 구성 (북미 set: us-east-1, us-east-2, us-west-2, 캐나다 2개 리전). 대륙 간 구성은 미지원.
RPO 0, 수동 failover 없음
한 리전이 사라져도 나머지 리전이 계속 처리. 가용성 설계 목표 99.999%
OCC, Repeatable Read 고정
잠금 대신 커밋 시 충돌 검사. 충돌한 트랜잭션은 앱이 재시도
트랜잭션 한도
3,000 rows, 10 MiB, DDL 1개, 연결 1시간, SAVEPOINT 미지원
private 연결
AWS PrivateLink interface endpoint와 IAM 인증 토큰으로 접속

DocumentDB: 카탈로그는 읽기 로컬로

us-east-1 (primary)
writer + replica
catalog, review 쓰기
→ 스토리지 기반
물리 복제 →
us-west-2 (secondary)
replica 최대 16대
상품 조회 로컬 처리
예전 자료 정정
"oplog 기반, 2초 이내"가 아니라 전용 인프라의 스토리지 기반 물리 복제이며 일반적인 lag은 1초 미만입니다. 관측: GlobalClusterReplicationLag (secondary)
secondary 최대 10개
쓰기는 primary cluster endpoint로만
switchover (RPO 0)
모든 리전이 같은 engine version일 때만
failover
AllowDataLoss, 미복제분은 스냅샷으로 보존 시도
제약
v3.6과 db.t3, db.t4g, db.r4 인스턴스는 global cluster 미지원

Valkey 캐시: 읽기만 로컬

us-east-1: primary (active)
읽기, 쓰기
cart, session 쓰기 지점
→ 비동기 복제, 보통 1초 미만
(전송 구간 암호화) →
us-west-2: secondary (passive)
읽기 전용
장애 시 수동 promote
secondary 최대 2개
primary 1 + 다른 리전 secondary 2. Valkey 7.2 이상 (최신 9.0, 2026-05)
자동 failover 없음
secondary promote는 직접 실행, 보통 1분 미만. 미복제 쓰기는 손실 가능
동일 구성 강제
node type, engine version, shard 수가 같아야 함. replica 수만 리전별로 다르게
지원 노드
large 이상 M5, M6g, M7g, M8g, R5, R6g, R6gd, R7g, R8g, C7gn, C8gn
장바구니 설계 포인트
us-west-2 사용자의 장바구니 쓰기는 us-east-1 primary까지 갑니다. 캐시는 원본이 아니라 사본으로 두고, 잃어도 재구성 가능한 데이터만 둡니다.

캐시 일관성은 TTL로 관리한다

Cache-aside
miss 때 DB 조회 후 SET. 읽기 많고 쓰기 적은 상품 정보
Write-through
쓰기 시 DB와 캐시를 함께 갱신. 세션, 장바구니
Event-driven invalidation
MSK 이벤트(product.updated)로 키 삭제. 비동기 일관성 허용
TTL 만료
자연 만료 후 재적재. 모든 키의 최종 안전장치

MSK Replicator: offset도 복제

us-east-1 MSK (source)
order.created, payment.completed
IAM 인증 9098, multi-VPC private connectivity
→ 비동기 →
MSK Replicator (us-west-2에 생성)
topic, config, ACL, consumer offset 복제
→
us-west-2 MSK (target)
standby consumer
장애 시 producer 전환
topic 이름
PREFIXED(기본) 또는 identical. identical이면 전환 시 앱 설정 변경 불필요
offset 동기화
LEGACY(기본, 단방향), ENHANCED(양방향 Replicator 필요)
시작 위치, 한도
기본 latest, 생성 후 변경 불가. Replicator당 750 topic
중복은 필연
비동기라 전환 시 재처리 발생. consumer를 idempotent하게
관측
ReplicationLatency(ms), MessageLag, target 리전 AWS/Kafka
Kafka 4.x는 KRaft 전용
3.9가 ZooKeeper 마지막. Standard 4.1, Express 4.2 지원

DynamoDB: MREC와 MRSC 중 고른다

active-active 비동기
모든 replica가 로컬 쓰기, 보통 1초 안에 전파 (SLA 없음)
last writer wins
같은 item을 거의 동시에 쓰면 item 단위로 마지막 쓰기가 이김. 충돌은 기록되지 않음
리전 수 제한 없음
파티션 내 모든 리전에 replica 가능. 트랜잭션은 리전 간 묶여서 복제되지 않음
관측
리전 쌍별 ReplicationLatency 평균, 최대로 최악의 lag 확인

장애 때 무엇을 잃는가: RPO 표

저장소복제 모델평시 lag계획 전환비계획 장애 시 손실볼 메트릭
Aurora PostgreSQL Global DB단일 writer, 비동기보통 1초 미만switchover RPO 0lag만큼 (rds.global_db_rpo로 상한)AuroraGlobalDBRPOLag
Aurora DSQL multi-Region동기, active-active커밋에 포함불필요0OCC 재시도율
DocumentDB Global단일 writer, 비동기보통 1초 미만switchover RPO 0lag만큼GlobalClusterReplicationLag
DynamoDB MRECmulti-writer, 비동기보통 1초 이내, SLA 없음불필요미전파 쓰기는 해당 리전 복구 전까지 없음ReplicationLatency
DynamoDB MRSC동기, 3개 리전쓰기에 포함불필요0충돌 예외 수
공통 방어선
손실 0이 아닌 행이 대부분입니다. 모든 쓰기 API를 idempotent하게 만들고, 표의 메트릭에 RPO 기준 알람을 겁니다.

Knowledge Check (1/2)

Q1: Aurora write forwarding에서 기본값이며, 내 세션이 방금 쓴 값을 바로 읽게 해 주는 consistency_mode는?
Q2: 리전 장애로 failover-global-cluster --allow-data-loss를 실행했다. 맞는 설명은?

Knowledge Check (2/2)

Q3: 두 리전에서 같은 결제 요청이 재시도될 때 이중 결제를 막는 저장 방식은?

Key Takeaways

① 쓰기 위치부터 정한다
서비스별 쓰기 리전과 허용 RPO를 정의한 뒤 저장소와 복제 모델을 고릅니다
② 계획 전환과 장애 전환은 다르다
switchover는 RPO 0, failover는 lag만큼 손실. global writer endpoint로 연결을 고정
③ RPO 0은 동기 모델에서만
Aurora DSQL, DynamoDB MRSC. 대신 쓰기 지연, OCC 재시도, 트랜잭션 제약을 수용
④ idempotency와 lag 알람
MSK 재처리, 캐시 stale, 비동기 손실을 견디려면 idempotent API와 lag 메트릭 알람이 기본

Thank You

Block 2: Data Sync & Replication 완료

← 목차로 돌아가기 다음: Traffic Routing & Edge →

Block 3: Traffic Routing & Edge

공개 입구는 CloudFront 하나, 리전 선택은 Edge에서, 절체 스위치는 데이터 플레인에

공개 입구는 CloudFront 하나뿐

사용자
브라우저, 앱
mall.example.com
Amazon Route 53Route 53
alias → CloudFront
→
Edge: 유일한 공개 입구
Amazon CloudFrontCloudFront
AWS WAFWAF web ACL
→
Behavior 분기
/static/*
→ S3 (OAC)
/api/*
→ CF Function
→ origin group
→
VPC origin
Elastic Load Balancinginternal ALB
us-east-1 (primary)
internal ALB
us-west-2 (secondary)
→
EKS 서비스
Amazon EKSorder, payment
catalog, cart
금지 목록
internet-facing LB, compute의 public IP, 보안 그룹의 0.0.0.0/0 및 ::/0 ingress. 우회 경로가 하나라도 있으면 WAF와 Edge 정책이 무력화됩니다.

리전 선택은 DNS가 아니라 Edge에서

판단 근거
recursive resolver IP, 또는 EDNS0 client subnet이 있으면 잘린 client IP. 회사 resolver가 다른 대륙이면 엉뚱한 리전이 나올 수 있음
latency 데이터
일정 기간 측정값 기반이라 바뀔 수 있음. 이번 주 Oregon이 다음 주 다른 리전이 될 수 있음 (실시간 측정 아님)
요금
latency 질의 $0.60/M, 표준 질의 $0.40/M. CloudFront로 가는 alias 질의는 무료
VPC origin과의 관계
VPC origin은 ALB ARN에 묶임. DNS 응답을 바꿔도 다른 리전 ALB로 가지 않으므로 공개 경로의 리전 선택은 Edge에서 해야 함
한 줄 정리
공개 경로는 Edge가 리전을 고르고, Route 53 latency는 private hosted zone의 내부 서비스 이름처럼 DNS가 직접 스위치인 곳에 씁니다.

헬스체크는 internal ALB를 못 본다

판정 규칙
전 세계 checker 중 18% 초과가 healthy라고 보고하면 healthy
간격, 임계값
간격 10초(fast, 유료 옵션) 또는 30초, 생성 후 변경 불가. 연속 실패 1~10 (기본 3)
HTTP(S) 기준
TCP 연결 4초 이내, 연결 후 2초 이내 2xx/3xx. HTTPS 체크는 인증서를 검증하지 않음
VPC 내부 대상
checker는 VPC 밖에 있음. internal ALB는 CloudWatch alarm 기반 health check로 감시
3회
60초
-
감지 (주기 × 횟수)
-
DNS 전환 근사 (+TTL)
AWS 블로그의 근사식 Failover = TTL + Interval × Threshold. resolver가 TTL을 지키지 않거나 alarm 평가 지연이 있으면 더 길어집니다. 요금: AWS endpoint 체크 $0.50/월, 옵션 기능(HTTPS, fast 등)마다 $1.00/월.

절체 스위치는 데이터 플레인에 둔다

on/off 스위치
routing control 상태가 Route 53 health check로 노출되어 failover 레코드를 움직임
클러스터
5개 리전 엔드포인트로 상태 조회, 변경. 한 리전이 장애여도 다른 엔드포인트 사용
safety rule
"최소 1개 ON" 같은 assertion, gating 규칙으로 두 리전을 동시에 끄는 실수 방지
요금
클러스터 $2.50/시간 (계정당 최대 2개). 여러 routing control을 한 클러스터에
한 줄 정리
장애 시 control plane API(레코드 편집, 배포)에 기대지 말고, 미리 만든 스위치의 상태만 바꾸세요.

Behavior: 캐시할 것과 안 할 것

동적 API: 캐시 끄고, 함수가 리전을 고른 origin group으로

PathPattern: /api/* TargetOriginId: og-api # origin group (alb-use1, alb-usw2) CachePolicy: Managed-CachingDisabled OriginRequestPolicy: Managed-AllViewerExceptHostHeader AllowedMethods: [GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE] ViewerProtocolPolicy: redirect-to-https FunctionAssociations: - EventType: viewer-request Function: mr-region-router # KVS 연결, 앞 슬라이드 코드

버전이 붙은 정적 자산: 길게 캐시, S3는 OAC로만

PathPattern: /static/* TargetOriginId: s3-assets # OAC, 버킷 public access 차단 CachePolicy: Managed-CachingOptimized # 기본 TTL 1일 AllowedMethods: [GET, HEAD] Compress: true ViewerProtocolPolicy: redirect-to-https # 파일명에 해시를 넣어 배포마다 새 URL (invalidation 최소화)

SPA 라우팅: custom error response 대신 함수로 rewrite

PathPattern: "*" # default behavior TargetOriginId: s3-assets CachePolicy: Managed-CachingOptimized FunctionAssociations: - EventType: viewer-request Function: spa-rewrite # 확장자 없는 경로 → /index.html # CustomErrorResponses(403/404 → 200 index.html)는 배포 전체에 적용되어 # /api/*의 404까지 HTML 200으로 바꿔 버림

Origin 잠금: VPC origin과 SG

Internet gateway
VPC에 붙어 있어야 함. "인터넷 트래픽을 받는 VPC" 표시용이며 origin 라우팅에는 쓰지 않음
private subnet IP
CloudFront가 service-managed ENI를 만들 IPv4 1개 이상 (dual-stack이면 IPv6도)
ALB Active 후 생성
VPC origin은 Deployed까지 최대 15분. ALB, NLB, EC2 지원 (GWLB, TLS listener NLB 불가)
AZ 예외
us-east-1은 use1-az3 제외, us-west-2는 전체 지원. ALB subnet AZ ID를 확인
한 줄 정리
ALB를 private subnet에 숨기고, SG는 VPC origin Service SG에서 443만 받으면 WAF를 우회할 경로가 사라집니다.

Origin Shield: 캐시될 때만 이득

Edge
서울, 도쿄, 시애틀 PoP
→
Regional edge cache
여러 REC
→
Origin Shield
us-east-1
(origin과 같은 리전)
→
Origin
ALB, S3
origin마다 지정
origin group이면 alb-use1은 us-east-1, alb-usw2는 us-west-2로 각자 Shield 리전을 둠
동적 요청은 항상 과금
PUT, POST, PATCH, DELETE와 TTL 3600초 미만 또는 캐시 비활성 GET, HEAD는 Shield가 언제나 추가 계층
캐시 요청은 일부만 과금
Shield와 같은 리전의 REC에서 오는 요청은 Shield를 건너뛰어 무과금, 다른 리전 REC에서 올 때만 과금
판단
/static/*은 켬. /api/*는 모든 요청이 과금 대상이므로 지연 개선을 측정한 뒤 결정. 미국 요금 $0.0075/10K

Origin failover는 GET만 구한다

조건
설정한 상태 코드(예: 500, 502, 503, 504) 또는 연결 실패, timeout. viewer 메서드가 GET, HEAD, OPTIONS일 때만
stateless
health 상태를 기억하지 않아 모든 요청이 primary부터 시도. 장애 중에는 요청마다 지연이 붙음
timeout 튜닝
connection attempts 1~3 (기본 3) × connection timeout 1~10초 (기본 10) → 기본값이면 넘어가기까지 최대 약 30초
쓰기 요청은 앱이 책임
POST /api/orders는 primary 오류가 그대로 사용자에게 갑니다. idempotency key + client retry, 그리고 KVS 활성 리전 전환으로 새 요청을 옮기세요.

WAF 순서: 넓게 거르고 좁게 본다

0IP allow/block set운영팀 명시 결정, 가장 먼저
1Anti-DDoS AMRAWSManagedRulesAntiDDoSRuleSet, 상단 배치, scope-down 금지
2Rate-basedwindow 60, 120, 300, 600초, 약 10초마다 평가
3IP reputationAmazonIpReputationList, AnonymousIpList
4ExploitCommonRuleSet, KnownBadInputs, SQLiRuleSet
5Bot Control + label 규칙scope-down 적용, 뒤에서 label로 예외 처리
scope CLOUDFRONT
CloudFront용 web ACL은 us-east-1에서 생성. ALB용 REGIONAL ACL과 별개
WCU
web ACL 기본 1,500 WCU. 초과 시 500 WCU마다 $0.20/M 요청 추가
요금
web ACL $5/월, 규칙 또는 rule group $1/월, 요청 $0.60/M

Bot Control은 Count로 시작한다

Common
자기 신고형 봇, 검증된 봇 분류. 구독 $10/월, 월 10M 요청 무료, 이후 $1/M
Targeted
정교한 봇 탐지. 월 1M 요청 무료, 이후 $10/M. flat-rate 플랜에서는 미지원
verified bot
검색 엔진 등은 차단하지 않고 bot:verified label만 붙임. web bot auth label은 v4.0 이상
한 줄 정리
Bot Control의 결정은 label로 남기고, 차단은 우리가 쓴 다음 규칙이 하게 만드세요.

CloudFront와 GA는 층이 다르다

항목Amazon CloudFrontCloudFrontAWS Global AcceleratorGlobal Accelerator
계층, 프로토콜L7 HTTP(S), WebSocketL4 TCP, UDP
입구 주소DNS 이름 (Anycast static IP 옵션 있음)고정 anycast IPv4 2개
캐시, WAFEdge 캐시, WAF를 Edge에서 적용캐시 없음, WAF는 뒤쪽 ALB에 붙임
리전 분배origin group, CloudFront Functiontraffic dial, endpoint weight, 자동 failover
private originVPC origin (ALB, NLB, EC2)internal ALB endpoint (client IP 보존)
과금요청 + 전송량, AWS origin fetch 무료$0.025/시간 + DT-Premium (미국→미국 $0.015/GB) + public IPv4
한 줄 정리
HTTP라면 CloudFront, 비HTTP라면 GA. 둘 다 쓰면 공개 입구가 두 개가 된다는 사실부터 인정하세요.

Edge 비용: 종량제 vs 정액제

100M
5TB
-
종량제 합계 (월)
$1,000
flat-rate Premium (월)
이 구조는 Premium이 필요합니다.
VPC origin은 Business 이상, 자동 origin failover와 Origin Shield는 Premium 전용. Premium 기본 한도 500M 요청, 50TB. 추정 가정: 미국 viewer, 전송량 첫 10TB 구간, 1TB=1,000GB 근사, WAF 규칙 8개, Anti-DDoS AMR, 로그, Route 53, ARC 제외.

Knowledge Check

Q1: POST /api/orders 처리 중 primary origin이 503을 반환하면?
Q2: VPC origin 뒤 internal ALB의 SG 소스로 가장 엄격한 것은?
Q3: Bot Control(Common)을 켠 뒤 모바일 앱 요청이 막혔다. 원인과 대응은?

Key Takeaways

입구는 하나
CloudFront → VPC origin → internal ALB. internet-facing LB, public IP, 0.0.0.0/0 없음
리전은 Edge가 고름
CloudFront Function + KVS + createRequestOriginGroup(), DNS latency는 내부 이름에
감지와 스위치 분리
internal ALB는 alarm 기반 health check, 절체는 routing control, Region switch
failover는 GET만
쓰기 API는 idempotency key, 재시도, 활성 리전 전환으로 보완
Bot Control은 Count부터
모바일 앱, webhook을 label로 확인한 뒤 Block
비용은 구조로 결정
VPC origin + failover + Shield면 flat-rate는 Premium. 종량제와 실측 비교

Thank You

Block 3: Traffic Routing & Edge 완료

← 목차로 돌아가기 다음: DR & Failover Automation →

Block 4: DR & Failover Automation

전략 선택 → 장애 시나리오 → 자동화 파이프라인 → 훈련과 검증

DR 전략은 비용과 RTO의 교환

Backup & RestoreRPO 시간 단위, RTO 24시간 이내
복구 리전에 백업만 둡니다. 장애 시 IaC로 인프라를 만들고 데이터를 복원합니다.
Pilot LightRPO 분 단위, RTO 수십 분
데이터 복제와 DB는 상시 가동, 애플리케이션 서버는 필요할 때 배포합니다.
Warm StandbyRPO 초 단위, RTO 분 단위
축소된 전체 스택이 항상 실행됩니다. 장애 시 확장 후 트래픽을 받습니다.
Multi-site Active/ActiveRPO 거의 0, RTO 0에 근접
두 리전이 동시에 트래픽을 처리합니다. 비용과 데이터 일관성 설계 부담이 가장 큽니다.
비용, 복잡도 낮음RTO, RPO 짧음 →
이 쇼핑몰의 선택 order, payment, inventory는 Aurora Global Database, catalog, cart는 global cluster, Global Datastore. 모두 쓰기는 us-east-1 한 곳인 Warm Standby이고, 양 리전 쓰기(Active/Active)는 DSQL multi-Region을 택할 때의 선택지입니다.

서비스마다 RTO, RPO가 다르다

서비스데이터 스토어 (현재)us-east-1 장애 시RPO 성격전환 방식
order, payment, inventoryAurora PostgreSQL Global DBus-west-2 읽기 유지, 쓰기 중단계획 0, 비계획은 복제 lag만큼failover (allow-data-loss), global writer endpoint (앱 적용 필요)
catalogDocumentDB global clusterus-west-2 읽기 유지초 단위 (비동기)managed failover, 보통 1분 내 승격
cart, sessionElastiCache (Valkey) Global Datastoreus-west-2 읽기 유지복제 지연 보통 1초 미만수동 promote, 보통 1분 미만
이벤트MSK, Replicator 미구성us-west-2에 이벤트 없음미처리 이벤트가 us-east-1에 남음Replicator 구성 전에는 전환 불가
정적 자산S3 CRR + RTC복제본에서 읽기99.99% 객체 15분 이내 설계CloudFront origin group
컴퓨트리전별 EKS 클러스터us-west-2 확장statelessGitOps + 용량 확장
가장 약한 고리 이벤트 경로입니다. MSK Replicator가 없어 DB가 넘어가도 order.created 같은 미처리 이벤트는 us-east-1에 남습니다.

장애는 세 가지 크기로 온다

us-east-1 전체가 응답하지 않는 경우입니다.

계층자동사람이 결정
엣지 (CloudFront)GET/HEAD/OPTIONS는 origin group으로 자동 재시도쓰기 요청의 활성 리전 전환
catalog (DocumentDB)없음failover-global-cluster 실행
cart (ElastiCache)없음failover-global-replication-group 실행
order, payment (Aurora Global DB)없음failover-global-cluster 실행

결론: 읽기는 살아남지만 주문, 결제는 DB 승격과 쓰기 리전 전환이 끝날 때까지 멈춥니다. 순서를 정한 Runbook이 필요합니다.

리전은 정상이고 한 데이터 스토어만 문제인 경우입니다.

상황먼저 할 일
catalog 장애캐시된 상품 정보로 읽기 전용 모드
cart 장애세션 쿠키와 DB로 장바구니 재구성, 쓰기는 재시도 큐
데이터 손상 (잘못된 쓰기)복제본에도 전파되므로 PITR, 스냅샷으로 복구
리전 전환 판단"DB 하나 때문에 모든 서비스를 옮길 가치가 있는가"

원칙: 리전 전체 전환보다 해당 서비스만 degrade하는 것이 먼저입니다.

노드, AZ 수준인지 클러스터 전체인지 먼저 구분합니다.

범위대응
노드, AZKarpenter 노드 교체, ARC zonal shift로 해당 AZ 우회
drain 중PodDisruptionBudget 없으면 replica가 동시에 빠질 수 있음
클러스터 전체GitOps로 같은 상태인 us-west-2 클러스터를 EKS resource scaling block으로 확장
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: order-api-pdb spec: minAvailable: 2 selector: matchLabels: app: order-api

Aurora failover는 쓰기부터 멈춘다

1. 쓰기 중지order, payment API 쓰기 차단
→
2. lag 기록AuroraGlobalDBRPOLag로 손실 범위 추정
→
3. failoverus-west-2에서 allow-data-loss
→
4. 쓰기 확인global writer endpoint로 재개
aws rds failover-global-cluster --region us-west-2 \ --global-cluster-identifier shop-global \ --target-db-cluster-identifier "$USW2_ARN" --allow-data-loss
RPO는 0이 아니다
동기화를 기다리지 않으므로 그 순간의 복제 lag만큼 잃습니다. 보통 초 단위입니다.
write fencing은 best effort
old primary가 잠시 쓰기를 받을 수 있어 1단계가 필수입니다. DNS 캐시 TTL은 5초 수준으로 둡니다.
연결 문자열은 그대로
앱이 global writer endpoint를 쓰면 새 primary를 자동으로 가리킵니다. 단 parameter group, alarm은 상속되지 않습니다.

RPO는 상한을 걸고 유실분은 대사한다

항목내용
파라미터rds.global_db_rpo (Aurora PostgreSQL, 초 단위, 최솟값 20초)
동작모든 secondary의 RPO lag이 값을 넘으면 primary 커밋을 멈추고, 하나라도 따라잡으면 재개
관측AuroraGlobalDBRPOLag (ms) 알람으로 상한에 다가가는 것을 먼저 감지
2리전 주의secondary 쪽 parameter group은 기본값 유지: failover 직후 커밋 정지 방지
결정커밋 가용성과 손실 상한 중 무엇을 택할지 결제 담당 팀과 합의
단계내용
스냅샷old primary 회복 시 rds:unplanned-global-failover-... 스냅샷 생성 시도
비교스냅샷을 별도 클러스터로 복원해 새 primary에 없는 마지막 트랜잭션 확인
외부 원장PG 승인 내역과 대조해 주문 레코드 없는 승인 건 처리
재반영DynamoDB Global Tables의 idempotency key로 중복 없이 재처리
항목내용
구성peered cluster 2개 (us-east-1, us-west-2) + witness 리전 (us-east-2)
얻는 것두 리전 모두 쓰기, 동기 커밋으로 RPO 0, failover 명령 불필요
대가쓰기마다 리전 간 왕복, OCC 충돌 재시도, 트랜잭션당 3,000 rows, 10 MiB 한도
적용 범위기존 Aurora 앱 일괄 이관이 아니라 RPO 0이 필수인 원장 테이블부터 검토

입구는 CloudFront 하나로 고정

사용자HTTPS
→
CloudFrontFunction + KeyValueStore
→
Origin group
VPC originus-east-1 internal ALB
VPC originus-west-2 internal ALB
→
EKS리전별 클러스터
읽기: 자동 재시도
primary origin이 오류를 내면 GET, HEAD, OPTIONS 요청은 secondary origin으로 재시도됩니다.
쓰기: 넘어가지 않음
POST, PUT, DELETE는 origin failover 대상이 아닙니다. 활성 리전 값을 KeyValueStore에 두고 Function이 origin group을 고릅니다.
노출 범위
ALB는 internal, 보안 그룹은 CloudFront VPC origin 쪽만 허용합니다. 컴퓨트에 public IP를 두지 않습니다.

전환은 Region switch plan으로

CloudWatch alarm또는 수동 실행
→
Manual approval실행 승인
→
병렬 실행 (us-west-2)
EKS resource scaling
Aurora Global Database
DocumentDB global cluster
Lambda: ElastiCache promote
→
Custom LambdaKVS 활성 리전 변경
활성화 리전에서 실행
Region switch는 리전별 data plane을 두고, 활성화하는 리전에서 plan을 실행합니다. 장애 리전에 의존하지 않습니다.
기본 제공 block
EC2 ASG, ECS, EKS, Aurora Global Database, DocumentDB, Neptune, RDS replica, ARC routing control, Route 53 health check 등.
없는 것은 Lambda로
ElastiCache Global Datastore와 CloudFront KVS 변경은 custom Lambda block으로 넣습니다.

Lambda는 재실행해도 안전하게

import boto3 GDS, RG, REGION = "<global-datastore-id>", "cart-usw2", "us-west-2" ec = boto3.client("elasticache", region_name=REGION) # 승격할 리전 def handler(event, context): g = ec.describe_global_replication_groups(GlobalReplicationGroupId=GDS, ShowMemberInfo=True)["GlobalReplicationGroups"][0] if any(m["ReplicationGroupId"] == RG and m["Role"].lower() == "primary" for m in g["Members"]): return {"status": "already-primary"} # 재실행해도 안전 # Status로 막지 않음: 리전 장애 중에는 available이 아닐 수 있음 ec.failover_global_replication_group( GlobalReplicationGroupId=GDS, PrimaryRegion=REGION, PrimaryReplicationGroupId=RG) return {"status": "failover-started"}
세 파라미터 필수, 상태로 막지 않는다 장애 중에는 Status가 available이 아닐 수 있어 "이미 primary인가"만 확인합니다.

DocumentDB 장애는 failover로

정상 상태의 global cluster에서 primary 리전을 옮깁니다. 훈련, 리전 순환, failover 후 원복에 씁니다.

aws docdb switchover-global-cluster \ --region us-east-1 \ --global-cluster-identifier mall-catalog-global \ --target-db-cluster-identifier arn:aws:rds:us-west-2:<ACCOUNT>:cluster:catalog-usw2

모든 secondary가 동기화될 때까지 기다린 뒤 전환하므로 데이터 손실이 없습니다. 모든 리전의 engine version이 같아야 하고, 역할 전환은 수 분까지 걸릴 수 있습니다.

primary 리전 장애 시 secondary를 승격합니다. 명령은 승격할 리전에서 실행합니다.

aws docdb failover-global-cluster \ --region us-west-2 \ --global-cluster-identifier mall-catalog-global \ --target-db-cluster-identifier arn:aws:rds:us-west-2:<ACCOUNT>:cluster:catalog-usw2 \ --allow-data-loss

실행 전 GlobalClusterReplicationLag(ms)가 가장 작은 secondary를 고릅니다. 보통 1분 안에 승격되며 복제되지 않은 쓰기는 유실될 수 있습니다. 이전 primary는 회복 후 자동으로 secondary로 재합류합니다.

점검 항목내용
writer endpoint바뀜: 앱이 새 endpoint를 쓰는지 확인
parameter group, alarm상속되지 않음: 새 primary에 다시 구성
다른 secondary재구축에 수 분에서 수 시간
유실분rds:docdb-unplanned-global-failover-... snapshot을 수동 snapshot으로 복사
원복원래 리전 회복 후 switchover로 수행

cart 캐시는 사람이 승격한다

1. 쓰기 차단cart API read-only
→
2. promote 실행us-west-2를 primary로
→
3. endpoint 전환앱 설정 갱신
→
4. 재합류 확인이전 primary는 secondary
aws elasticache failover-global-replication-group \ --global-replication-group-id <global-datastore-name> \ --primary-region us-west-2 \ --primary-replication-group-id cart-usw2
자동 failover 없음
Global Datastore는 리전 장애 시 스스로 승격하지 않습니다. 승격은 보통 1분 미만입니다.
전환 중 cart
secondary는 읽기 전용이라 담기, 수정이 실패합니다. 클라이언트에서 재시도 큐로 받습니다.
유실 대비
복제 지연은 보통 1초 미만. 마지막 변경분은 세션 쿠키나 주문 DB에서 재구성합니다.

로드맵: 데이터 먼저, 자동화 다음

P0 데이터 보호
  • MSK Replicator 구성 (us-west-2), consumer offset 동기화
  • Aurora RPO lag 알람, rds.global_db_rpo 정책, global writer endpoint 적용
  • failover 유실분 대사 절차 (스냅샷, PG 승인 대조)
P1 전환 자동화
  • Region switch plan: 승인, EKS scaling, Aurora Global DB, DocumentDB block
  • custom Lambda: ElastiCache promote, CloudFront KVS 변경
  • 전 서비스 PodDisruptionBudget
P2 검증 루프
  • 분기별 FIS 훈련과 Region switch 리허설
  • Resilience Hub 평가를 CI/CD에 연결
  • 실측 RTO/RPO로 목표표 갱신
  • RPO 0 필수 테이블은 DSQL multi-Region 검토
숫자는 비워 둔다 "자동화로 RTO 2분" 같은 목표는 P2 훈련에서 잰 값으로 채웁니다.

훈련 없는 DR은 가설일 뿐

FIS scenario library의 시나리오로, 한 AZ의 전원 손실 증상을 주입합니다.

항목내용
대상EC2 (EKS, ECS 노드 포함), EBS, ASG, 서브넷, ElastiCache, RDS
용량 제약 재현지정한 IAM role, ASG의 새 인스턴스 시작을 막아 "용량 확보 실패"까지 시험
관찰 지표Karpenter 노드 교체, zonal shift, DB writer 이동 시간
주기 (예시)월 1회 비운영, 분기 1회 운영: 조직 기준으로 조정

실험 리전에서 대상 리전으로 가는 트래픽을 막고 복제를 멈춥니다. 기본 지속 시간 3시간(disruptionDuration).

Action효과
aws:network:route-table-disrupt-cross-region-connectivity서브넷의 대상 리전 경로 차단
aws:network:transit-gateway-disrupt-cross-region-connectivityTGW 경유 트래픽 차단
aws:s3:bucket-pause-replicationS3 복제 일시 정지
aws:dynamodb:global-table-pause-replicationGlobal Table 복제 정지

AWS 관리형 서비스 트래픽은 막히지 않을 수 있습니다. DocumentDB, ElastiCache 복제는 이 시나리오로 끊기지 않으니 별도로 검증합니다.

단계내용
실행분기 1회 plan을 실제로 실행해 us-west-2로 전환, switchover로 원복
측정감지까지, 승인까지, 전환 완료까지 시간과 유실 데이터
장애 중 전환FIS로 장애를 주입한 상태에서 plan 실행
회고PIR로 기록하고 Runbook과 plan을 함께 갱신
기능내용
Resiliency policyApplication, Infrastructure, Availability Zone, Region별 RTO/RPO 목표
Assessment구성 요소를 분석해 목표 충족, 위반과 추정 RTO/RPO 표시
Recommendations개선안별 예상 RTO, RPO, 비용과 alarm, FIS 실험, SOP 제안
CI/CD 연동구성 변경이 목표를 깨는지 배포 전에 확인

Key Takeaways

1. 기본은 단일 writer
지금은 전부 단일 writer Warm Standby. RPO 0이 필수인 테이블만 DSQL Active/Active를 검토합니다.
2. 가장 약한 고리가 RTO, RPO
MSK Replicator가 없으면 DB가 넘어가도 이벤트는 남습니다. Aurora failover는 lag만큼 잃고 rds.global_db_rpo로 상한을 둡니다.
3. 엣지는 읽기만 자동
CloudFront origin failover는 GET, HEAD, OPTIONS만. 쓰기는 KVS의 활성 리전 값으로 전환합니다.
4. 전환은 plan으로
Region switch는 활성화 리전에서 실행됩니다. 기본 block이 없는 단계는 멱등 Lambda로 채웁니다.
5. 명령을 구분
Aurora, DocumentDB 장애는 쓰기 중지 후 failover + allow-data-loss, 계획 전환과 원복은 switchover. ElastiCache는 수동 promote.
6. 숫자는 훈련으로
FIS 시나리오와 Region switch 리허설로 실측한 RTO/RPO만 목표표에 씁니다.

Knowledge Check

Q1: us-east-1 장애 시 DocumentDB global cluster를 us-west-2로 넘기는 올바른 방법은?
Q2: CloudFront origin group이 secondary origin으로 재시도하는 요청은?
Q3: us-east-1 장애로 Aurora Global Database를 failover했을 때 맞는 설명은?

Thank You

Block 4: DR & Failover Automation 완료

← 목차로 돌아가기 다음: Observability & Operations →

Block 5: Observability & Operations

수집 → 샘플링 → 저장 → 리전 간 상관 → 비용 → 부하 테스트 → SLO → 출시 준비

텔레메트리는 리전 안에서 끝낸다

사용자 경로
CloudFront유일한 public 진입점
VPC origin → internal ALBX-Amzn-Trace-Id 추가
→
App Pod
OTel SDKW3C traceparent 전파
order, paymentcatalog, cart
→
Collector 2계층
Agent (DaemonSet)traceID로 분배
Gateway (Deployment)tail_sampling
→
리전 로컬 backend
Amazon Managed Service for Prometheus
Tempo on S3 또는 CloudWatch (X-Ray)
같은 스택을 두 번 us-east-1과 us-west-2에 동일하게 배포합니다. 한 리전 장애가 다른 리전의 관측을 끊지 않도록 합니다.
조회만 전역으로 Grafana가 두 리전 data source를 함께 조회합니다. 데이터 이동은 필요한 경우에만 합니다.

Collector는 2계층으로 나눈다

노드 로컬에서 받아 trace ID 기준으로 Gateway에 분배합니다.

receivers: otlp: protocols: grpc: { endpoint: "${env:MY_POD_IP}:4317" } processors: memory_limiter: { check_interval: 1s, limit_percentage: 80, spike_limit_percentage: 25 } exporters: loadbalancing: routing_key: traceID protocol: otlp: { timeout: 1s } resolver: k8s: { service: otel-gateway.observability, ports: [4317] }
processors: memory_limiter: { check_interval: 1s, limit_percentage: 80, spike_limit_percentage: 25 } batch: {} # 기본값 8192건, 200ms tail_sampling: decision_wait: 30s # 기본값 30s num_traces: 50000 # 기본값 50000 expected_new_traces_per_sec: 2000 policies: - name: keep-errors type: status_code status_code: { status_codes: [ERROR] } - name: keep-slow type: latency latency: { threshold_ms: 500 } - name: baseline type: probabilistic probabilistic: { sampling_percentage: 10 }
extensions: sigv4auth/traces: { region: us-east-1, service: xray } exporters: otlphttp/xray: compression: gzip traces_endpoint: https://xray.us-east-1.amazonaws.com/v1/traces auth: { authenticator: sigv4auth/traces } service: extensions: [sigv4auth/traces] pipelines: traces: receivers: [otlp] processors: [memory_limiter, tail_sampling, batch] exporters: [otlphttp/xray]

X-Ray OTLP endpoint는 Transaction Search 활성화가 전제입니다. us-west-2 Gateway는 region과 endpoint만 바꿉니다.

tail sampling은 같은 인스턴스가 전제

에러 trace
100%
status_code = ERROR
느린 trace
100%
latency ≥ 500ms
나머지
10%
probabilistic baseline
예시 보존량
약 12.7%
에러 1%, 느림 2% 가정: 3% + 97% × 10%
같은 trace, 같은 인스턴스
trace의 모든 span이 한 Collector에 모여야 판단할 수 있습니다. Gateway를 늘리면 앞단에 traceID 라우팅이 필수입니다.
메모리 = 유입률 × 대기
2,000 trace/s × 30s = 60,000개가 메모리에 머뭅니다. num_traces 50000보다 크면 판단 전에 밀려납니다.
늦게 오는 span
decision_wait 뒤에 도착한 span은 이미 내려진 결정을 따릅니다. 비동기 consumer가 긴 trace는 대기 시간을 따로 봅니다.

백엔드는 Tempo와 X-Ray 중 고른다

항목2026-10-15 기준
수집 경로OTLP endpoint, SigV4 (service: xray)
저장 위치CloudWatch Logs aws/spans log group
검색모든 span을 attribute로 검색, trace 최대 10,000 span
인덱싱수집 span의 1%는 trace summary로 무료 인덱싱
수집 요금$0.35/GB (첫 10 TB, us-east-1 list price)
항목내용
저장S3에 Parquet 블록 (storage.trace.backend: s3)
쓰기 경로3.0에서 ingester 제거, block-builder와 live-store
배포 모드monolithic은 Kafka 불필요, microservices는 Kafka 호환 큐
질의TraceQL, 구조 연산자 >>, >, ~
service graphmetrics-generator service_graphs, 기본 비활성
질문Transaction SearchTempo
운영 부담관리형클러스터 직접 운영
샘플링100% 수집 후 일부 인덱싱tail sampling 결과만 저장
AWS 연계Application Signals, SLOGrafana 생태계
비용 성격GB당 수집 요금S3 + 컴퓨트

X-Ray SDK와 daemon은 2026-02-25부터 maintenance mode입니다. 보안 수정만 릴리스되며 X-Ray 서비스 자체는 계속 지원됩니다. 신규 계측은 OpenTelemetry(ADOT SDK 또는 upstream SDK)로 시작합니다.

trace ID는 리전을 넘어 이어진다

us-west-2
cart-servicetrace 시작, cloud.region = us-west-2
→
traceparent 헤더
같은 trace IDTGW peering 경유 사설 호출
→
us-east-1 (write primary)
order → paymentspan은 us-east-1 backend에 저장
A. 리전별 저장 (기본) 각 리전 backend에 그대로 두고 trace ID로 양쪽을 조회합니다. 장애 격리가 우선입니다.
B. sampled 사본만 이동 Gateway에 원격 exporter를 하나 더 둡니다. tail sampling 뒤라 바이트가 작지만 리전 간 전송 요금이 붙습니다.
# B 구성에서 한 Tempo에 두 리전 span이 있을 때 { resource.cloud.region = "us-west-2" } >> { resource.cloud.region = "us-east-1" && status = error }

OAM은 리전을 넘지 않는다

Cross-account observability (OAM)
  • sink와 link는 같은 Region에서만 연결
  • 계정당 Region별 sink 1개
  • monitoring 계정당 source 최대 100,000
  • metrics, logs, traces를 복제 없이 조회
Centralization rules
  • Organizations 기반, source Region 여러 개 선택
  • destination Region + backup Region
  • @aws.account, @aws.region 필드 보존
  • 첫 사본 무료, 추가 사본 $0.05/GB
Cross-account cross-Region 대시보드
  • metrics와 alarm 위젯용
  • logs와 traces는 지원하지 않음
  • alarm은 telemetry가 있는 Region에 생성
시나리오 적용 monitoring 계정에 us-east-1, us-west-2 sink를 각각 만들고, 로그는 Centralization rule로 us-east-1에 모으며 backup Region을 us-west-2로 둡니다.

변동비는 바이트 수가 정한다

300
100
50
20
13%
us-east-1 list price, 2026-10-15 Pricing API 기준, 30일/월, 730시간/월. 리전 간 $0.02/GB, NAT $0.045/GB와 $0.045/시간, Logs $0.50 또는 $0.25/GB, span $0.35/GB, EKS $0.10/시간.
-
리전 간 전송
-
NAT 데이터 처리
-
로그 수집
-
span 수집
-
고정: EKS 2개 + NAT GW 6개
-
변동비 중 리전 간 비중
-
월 합계 (컴퓨트, DB, 스토리지 제외)

최적화는 바이트를 줄이는 일

S3 gateway endpoint즉시
S3 트래픽을 NAT에서 빼면 GB당 $0.045 처리 요금이 사라집니다. gateway endpoint는 추가 요금이 없습니다.
sampled span만 이동즉시
원격 리전 exporter는 tail sampling 뒤에 둡니다. 원본 span을 리전 간으로 보내지 않습니다.
복제 범위 축소설계
MSK Replicator topic 필터, 리전 로컬로 재생성 가능한 cache와 search index는 복제 대신 재구축을 검토합니다.
로그 class 분리설계
감사, 디버그 로그는 IA class($0.25/GB)로 보냅니다. IA에서 쓸 수 없는 기능은 사전에 확인합니다.
컴퓨트 통합튜닝
stateless tier NodePool은 Spot과 Graviton을 허용하고 Karpenter consolidation을 켭니다. 할인 폭은 시점마다 다릅니다.
측정이 먼저상시
Cost Explorer를 usage type으로 묶어 USE1-USW2 전송, NAT, DataProcessing을 주 단위로 봅니다.

병목은 클라이언트 기본값에 숨는다

Valkey cluster mode
cluster-aware client가 아니면 다른 shard 키에서 MOVED 응답을 처리하지 못합니다.
조치 Python은 RedisCluster 계열 client로 교체
Go pgxpool
MaxConns 기본값은 max(4, NumCPU)입니다. 작은 Pod에서는 4개라 고부하에서 대기열이 생깁니다.
조치 pool_max_conns를 부하 테스트로 정하고 명시
PyMongo / Motor
maxPoolSize 기본 100입니다. Pod 수 × 100이 DocumentDB 연결 한도를 넘지 않는지 계산합니다.
조치 HPA 최대 Pod 수 기준으로 pool 크기 역산
Go http.Transport
DefaultMaxIdleConnsPerHost는 2입니다. 내부 API 호출이 많으면 연결을 계속 새로 맺습니다.
조치 공유 Transport에 MaxIdleConnsPerHost 상향
Quick win catalog의 GET 응답에 짧은 TTL cache를 두고, CloudFront cache behavior로 상품 조회 경로를 캐싱해 origin 요청을 줄입니다.

부하 테스트는 네 가지 모양으로

export const options = { vus: 100, duration: '10m', thresholds: { http_req_duration: ['p(95)<300', 'p(99)<500'], http_req_failed: ['rate<0.001'], 'http_req_duration{endpoint:orders}': ['p(95)<500'], }, }; // 트래픽 비율: browse 60, search 20, purchase 15, seller 5
export const options = { stages: [ { duration: '5m', target: 100 }, { duration: '10m', target: 500 }, { duration: '10m', target: 1000 }, { duration: '5m', target: 0 }, ], thresholds: { http_req_duration: [{ threshold: 'p(99)<1000', abortOnFail: true, delayAbortEval: '1m' }], }, };
export const options = { scenarios: { spike: { executor: 'ramping-arrival-rate', startRate: 500, timeUnit: '1s', preAllocatedVUs: 500, maxVUs: 3000, stages: [ { duration: '2m', target: 500 }, { duration: '1m', target: 2000 }, { duration: '5m', target: 2000 }, { duration: '2m', target: 500 }, ], }, }, }; // 관찰: Karpenter 노드 준비 시간, HPA 반응, 5xx

vus: 300, duration: '4h'로 4시간 유지합니다. 지표 대신 추세를 봅니다.

관찰 대상누수 신호
Pod 메모리시간에 비례해 증가
DB 연결 수pool 한도에 수렴 후 대기
goroutine, thread반환되지 않고 누적
tail sampling 메모리num_traces 도달 후 drop

SLO는 burn rate로 경보한다

99.9%
가용성, 30일
p95 < 300ms
전체 latency
p99 < 500ms
orders, payments
43.2분
30일 error budget
Application Signals SLO
period-based와 request-based 두 방식입니다. SLO당 burn rate 설정은 최대 10개입니다.
burn rate
baseline error rate = 100% - 목표입니다. 99.9%면 0.1%가 기준이고, 1보다 크면 budget을 빨리 씁니다.
리전별 SLO
SLO는 리전마다 따로 둡니다. 전역 평균은 한 리전 장애를 희석해 경보를 늦춥니다.

P0 네 개가 출시를 막는다

P0 출시 차단, 데이터 보호Phase 1, 2주
인증 미들웨어 없음gateway가 누구의 호출이든 통과
event bus가 mock publishMSK consumer 7개가 이벤트를 못 받음
MSK Replicator 미구성리전 간 topic, consumer offset 동기화 없음
Aurora Global DB 전환 준비 미흡rds.global_db_rpo 미설정, global writer endpoint 미적용
완료 기준: 인증 통합 테스트, 이벤트 end-to-end trace, us-west-2 topic 복제 lag 확인
P1 운영 위험Phase 2, 4주
WAF Bot Control이 synthetic 차단모니터링 체크 실패, scope-down 필요
search가 문자열 비교 mockOpenSearch 연동 전
함께 처리: 클라이언트 기본값 4건 수정
P2 개선Phase 3, 2주
CI/CD 수동 배포두 리전 동시 배포 파이프라인
Phase 4 상시: k6 4개 프로필, SLO 튜닝, 비용 최적화

Key Takeaways

1. 리전 로컬 관측
텔레메트리는 리전 안에서 끝내고 조회만 전역으로 모읍니다.
2. Collector 2계층
traceID 라우팅 없이는 tail sampling을 확장할 수 없습니다.
3. OTel이 표준
X-Ray SDK는 maintenance mode, OTLP endpoint와 Transaction Search로 갑니다.
4. OAM은 리전 안
리전마다 sink, 리전 간 집계는 Centralization rule입니다.
5. 바이트가 비용
리전 간 $0.02/GB, NAT $0.045/GB. 측정하고 줄입니다.
6. 출시는 P0부터
gap, 성능, 부하 테스트, 비용 순서로 리전별 SLO에 맞춥니다.

Knowledge Check (1/2)

Q1: tail sampling Gateway를 여러 개로 늘릴 때 반드시 필요한 것은?
Q2: CloudWatch cross-account observability(OAM)에 대한 설명으로 맞는 것은?

Knowledge Check (2/2)

Q3: us-east-1 → us-west-2 리전 간 데이터 전송 list price는? (2026-10-15 기준)

Thank You

Multi-Region Architecture Deep Dive, 감사합니다

수고하셨습니다!

← 목차로 돌아가기