About

RDS Multi-AZ 로 바꾸기 전에 알 것 — 값은 2배, 스탠바이는 못 읽고, 순서가 중요하다

Single-AZ 본번 DB 를 Multi-AZ 로 옮기며 밟은 것: 한 번도 안 먹던 terraform 분기, 멈출 수 없는 스냅샷, 스토리지까지 2배

본번 RDS(PostgreSQL)를 Single-AZ 에서 Multi-AZ 로 옮겼다. 이 글을 읽으면 Multi-AZ 가 실제로 사 주는 것(장애 · 유지보수 때 짧아지는 정지)과 사 주지 않는 것(읽기 성능), 값이 어디서 두 배가 되는지, 전환을 어떤 순서로 해야 덜 아픈지를 정할 수 있다.

시작은 리뷰에서 받은 질문 하나였다. 「지금까지 Multi-AZ 로 안 한 이유가 있나요?」 찾아보니 이유가 없었다.

켜는 코드는 있었다. 한 번도 참이 된 적이 없을 뿐

terraform 에는 본번만 Multi-AZ 로 켜는 분기가 분명히 있었다.

locals {
  rds_multi_az = var.stage == "production"
}

variable "stage" {
  default = "staging"  # 본번 디렉터리인데 staging
}

tfvars 도 없고, Makefile 도 -var stage=... 를 넘기지 않았다. 그러니 rds_multi_az 는 늘 false 였다. 처음 구축할 때 넣은 default 가 몇 년을 살아남은 거다.

조건으로 켜지는 설정은 조건이 실제로 참이 되는지까지 봐야 한다. 코드에 적힌 것과 적용된 것은 다르다.

하나 더 있었다. 두 달 가까이 apply 가 없는 사이 스토리지 오토스케일링이 allocated_storage 를 코드 값의 두 배로 키워 놨다. 그대로 apply 했으면 terraform 이 스토리지를 줄이려다 실패했을 거다. RDS 스토리지는 늘리기만 된다. terraform plan 만 정기적으로 돌렸어도 둘 다 진작 보였다.

Multi-AZ 가 하는 일은 두 가지뿐

다른 AZ(같은 리전 안의 떨어진 데이터센터 묶음)에 스탠바이 인스턴스를 두고 동기식으로 복제한다.

  • 쓰기는 프라이머리와 스탠바이 양쪽에 기록돼야 커밋된다

  • 스탠바이는 읽을 수 없다. 기다리기만 한다

두 번째를 자주 오해한다. AWS 문서도 「읽기 확장 수단이 아니다, 스탠바이로 읽기 트래픽을 받을 수 없다」 고 적어 둔다. 이중화했으니 빨라지겠지? 안 빨라진다. 커밋마다 AZ 를 한 번 왕복하니 쓰기 지연은 오히려 조금 는다. 보통은 체감할 일이 없지만, 대량 INSERT · UPDATE 를 돌리는 배치에서는 쌓인다.

Multi-AZ instance this post Primary (AZ-a) sync Standby (AZ-b) reads: no auto failover: yes price: instance x2, storage x2 Read replica for read scaling Primary async Replica reads: yes auto failover: no (promote by hand) price: one more instance Multi-AZ DB cluster availability + reads Writer semi-sync Reader Reader reads: yes (2 readers) auto failover: yes storage x3, NVMe classes only

사 주는 것 ① 장애 때 자동 페일오버

AZ · 인스턴스 · 스토리지에 문제가 생기면 스탠바이가 승격되고, 엔드포인트의 DNS 가 새 프라이머리를 가리킨다. 앱 설정은 그대로 둬도 된다. 문서상 페일오버는 보통 60〜120초다.

다만 그 순간 기존 커넥션은 전부 끊긴다. 앱에 재연결 · 재시도가 없으면 그 1〜2분 동안 에러가 사용자에게 그대로 나간다. Multi-AZ 를 켰다고 앱이 저절로 튼튼해지지 않는다.

사 주는 것 ② 유지보수 정지가 짧아진다 — 실무에서는 이게 제일 크다

Single-AZ 에서 인스턴스 클래스를 바꾸면 정지 → 리사이즈 → 기동이다. 우리는 약 3분 멈췄다.

Multi-AZ 면 OS 패치를 스탠바이 먼저 → 승격 → 옛 프라이머리 순서로 한다. 문서상 그 페일오버는 보통 1분이 안 된다. 클래스 변경도 문서는 「Multi-AZ 면 다운타임을 줄일 수 있다」 고 적는다. 우리는 클래스를 Single-AZ 상태에서 바꿨기 때문에 Multi-AZ 쪽 숫자는 재지 않았다.

