본문으로 건너뛰기
yutils

multi-region 아키텍처는 어떻게 동작할까?

active-passive vs active-active, 동기 vs 비동기 복제와 write 충돌, 지리적 latency, DNS·health check 기반 failover, split-brain, data residency — region 을 넘나드는 운영의 실제 trade-off.

약 10분 읽기

"그냥 region 하나 더 띄우면 되지" — multi-region 은 그렇게 단순하지 않다. region 사이 거리는 빛의 속도라는 물리 한계를 가져오고, 데이터 복제는 동기 vs 비동기 사이에서 latency 와 일관성을 맞바꾼다. 이 가이드는 active-passive vs active-active, 복제 모델, failover, split brain, data residency 를 정리한다. region 의 복제 메커니즘은 별도 가이드(how-replication-actually-works), partition 시 일관성 선택은 how-the-cap-theorem-actually-works를 참조.

왜 multi-region 인가

동기 (한 region 만 운영) 의 한계:
1. 가용성 — region 전체 장애 (AWS us-east-1 대규모 outage 등) 시 전멸
2. latency — 지구 반대편 사용자에게 매 요청 수백 ms RTT
3. 규제 — EU 사용자 데이터는 EU 안에 두라 (GDPR data residency)
4. 재해 복구 — 단일 region 백업은 같은 재해에 함께 날아갈 수 있음

→ multi-region 의 동기는 이 4 가지 중 하나 이상.
   "그냥 빠르니까" 가 아니라 어느 동기인지 먼저 정해야 설계가 갈림.

핵심: 무엇을 위해 multi-region 인가가 토폴로지를 결정한다. 재해 복구만 필요하면 active-passive 로 충분하고, 전 세계 낮은 latency 가 목표면 active-active 가 필요하지만 비용·복잡도가 급증한다.

지리적 latency — 물리 한계

빛은 광섬유에서 약 200,000 km/s (진공의 2/3).
왕복(RTT) 은 거리 × 2 + 라우팅 오버헤드.

대략적 RTT (실측, 이상적 직선보다 큼):
  서울 ↔ 도쿄        ~30-40 ms
  서울 ↔ 싱가포르     ~70-90 ms
  서울 ↔ 미국 서부     ~130-160 ms
  서울 ↔ 미국 동부     ~180-200 ms
  서울 ↔ 유럽         ~230-280 ms

함의:
- 동기 복제를 멀리 떨어진 region 간에 걸면 매 write 가 그 RTT 를 먹음
- 서울-버지니아 동기 복제 = write 당 최소 ~180 ms 추가
- 이건 튜닝으로 못 줄임 — 광속은 협상 불가

Active-Passive (failover)

한 region 이 모든 트래픽을 받고(active), 다른 region 은 데이터만 복제받으며 대기(passive/standby). 장애 시 passive 를 active 로 승격.

         [사용자]
            │  (전부)
            ▼
       ┌─────────┐   비동기 복제   ┌──────────┐
       │ Primary │ ─────────────▶ │ Standby  │
       │ (us-east) │              │ (us-west) │
       └─────────┘   (대기, 무트래픽) └──────────┘

장점:
- write 충돌 없음 (한 곳만 write 받음)
- 구현·추론 단순 — 평소엔 사실상 단일 region
- standby 는 read replica 로도 활용 가능

단점:
- standby 자원이 평소엔 놀고 있음 (비용)
- failover 가 자동이 아니면 RTO(복구 시간) 가 수 분~수십 분
- 비동기 복제면 failover 시 마지막 몇 초의 write 손실 가능 (RPO > 0)

RTO / RPO — failover 의 두 지표

RPO (Recovery Point Objective): 얼마만큼의 데이터를 잃어도 되나
  - 동기 복제: RPO = 0 (손실 없음, latency 대가)
  - 비동기 복제 (lag 5 s): RPO ≈ 5 s 분량의 write

RTO (Recovery Time Objective): 복구까지 얼마나 걸려도 되나
  - 수동 failover: 사람이 깨서 승격 → 수 분~수십 분
  - 자동 failover: health check + 자동 승격 → 수십 초

이 둘이 SLA 와 비용을 결정. "RPO 0, RTO 0" 은 active-active 거나
매우 비싼 동기 + 자동 failover. 대부분은 둘 다 타협.

Active-Active (multi-master)

