Skip to content

필사 모드: 이중화·삼중화 완전 가이드 — 99.999% 가용성의 비밀

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

"서버 하나가 죽으면 서비스도 죽는다" — 이게 단일 장애점(SPOF)입니다.

이중화, 삼중화는 이 SPOF를 제거하는 기술입니다. 은행, 증권, 항공 관제 시스템은 **삼중화**까지 하고, 우리가 매일 쓰는 클라우드 서비스도 **이중화** 이상으로 운영됩니다.

가용성(Availability) 숫자의 의미

가용성 = 정상 운영 시간 / 전체 시간 × 100%

| 가용성 | 등급 | 연간 다운타임 | 월간 다운타임 |

| -------- | ----------- | ------------- | ------------- |

| 99% | Two 9s | 3.65일 | 7.3시간 |

| 99.9% | Three 9s | 8.77시간 | 43.8분 |

| 99.99% | Four 9s | 52.6분 | 4.38분 |

| 99.999% | **Five 9s** | **5.26분** | **26.3초** |

| 99.9999% | Six 9s | 31.5초 | 2.6초 |

**핵심**: 99.9% → 99.99%로 올리는 건 8시간 → 52분. 비용은 10배 이상 증가!

이중화 (Redundancy) 패턴

1. Active-Standby (액티브-스탠바이)

정상 상태:

[Active 서버] ←── 모든 트래픽

[Standby 서버] (대기, 동기화만)

장애 발생:

[Active 서버] ✗ 장애 감지!

[Standby 서버] ←── 트래픽 전환 (Failover)

새 Active로 승격

Kubernetes에서 Active-Standby: StatefulSet + Leader Election

apiVersion: apps/v1

kind: StatefulSet

metadata:

name: redis-ha

spec:

replicas: 2 # 1 Active + 1 Standby

selector:

matchLabels:

app: redis

template:

spec:

containers:

- name: redis

image: redis:7

ports:

- containerPort: 6379

- name: sentinel # 장애 감지 + 자동 Failover

image: redis:7

command: ['redis-sentinel', '/etc/sentinel.conf']

**장점**: 리소스 효율적 (Standby는 최소 자원)

**단점**: Failover 시간 (수 초~수십 초 다운타임)

2. Active-Active (액티브-액티브)

정상 상태:

[서버 A] ←── 트래픽 50%

[서버 B] ←── 트래픽 50%

Load Balancer가 분산

장애 발생:

[서버 A] ✗ 장애!

[서버 B] ←── 트래픽 100% (자동)

Kubernetes Service = 자동 Active-Active

apiVersion: v1

kind: Service

metadata:

name: my-api

spec:

selector:

app: my-api

ports:

- port: 80

apiVersion: apps/v1

kind: Deployment

metadata:

name: my-api

spec:

replicas: 2 # 둘 다 Active!

template:

spec:

containers:

- name: api

image: my-api:latest

readinessProbe: # 장애 감지

httpGet:

path: /health

port: 8080

periodSeconds: 5

failureThreshold: 3 # 3번 실패 → 트래픽 제외

**장점**: 다운타임 거의 0 (이미 분산 중이므로)

**단점**: 데이터 동기화 복잡 (충돌 해결 필요)

3. N+1 / N+2 이중화

N+1: N대가 필요한데 1대 더 (최소 여유분)

[서버1] [서버2] [서버3] [+예비1]

→ 1대 죽어도 OK

N+2: N대가 필요한데 2대 더

[서버1] [서버2] [서버3] [+예비1] [+예비2]

→ 2대 동시에 죽어도 OK + 1대 점검 가능

2N: 전체를 2배로 (가장 비쌈)

[서버1] [서버2] [서버3] [서버4] [서버5] [서버6]

→ 반이 죽어도 OK (미션 크리티컬)

삼중화 (Triple Redundancy)

왜 삼중화?

이중화의 치명적 약점: **스플릿 브레인 (Split Brain)**

이중화에서 네트워크 단절 시:

[서버 A] ──✗── [서버 B]

"B가 죽었나? 내가 Active!" "A가 죽었나? 내가 Active!"

→ 둘 다 Active → 데이터 불일치 → 재앙!

삼중화 + 쿼럼으로 해결:

삼중화 (3노드 클러스터):

[노드 A]──[노드 B]──[노드 C]

네트워크 분할 시:

[노드 A] [노드 B]──[노드 C]

1표 (소수) 2표 (과반수 = 쿼럼!)

→ A는 자진 사퇴

→ B,C가 계속 서비스

→ 스플릿 브레인 방지!

쿼럼 공식: 과반수 = (N/2) + 1

3노드: 2표 필요 (1노드 장애 허용)

5노드: 3표 필요 (2노드 장애 허용)

7노드: 4표 필요 (3노드 장애 허용)

etcd (Kubernetes의 뇌) — 삼중화 필수!

etcd 3노드 클러스터 (Raft 합의 알고리즘)

1노드 죽어도 쿼럼(2/3) 유지 → 서비스 계속

2노드 죽으면 쿼럼 상실 → 읽기만 가능

kubeadm 기본 설정

apiVersion: kubeadm.k8s.io/v1beta4

kind: ClusterConfiguration

etcd:

local:

extraArgs:

initial-cluster: >-

etcd-0=https://10.0.0.1:2380,

etcd-1=https://10.0.0.2:2380,

etcd-2=https://10.0.0.3:2380

Raft 합의 알고리즘 (의사코드)

class RaftNode:

def __init__(self, node_id, peers):

self.state = "follower" # follower → candidate → leader

self.term = 0

self.voted_for = None

self.log = []

def request_vote(self):

"""리더 선출 — 과반수 투표 필요"""

self.state = "candidate"

self.term += 1

votes = 1 # 자기 자신

for peer in self.peers:

if peer.grant_vote(self.term, self.log):

votes += 1

if votes > len(self.peers) // 2: # 쿼럼!

self.state = "leader"

return True

return False

def replicate(self, entry):

"""데이터 복제 — 과반수 확인 후 커밋"""

self.log.append(entry)

acks = 1

for peer in self.peers:

if peer.append_entry(entry):

acks += 1

if acks > len(self.peers) // 2: # 쿼럼!

self.commit(entry) # 과반수 확인 → 안전하게 커밋

계층별 이중화 전략

전체 아키텍처

[사용자]

[DNS] ← Route 53 헬스체크 (다중 리전)

[CDN] ← CloudFront (글로벌 엣지)

[L4 LB] ← NLB x2 (Active-Active, AZ 분산)

[L7 LB] ← ALB x2 (Active-Active)

[웹 서버] ← Deployment replicas: 3+ (Active-Active)

[앱 서버] ← Deployment replicas: 3+ (Active-Active)

├──▶ [DB Primary] ──동기복제──▶ [DB Standby] (Active-Standby)

│ └── 비동기복제 ──▶ [DB Read Replica x2]

├──▶ [Redis Primary] ── [Redis Replica x2] (Sentinel)

└──▶ [MQ] ← RabbitMQ 3노드 (쿼럼 큐)

데이터베이스 이중화

[동기 복제] (Strong Consistency)

Primary ──COMMIT──▶ Standby

"양쪽 다 쓸 때까지 기다림"

장점: 데이터 손실 0

단점: 느림 (네트워크 RTT 추가)

[비동기 복제] (Eventual Consistency)

Primary ──COMMIT──▶ (나중에) Standby

"일단 Primary에만 쓰고 응답"

장점: 빠름

단점: 장애 시 최근 데이터 유실 가능 (RPO > 0)

[반동기 복제] (Semi-Sync)

Primary ──COMMIT──▶ Standby (1개만 확인)

MySQL 기본 + 금융권 선호

-- PostgreSQL Streaming Replication 설정

-- Primary (postgresql.conf)

-- wal_level = replica

-- max_wal_senders = 3

-- synchronous_standby_names = 'standby1'