처음엔 엔진 마이너 버전 업그레이드도 이렇게 짧아질 줄 알았다. 아니었다. 문서를 다시 보니 엔진 업그레이드는 프라이머리와 스탠바이를 동시에 바꿔서 둘 다 멈춘다. 엔진 업그레이드의 정지를 줄이려면 Blue/Green Deployments 쪽을 본다.

그래도 OS 패치와 클래스 변경이 무섭지 않게 되는 것만으로 크다. 다운타임이 무서워 패치를 미루고, 미룬 패치가 쌓여 더 큰 작업이 되는 고리에서 빠져나온다.

사 주는 것 ③ 백업이 프라이머리를 멈추지 않는다

Single-AZ 에서 스냅샷을 뜨면 몇 초에서 몇 분 동안 I/O 가 멈춘다(문서). PostgreSQL · MySQL 의 Multi-AZ 는 스탠바이에서 뜨니 프라이머리 I/O 가 멈추지 않는다.

이번에 이걸 정면으로 맞았다. 작업 전에 보험으로 수동 스냅샷을 떴는데, 볼륨 대역폭이 이미 포화라 수십 GB 에 40분쯤 걸렸다. 그동안 인스턴스 상태가 backing-up 이라 변경 요청이 거부됐다.

InvalidDBInstanceState: Database instance is not in available state.
InvalidDBSnapshotState: Cannot delete the snapshot because it is not
  currently in the available or failed state.

진행 중인 스냅샷을 지워서 멈추려 해도 두 번째 줄처럼 거부된다. 잡아 둔 작업 시간 안에서 40분을 그냥 기다렸다.

값 — 인스턴스도 스토리지도 2배

AWS 공개 가격표(도쿄 리전 · PostgreSQL · 온디맨드, 2026-10-29 판)에서 뽑았다. 월 730시간으로 셈했다.

Single-AZ Multi-AZ
db.t3.large $163.52 $327.04
db.r6g.xlarge $394.20 $787.67
gp3 스토리지 $0.138/GB·월 $0.276/GB·월

인스턴스만 보고 견적을 내면 틀린다. 스토리지도 2배다. 우리 첫 견적도 인스턴스 값만 보고 나와서 실제보다 꽤 낮았다.

셋 중 무엇을 사나 — Multi-AZ · 리드 리플리카 · Multi-AZ DB 클러스터

스탠바이로 읽기 복제 자동 페일오버 도쿄 gp3 스토리지
Multi-AZ 인스턴스 안 됨 동기 됨 $0.276 (2배)
리드 리플리카 됨 비동기 안 됨 (손으로 승격) 리플리카 인스턴스 몫이 따로
Multi-AZ DB 클러스터 됨 (리더 2대) 반동기 됨 $0.414 (3배)

셋은 서로 배타적이지 않다. 멈추지 않는 게 목적이면 Multi-AZ, 읽기를 나누는 게 목적이면 리드 리플리카다. 둘 다 필요하면 같이 쓰거나 클러스터를 본다. 다만 클러스터는 r6gd · m6gd 처럼 로컬 NVMe 가 달린 클래스만 고를 수 있어서, 지금 쓰는 클래스를 그대로 옮기지는 못한다.

전환 순서 — 스펙업 먼저, Multi-AZ 는 나중

켜는 것 자체는 무중단이다.

aws rds modify-db-instance --db-instance-identifier <id> --multi-az --apply-immediately

--apply-immediately 를 빼면 다음 유지보수 윈도우까지 기다린다. 밤에 잡은 작업이 통째로 헛일이 된다.

무중단이라고 가볍지는 않다. RDS 는 프라이머리 볼륨의 스냅샷으로 스탠바이 볼륨을 만들고, 그 볼륨은 뒤에서 데이터를 채운다(문서). 이미 I/O 가 포화인 인스턴스에서 켜면 이 작업이 한없이 늘어지고 그동안 서비스도 느려진다. 스냅샷 하나에 40분 걸린 게 그 증거였다.

그래서 순서를 이렇게 잡았다.

  1. 정지 창을 잡고 클래스를 올린다 (Single-AZ, 약 3분 정지) — 대역폭부터 확보
  2. 그다음 Multi-AZ 를 켠다 (무중단) — 동기화가 짧고 덜 아프다

진행은 이렇게 본다.

aws rds describe-db-instances --db-instance-identifier <id> --query 'DBInstances[0].{Status:DBInstanceStatus,MultiAZ:MultiAZ,Secondary:SecondaryAvailabilityZone,Storage:StorageOperationStatus}'

