infra
Platform

모듈 맵

[Database] Master-Slave 복제(Replication) 구축과 DB 고가용성(HA) 아키텍처

0 / 37 완료

펼치기
0 / 37 완료0%

Database · 35 / 37

[Database] Master-Slave 복제(Replication) 구축과 DB 고가용성(HA) 아키텍처

MySQL 복제 원리를 이해하고, RDS Multi-AZ/Read Replica가 이를 어떻게 대신하는지, 개발자가 주의해야 할 복제 지연 패턴을 익힙니다

🚨INCIDENT ALERT
HIGH

DB 서버 한 대에 모든 쓰기와 읽기를 맡기면 장애와 점검에 취약합니다. 복제와 고가용성 구성은 데이터를 여러 노드에 유지해 장애 영향을 줄이는 방법입니다. 다만 지연과 승격 절차를 이해하지 못하면 HA 구성이 오히려 혼란을 만듭니다.

이번 챕터에서 배울 것

복제를 직접 구축할 일은 거의 없지만, 원리를 알면 클라우드 RDS 옵션 선택과 복제 지연 버그를 이해할 수 있습니다.

  • 1복제가 왜 필요한가 — 고가용성(HA)과 읽기 스케일아웃
  • 2복제 원리 — 바이너리 로그, IO/SQL 스레드
  • 3RDS Multi-AZ vs Read Replica — 클라우드가 대신 해주는 것들
  • 4개발자가 주의해야 할 복제 지연(Replication Lag) 패턴
  • 5쓰기/읽기 분리 아키텍처 설계 원칙

DB 복제와 고가용성 — 개념 이해와 클라우드 활용

서비스가 커지면 두 가지 DB 문제가 생깁니다. 첫 번째: "DB 서버 하나가 죽으면 서비스 전체가 다운된다." 두 번째: "읽기 쿼리가 너무 많아서 DB가 버틸 수가 없다." 복제(Replication)는 이 두 문제를 동시에 해결하는 기술입니다.


OUTPUT
실행 결과를 확인할 수 있는 DB 콘솔 출력이 표시됩니다.
🔍실행 후 확인할 것
  • 복제 지연Primary와 Replica 사이 지연 시간이 허용 범위인지 확인합니다.
  • 읽기 라우팅지연에 민감한 조회가 Replica로 가지 않는지 봅니다.
  • 장애 전환Failover 후 애플리케이션 연결 문자열과 권한이 정상인지 점검합니다.
실습 환경 준비

💡개념

복제가 필요한 두 가지 이유

이유 1: 고가용성 (High Availability) — 단일 DB와 복제 구성의 장애 대응 차이입니다.

단일 DB:
  [웹서버] → [DB 서버 (장애!)] → 서비스 전체 다운


![복제가 필요한 두 가지 이유](/images/database/replication-ha/replication-architecture.png)

복제 구성:
  [웹서버] → [Primary DB] → 실시간 복제 → [Replica DB]
                  ↓ 장애 발생
             [Replica가 Primary로 승격] → 서비스 지속

이유 2: 읽기 스케일아웃 (Read Scale-out) — 읽기 트래픽을 Replica 여러 대로 분산합니다.

DAU 100만 서비스 — 쿼리 비율: 읽기 95%, 쓰기 5%

단일 DB:  [모든 쿼리] → [DB 서버 1대] → 병목
Read Replica:
  [쓰기 쿼리] → [Primary DB]
  [읽기 쿼리] → [Replica 1]
              → [Replica 2]
              → [Replica 3]  ← 읽기 부하를 N대로 분산

언제 복제가 필요한가:

  • 일일 방문자 수만 명 이상의 서비스
  • DB 다운 허용 시간이 수 분 이내인 서비스
  • 읽기 쿼리가 쓰기의 10배 이상인 경우
  • 분석/리포트 쿼리가 운영 DB에 부하를 주는 경우

💡개념

복제 원리 — 바이너리 로그와 두 개의 스레드

MySQL 복제가 어떻게 동작하는지 알면, 복제 지연이 왜 생기는지 이해할 수 있습니다.