-- Standby 확인

SELECT client_addr, state, sync_state

FROM pg_stat_replication;

-- client_addr | state | sync_state

-- 10.0.0.2 | streaming | sync

-- 10.0.0.3 | streaming | async

장애 복구 지표

RPO (Recovery Point Objective):

"얼마나 많은 데이터를 잃어도 되나?"

동기 복제: RPO = 0 (데이터 무손실)

비동기 복제: RPO = 수 초~수 분

RTO (Recovery Time Objective):

"얼마나 빨리 복구해야 하나?"

Active-Active: RTO ≈ 0

Active-Standby: RTO = 수 초~수 분

백업 복원: RTO = 수 시간

MTBF (Mean Time Between Failures):

장애 간 평균 시간 (길수록 좋음)

MTTR (Mean Time To Repair):

복구까지 평균 시간 (짧을수록 좋음)

가용성 = MTBF / (MTBF + MTTR)

비용 대비 가용성

가용성 │ 구성 │ 상대 비용

───────────┼───────────────────┼──────────

99% │ 단일 서버 │ 1x

99.9% │ 이중화 (1 리전) │ 2~3x

99.99% │ 삼중화 + 자동복구 │ 5~10x

99.999% │ 다중 리전 Active │ 10~50x

99.9999% │ 다중 리전 + DR │ 50~100x

**Q1.** Active-Standby와 Active-Active의 가장 큰 차이는?

||Active-Standby: 평시에 1대만 트래픽 처리, Failover 시 전환 지연 있음. Active-Active: 평시에 모두 트래픽 분산, 한 대 죽어도 나머지가 즉시 흡수 (거의 무중단)||

**Q2.** 스플릿 브레인(Split Brain)이란 무엇이고 어떻게 방지하나?

||네트워크 단절로 양쪽 모두 자신이 Active라고 판단하는 상태. 데이터 불일치 발생. 삼중화 + 쿼럼(과반수 투표)으로 방지 — 과반수를 얻지 못한 쪽이 자진 사퇴||

**Q3.** etcd가 3노드인 이유는? 4노드가 아닌 이유는?

||3노드: 1노드 장애 허용 (쿼럼 2/3). 4노드: 역시 1노드만 장애 허용 (쿼럼 3/4)으로 3노드와 같은데 비용만 증가. 홀수가 효율적||

**Q4.** RPO와 RTO의 차이는?

||RPO: 허용 가능한 데이터 손실량 (동기복제 = 0, 비동기 = 수초). RTO: 장애 발생부터 서비스 복구까지 허용 시간. 둘 다 짧을수록 좋지만 비용 증가||

**Q5.** 99.99%와 99.999% 가용성의 연간 다운타임 차이는?

||99.99% = 52.6분/년, 99.999% = 5.26분/년. 약 10배 차이이며 비용은 5~10배 이상 증가||

**Q6.** N+1과 2N 이중화의 차이는?

||N+1: 필요 대수(N) + 여유 1대 — 비용 효율적, 1대 장애 허용. 2N: 전체를 2배 — 비용 높지만 반이 죽어도 서비스 유지, 미션 크리티컬 시스템용||

**Q7.** 동기 복제와 비동기 복제를 각각 어떤 상황에서 쓰나?

||동기: 금융 거래, 결제 등 데이터 무손실 필수 (RPO=0). 비동기: 읽기 부하 분산, 분석용 복제 등 약간의 지연 허용 가능한 경우 (성능 우선)||

**Q8.** Raft 합의에서 리더 선출 과정을 설명하라.

||Follower가 리더 heartbeat를 못 받으면 Candidate로 전환 → term 증가 → 다른 노드에 투표 요청 → 과반수 득표 시 Leader 승격 → 클라이언트 요청 처리 시작||

현재 단락 (1/226)

"서버 하나가 죽으면 서비스도 죽는다" — 이게 단일 장애점(SPOF)입니다.

작성 글자: 0원문 글자: 5,131작성 단락: 0/226