모든 region 이 동시에 read·write 를 받는다. 사용자는 가장 가까운 region 으로 라우팅 → 낮은 latency. 대가는 write 충돌.

  [아시아 사용자]        [미국 사용자]
       │                    │
       ▼                    ▼
  ┌─────────┐  양방향 복제  ┌─────────┐
  │ ap-east │ ◀──────────▶ │ us-east │
  └─────────┘              └─────────┘
   둘 다 write 받음 → 같은 행을 동시에 다른 값으로?

장점:
- 모든 사용자가 가까운 region (낮은 read·write latency)
- 한 region 장애 시 나머지가 즉시 흡수 (RTO 사실상 0)

단점:
- write 충돌 해결 필요 (아래 참조) — 가장 어려운 부분
- 복제 lag 동안 region 마다 다른 값을 볼 수 있음 (eventual)
- 강한 일관성을 원하면 cross-region 합의 필요 = latency 폭증

복제: 동기 vs 비동기

동기 (synchronous):
  write → 다른 region 이 ack 할 때까지 대기 → 그 다음 client 에 성공 반환
  - 일관성 강함 (RPO 0)
  - 매 write 가 cross-region RTT 를 먹음 (수십~수백 ms)
  - 원격 region 이 느리거나 끊기면 write 가 멈춤 (가용성 ↓)

비동기 (asynchronous):
  write → 로컬에 쓰고 즉시 성공 반환 → 백그라운드로 다른 region 복제
  - latency 작음 (로컬 속도)
  - 복제 lag 존재 → failover 시 마지막 write 손실 가능 (RPO > 0)
  - 원격 region 이 느려도 로컬 write 는 계속됨

준동기 (semi-sync):
  최소 1 곳 ack 만 기다림 (전부는 아님) — 절충안

멀리 떨어진 region 간 동기 복제는 거의 쓰지 않는다 — latency 가 사용자 체감을 망친다. 대부분의 multi-region 은 region 안은 동기(또는 quorum), region 사이는 비동기 로 계층을 나눈다.

Write 충돌 — active-active 의 핵심 난제

두 region 이 같은 데이터를 거의 동시에 수정:
  ap-east: user.name = "철수"   (t=0 ms)
  us-east: user.name = "John"   (t=5 ms)
  복제 lag 100 ms → 둘 다 "내가 먼저" 라고 믿음 → 충돌

해결 전략:
1. LWW (Last-Write-Wins): timestamp 큰 쪽 채택
   - 단순하지만 clock skew 에 취약 + 진 쪽 write 조용히 소실
2. 충돌 회피 (partition by region): 각 데이터는 한 region 만 write
   - 예: 사용자별 home region 지정 → 그 사용자 write 는 그 region 만
   - 충돌 원천 차단 (가장 실용적)
3. CRDT (Conflict-free Replicated Data Type): 수학적으로 병합 가능한 자료구조
   - 카운터·집합 등은 자동 병합 (순서 무관 수렴)
   - 임의 데이터엔 적용 어려움
4. 애플리케이션 머지: 충돌을 앱에 노출해 직접 해결 (예: Git 머지 충돌)

실전에서 가장 흔한 건 2번 (region 별 분할). "이 사용자/이 테넌트의 쓰기는 항상 이 region" 으로 라우팅하면 active active 의 이점(가까운 region)을 누리면서 충돌을 원천 제거한다.

Failover — DNS · health check

트래픽을 어느 region 으로 보낼지 결정하는 계층:

1. DNS 기반 (예: Route 53, Cloudflare):
   - health check 가 primary 를 감시
   - 죽으면 DNS 응답을 standby IP 로 교체
   - 문제: DNS TTL + resolver 캐시 → 전파에 수십 초~수 분
   - 그래서 TTL 을 짧게 (예: 60 s) 두지만 너무 짧으면 DNS 부하 ↑

2. Anycast (예: 같은 IP 를 여러 region 에서 광고):
   - BGP 라우팅이 가장 가까운 살아있는 region 으로 보냄
   - 전파 빠름 (DNS 캐시 우회) — CDN·edge 가 흔히 사용
   - 세션 affinity 보장 어려움

3. Global Load Balancer (예: GCP GLB, AWS Global Accelerator):
   - 단일 anycast 진입점 + 백엔드 health 기반 라우팅
   - failover 빠름, 운영 단순 (그러나 vendor lock-in)

health check 의 함정:
- 너무 민감하면 일시적 jitter 에 false failover (flapping)
- 너무 둔하면 진짜 장애 감지가 늦음
- "앱은 살아있는데 DB 만 죽음" → L7(애플리케이션) health check 필요