SecondaryAvailabilityZone 이 채워지면 스탠바이가 생긴 거다. 상태가 available 로 돌아와도 스탠바이 볼륨은 아직 뒤에서 채워지는 중일 수 있다. 그건 StorageOperationStatus 가 Initializing 인지로 본다. 우리는 수십 GB 에 20〜40분 걸렸다.

AWS 문서는 사실 본번 인스턴스를 그 자리에서 바꾸기보다, 리드 리플리카를 만들어 Multi-AZ 로 바꾼 뒤 승격하는 길을 권한다. 쓰기에 민감한 서비스면 그쪽을 먼저 검토할 만하다. 우리는 그 자리에서 바꿨고, 대신 위 순서로 대역폭을 먼저 벌어 뒀다.

T 계열에서 옮기면 대시보드에 No data 가 뜬다

CPUCreditBalance 는 버스터블(T 계열) 인스턴스 전용 지표라 r6g 로 가면 더 안 나온다. 대시보드 위젯이 「No data」 가 되는데 고장이 아니다. 이 지표에 알림을 걸어 뒀다면 오탐이 나니 미리 정리해 둔다.

켤까 말까

켠다: 몇 분 멈추는 게 매출 · 신뢰로 바로 이어지는 서비스. 패치 · 스펙 변경을 정기적으로 해야 하는데 다운타임 때문에 미루고 있는 곳 — 이것만으로도 값을 한다. 백업 때 I/O 가 멈추는 게 문제가 되는 규모.

안 켠다: dev · staging (값만 2배). 몇 분 멈춰도 되고 복구 시간이 넉넉한 사내 시스템.

들여다보면 같이 나오는 것들

Multi-AZ 를 검토하면서 같은 인스턴스에서 처음 구축할 때의 설정이 줄줄이 나왔다.

  • 백업 보존 1일 — terraform 에 backup_retention_period = 1 이 박혀 있었다. 시점 복구(PITR) 범위가 24시간뿐이라, 하루 넘겨 알게 된 사고는 못 되돌린다

  • 스토리지 암호화 off — 켜려면 스냅샷 복사 → 복원 → 엔드포인트 전환이라 따로 정지가 필요하다. 그 자리에서는 못 바꾼다

  • 오토스케일링 상한 도달 — 할당량이 이미 상한과 같아서 더 늘어날 여지가 없었다

인프라를 한 번 제대로 들여다보면 이런 게 꼭 나온다. Multi-AZ 검토는 그 계기로 쓰기 좋다.

본번 DB 의 이중화나 스펙 변경 순서, terraform 과 실제 상태가 어긋난 인프라 정리로 고민 중이면 https://www.negabaro.com/contact 로 물어봐 주면 된다.

동작 흐름

1

terraform 의 Multi-AZ 조건이 실제로 참이 되는지, plan 에 차이가 없는지 먼저 본다

2

정지 창을 잡고 인스턴스 클래스를 올린다 (Single-AZ 는 정지 → 리사이즈 → 기동)

3

--multi-az --apply-immediately 로 Multi-AZ 를 켠다 (무중단, 스냅샷에서 스탠바이 볼륨 생성)

4

SecondaryAvailabilityZone 과 StorageOperationStatus 로 스탠바이 준비가 끝났는지 본다

5

T 계열 전용 지표(CPUCreditBalance) 위젯 · 알림을 정리한다

장점

  • ✓ 장애 때 자동 페일오버, 엔드포인트 그대로
  • ✓ OS 패치를 스탠바이 먼저 하니 정지가 페일오버 시간만큼
  • ✓ 백업을 스탠바이에서 떠서 프라이머리 I/O 가 안 멈춘다 (PostgreSQL · MySQL)

단점

  • ✗ 인스턴스도 스토리지도 값이 2배
  • ✗ 스탠바이는 못 읽는다 — 읽기 성능은 그대로
  • ✗ 페일오버 때 커넥션이 끊긴다. 엔진 업그레이드는 여전히 정지

사용 사례

몇 분 정지가 매출 · 신뢰로 바로 이어지는 본번 DB 다운타임 때문에 OS 패치 · 클래스 변경을 미뤄 온 DB 백업 때 I/O 가 멈추는 게 문제가 되는 규모
← 봇 차단은 헤더 하나가 아니다 — 막는 쪽에서 본 다섯 층 ECS Exec 세션 로그가 한 줄도 안 남을 때 — 이미지에 script 가 있는지부터 본다 →