Primary (Master)              Replica (Slave)
┌─────────────────┐           ┌──────────────────────────────┐
│  Client         │           │                              │
│  INSERT         │           │  1) IO Thread                │
│      ↓          │  binlog   │  ┌────────────────────┐      │
│  Binary Log     │──events──→│  │ Relay Log (디스크) │      │
│  (모든 변경 기록) │           │  └─────────┬──────────┘      │
└─────────────────┘           │            ↓                 │
                              │  2) SQL Thread               │
                              │  릴레이 로그 이벤트를         │
                              │  Replica DB에 순차 적용      │
                              └──────────────────────────────┘

핵심 포인트:

  • Primary는 모든 변경(INSERT/UPDATE/DELETE)을 Binary Log에 기록
  • Replica의 IO Thread가 이 로그를 가져와 Relay Log에 저장
  • SQL Thread가 Relay Log를 순차로 실행해서 Replica DB에 반영
  • IO Thread와 SQL Thread 사이에 항상 약간의 시간 지연이 존재
SQL
-- Replica에서 복제 상태 확인
SHOW REPLICA STATUS\G

-- 핵심 지표:
-- Replica_IO_Running: Yes      ← IO 스레드 정상
-- Replica_SQL_Running: Yes     ← SQL 스레드 정상
-- Seconds_Behind_Source: 0    ← 복제 지연 (초 단위)

💡개념

RDS Multi-AZ vs Read Replica — 클라우드가 대신 해주는 것

온프레미스에서는 MHA, ProxySQL, 3대의 서버, SSH 키 설정 등 복잡한 구축이 필요합니다. AWS RDS는 이것들을 클릭 몇 번으로 제공합니다.

┌────────────────────────────────────────────────────────┐
│  RDS Multi-AZ (고가용성)                                │
│                                                        │
│  Primary (us-east-1a)  ──동기 복제──  Standby (us-east-1b)  │
│      ↓ 장애 (60초 이내)                                │
│  자동 DNS 전환 → Standby가 Primary로 승격              │
│  (애플리케이션 재연결만 하면 됨)                        │
└────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────┐
│  RDS Read Replica (읽기 분산)                           │
│                                                        │
│  Primary ──비동기 복제──→ Read Replica 1               │
│                     └──→ Read Replica 2               │
│  - 쓰기: Primary 엔드포인트                            │
│  - 읽기: Replica 엔드포인트 (읽기 전용)                │
│  - 최대 5개까지 생성 가능                              │
└────────────────────────────────────────────────────────┘
구분Multi-AZRead Replica
목적고가용성 (HA)읽기 분산
복제 방식동기 (데이터 유실 없음)비동기 (지연 있음)
Standby 읽기불가 (대기만 함)가능 (읽기 전용)
자동 페일오버있음 (~60초)없음 (수동 승격)
추가 비용인스턴스 2배Replica 수만큼
언제 쓰나운영 DB 필수읽기 많은 서비스

Python
# 이런 코드가 문제를 만듭니다
def register_user(data):
    db_write.execute("INSERT INTO users ...", data)  # Primary에 쓰기
    user = db_read.query("SELECT * FROM users WHERE email = ?", data["email"])
    # ↑ Replica에서 읽기 → 복제 지연으로 방금 쓴 데이터가 아직 없을 수 있음!
    send_welcome_email(user)  # user가 None이면 에러

원인: 쓰기는 Primary, 읽기는 Replica — 복제 지연 때 문제 발생.

해결 패턴 1: 쓰기 직후 읽기는 Primary에서 — 복제 지연을 우회하는 가장 단순한 방법입니다.

Python
def register_user(data):
    db_write.execute("INSERT INTO users ...", data)
    # 방금 쓴 데이터는 Primary에서 읽기
    user = db_write.query("SELECT * FROM users WHERE email = ?", data["email"])
    send_welcome_email(user)

해결 패턴 2: 방금 INSERT한 ID 활용 (DB 왕복 없이) — Replica 조회 없이 INSERT 결과를 바로 씁니다.

Python
def register_user(data):
    result = db_write.execute("INSERT INTO users ...", data)
    user_id = result.lastrowid  # INSERT한 ID를 바로 활용
    # Replica에서 조회하지 않고 ID로 직접 처리
    send_welcome_email(user_id=user_id, email=data["email"])