Split-brain — 가장 위험한 실패

network partition 으로 두 region 이 서로를 "죽었다" 판단:

  [us-east] ──✕── [us-west]   (region 간 링크 끊김, 둘 다 살아있음)

active-passive 에서:
  - us-west 가 "primary 죽었다" → 자신을 primary 승격
  - 그런데 us-east 도 멀쩡히 write 받는 중
  - → 두 primary 가 각자 write → 데이터 분기 (split-brain)
  - partition 회복 시 어느 쪽이 진실? → 충돌·손실

방지:
- 과반수(quorum) 기반 승격: 3rd 지역의 witness/arbiter 가 투표
  → 과반수 못 얻는 쪽은 승격 금지 (consensus 와 같은 원리)
- fencing: 옛 primary 를 강제 격리 (STONITH — "Shoot The Other Node
  In The Head") — 옛 primary 의 write 를 물리적으로 차단
- "2 개 region 만으로는 안전한 자동 failover 불가" — 동수 split 가능.
  최소 3 곳(또는 외부 arbiter)이 있어야 과반수 판정 가능

consensus·quorum 의 세부는 how-consensus-actually-works 참조.

Data residency — 규제 제약

일부 데이터는 법적으로 특정 지역을 떠나면 안 됨:
- GDPR (EU): EU 시민 개인정보는 적절한 보호 없이 EU 밖 이전 제한
- 중국·러시아·인도 등: 자국민 데이터 국내 저장 의무 (data localization)
- 금융·의료: 산업별 규제 (예: 한국 금융 데이터 국내)

설계 영향:
- "전 세계 단일 active-active 로 모든 데이터 복제" → 위반 가능
- 해결: 데이터를 region 에 고정(pinned) — EU 사용자 데이터는 EU region 만
  → 사실상 region 별 분할(sharding by geography)
- 메타데이터(non-PII)만 글로벌 복제, 민감 데이터는 지역 격리

→ data residency 가 있으면 active-active 의 "어디서나 모든 데이터" 가
   깨진다. 규제를 먼저 확인하고 토폴로지를 정해야 함.

토폴로지 비교

측면Active-PassiveActive-Active
write 위치한 region모든 region
write 충돌없음핵심 난제
read latency먼 사용자는 높음전부 가까움
RTO (failover)수 분~수십 분사실상 0
자원 효율standby 놀음전부 활용
복잡도낮음높음
적합재해 복구 위주글로벌 저latency 필수

흔한 함정

  • 동기 복제를 먼 region 에 거는 것 — 매 write 가 cross-region RTT 를 먹어 사용자 체감 latency 폭증. region 안은 동기, 사이는 비동기로 계층화.
  • 2 region 만으로 자동 failover — partition 시 동수 split → split-brain. 외부 arbiter/witness(3번째 지역) 없이는 안전한 자동 승격 불가.
  • DNS failover 가 즉시라는 가정 — TTL + resolver 캐시로 전파에 수 분. RTO 계산에 DNS 전파 시간 포함해야 함.
  • LWW 를 충돌 해결책으로 맹신 — clock skew 면 잘못된 write 가 이기고 진 write 는 조용히 소실. region 별 분할이 더 안전.
  • failover 를 실제로 테스트 안 함 — "되겠지" 는 장애 때 안 됨. 정기적 game day(의도적 region 차단 훈련) 필수.
  • data residency 무시 — 글로벌 복제가 규제 위반일 수 있음. 데이터를 region 에 고정해야 하는지 먼저 확인.
  • standby 가 실제로 동작하는지 검증 안 함 — 복제는 되는데 승격이 막혀 있거나 용량이 모자라면 failover 가 실패. standby 를 read replica 로라도 상시 사용해 검증.

마무리

multi-region 의 첫 질문은 "왜" 다 — 재해 복구, latency, 규제 중 무엇이냐가 토폴로지를 정한다. 재해 복구면 active-passive 로 충분하고, 글로벌 저latency 가 목표라야 active-active 의 복잡도(write 충돌, split-brain)를 감수할 가치가 생긴다.

물리 한계(광속)는 협상 불가다. 그래서 실용 설계는 region 안은 동기, region 사이는 비동기로 나누고, active-active 가 필요하면 데이터를 region 별로 분할해 충돌을 원천 제거한다. 그리고 failover 는 반드시 실제로 테스트한다 — 테스트 안 된 failover 는 failover 가 아니다.

가이드 목록으로