설계 원칙: Read-Your-Writes 패턴 — 어떤 요청을 Primary, Replica로 보낼지 기준입니다.

Primary (쓰기 + 즉시 읽기 필요한 경우):
  - 회원가입 후 프로필 조회
  - 결제 후 주문 확인
  - 설정 변경 후 확인 화면

Replica (복제 지연 허용 가능한 조회):
  - 상품 목록/검색
  - 통계/대시보드
  - 다른 사용자의 게시물 조회
💼
실무 맥락
현업 패턴

개발자가 DB 복제 관련 알아야 하는 것

RTO/RPO — 장애 대응 기준 수립: 팀원과 공통 언어로 장애 허용 범위를 정의하는 방법입니다.

팀장: "우리 DB 죽으면 얼마나 버틸 수 있어요?"

RTO (Recovery Time Objective) — 복구 목표 시간
  - "서비스가 최대 X분 다운돼도 된다"
  - RDS Multi-AZ: ~60초 자동 페일오버

RPO (Recovery Point Objective) — 데이터 유실 허용 범위
  - "최대 X분치 데이터가 사라져도 된다"
  - RDS Multi-AZ (동기 복제): RPO ≈ 0 (데이터 유실 없음)
  - Read Replica (비동기 복제): RPO = 복제 지연만큼

ORM에서 읽기/쓰기 분리: Django, SQLAlchemy 등 ORM에서 읽기/쓰기 DB를 구분하는 설정 예시입니다.

Python
# Django
DATABASES = {
    'default': {  # 쓰기용 Primary
        'HOST': 'rds-primary.xxxxx.rds.amazonaws.com'
    },
    'replica': {  # 읽기용 Replica
        'HOST': 'rds-replica.xxxxx.rds.amazonaws.com'
    }
}

# 쓰기 직후 읽어야 하는 경우 using('default')로 강제
user = User.objects.using('default').get(id=user_id)

# 일반 조회는 replica 사용 (Router 설정 시 자동)
users = User.objects.all()  # → Replica로 자동 라우팅

복제 지연 모니터링 (CloudWatch): ReplicaLag 수치로 복제 상태를 판단하는 기준입니다.

RDS 메트릭: ReplicaLag (초 단위)
  - 0~1초: 정상
  - 1~10초: 주의 (쓰기 집중 작업 있는지 확인)
  - 10초 이상: 위험 (배치 작업, 대용량 마이그레이션 확인)

알람 설정: ReplicaLag > 30초 → SNS 알림

복제 원리를 알면 "왜 방금 저장한 데이터가 조회가 안 되지?"라는 버그의 원인을 즉시 파악하고, RDS 구성 시 Multi-AZ vs Read Replica 선택을 제대로 할 수 있습니다.

다음 모듈에서는 실시간 DB 모니터링 체계 구축과 슬로우 쿼리 슬랙 알림 설정 방법을 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

팀원이 'RDS Read Replica를 추가했으니 이제 DB Primary 장애가 나도 자동으로 서비스가 복구돼요'라고 했다. 무엇이 잘못된 이해인가?

Q2

방금 INSERT한 데이터가 Read Replica에서 조회했더니 없다. 원인과 해결책은?

Q3

복제 지연(Replication Lag)이 커질 때 가장 흔한 원인은?

Q4

개발자 관점에서 DB 복제를 사용할 때 가장 중요한 설계 원칙은?

0 / 4 답변

🧪 실습으로 확인하기

PostgreSQL 설치 및 기본 설정

초급

Ubuntu 서버에 PostgreSQL을 설치하고, 데이터베이스와 사용자를 생성한 뒤 외부 접속이 가능하도록 설정한다.

40📋 5단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

database고급 · 70
[Database] DB 연결 지연을 없애는 HikariCP 설정과 대기 성능 튜닝
Database 트랙 계속
linux입문 · 30
[Linux] 개발자가 왜 리눅스 서버와 커맨드라인을 반드시 배워야 하는가
Linux 트랙 시작점