Post

RDS 업그레이드, 순서 제대로 알자

이번에 온콜이라서 RDS for MariaDB랑 Aurora 클러스터 마이너 버전 업그레이드 작업을 했다.

RDS 업그레이드, 순서 제대로 알자

이번에 온콜이라서 RDS for MariaDB랑 Aurora 클러스터 마이너 버전 업그레이드 작업을 했다. (고객이 저녁에 요청 근데 그 시간에 다른 작업도 동시에 있네?)

이 과정에서 보통은 업그레이드를 우리가 자체적으로 진행하고 완료 메일을 보낸다. 근데 이번에는 고객이 전화를 와서 직접 작업에대해서 물어보고 슬랙을 통해서 연락을 달라고 했다.( 여기서 내가 멀티 az 업그레이드 방식으로 잘못 설명함 )

그래서 이런 실수를 하지 않기 위해서 RDS 업그레이드 방법에 대해서 정리한다.

같은 “RDS 업그레이드”인데 Aurora냐 아니냐, 마이너냐 메이저냐, 엔진 업그레이드냐 OS 업데이트냐에 따라 동작이 전부 다르다.


먼저 마이너와 메이저

용어부터 짚고 간다. AWS 문서 기준 정의는 이렇다.

1
2
3
4
5
6
7
8
9
메이저 버전 업그레이드 (major version upgrade)
  기존 애플리케이션과 호환되지 않을 수 있는 변경을 포함
  예) MariaDB 10.5 → 10.6, Aurora MySQL v2(5.7 호환) → v3(8.0 호환)
  → 무조건 수동. AWS가 알아서 해주지 않는다

마이너 버전 업그레이드 (minor version upgrade)
  기존 애플리케이션과 하위 호환되는 변경만 포함
  예) MySQL 5.7.22 → 5.7.23
  → 수동으로도 되고, Auto minor version upgrade 켜두면 자동

공식문서 · Upgrading a DB instance engine version — “In general, a major engine version upgrade can introduce changes that are not compatible with existing applications. In contrast, a minor version upgrade includes only changes that are backward-compatible with existing applications.” / “For major version upgrades, you must manually modify the DB engine version through the AWS Management Console, AWS CLI, or RDS API.”

여기서 중요한 건 마이너든 메이저든 다운타임이 있다는 것이다. 마이너라고 무중단이 아니다. 문서에도 “Automatic upgrades incur downtime”이라고 못 박혀 있다. 그냥 마이너가 좀 더 짧을 뿐이다.

그리고 버전 번호 읽는 법도 엔진마다 다르다. 나는 앞자리가 바뀌면 메이저, 중간이 바뀌면 마이너로 알고 있었는데 MySQL 계열은 앞 두 자리가 통째로 메이저다.

1
2
3
4
5
6
7
8
MySQL / MariaDB   앞 두 자리가 메이저, 세 번째가 마이너
                  10.5 → 10.6  메이저 (앞자리 10은 그대로인데도)
                  8.0 → 8.4    메이저
                  10.6.14 → 10.6.16  마이너

PostgreSQL        첫 자리만 메이저
                  15 → 16      메이저
                  16.1 → 16.2  마이너

공식문서 · MariaDB version numbers — “The major version number is both the integer and the first fractional part of the version number, for example, 10.11… an upgrade from 10.5.20 to 10.6.12 is a major version upgrade.” / “The minor version number is the third part of the version number, for example, the 5 in 10.11.5.” · Upgrading a DB instance engine version — “The version numbering sequence is specific to each database engine. For example, RDS for MySQL 5.7 and 8.0 are major engine versions…”

그래서 위에 예시로 든 10.5 → 10.6도 앞자리가 그대로지만 메이저다. 번호만 보고 짐작하지 말고 API에 물어보는 게 확실하다.

1
2
3
4
aws rds describe-db-engine-versions \
  --engine mariadb --engine-version 10.6.14 \
  --query "DBEngineVersions[].ValidUpgradeTarget[?IsMajorVersionUpgrade].{V:EngineVersion}" \
  --output table

그냥 그때마다 버전을 봐야지 뭐…


RDS for MariaDB — 레플리카를 먼저 올려야 한다

MariaDB 쪽 문서에 답이 그냥 한 문장으로 나와 있었다.

공식문서 · Upgrades of the MariaDB DB engine — “If your MariaDB DB instance is using read replicas, you must upgrade all of the read replicas before upgrading the source instance.”

레플리카 먼저인 건 맞다. 근데 승격은 안 한다. 레플리카를 다 올린 다음, 소스 인스턴스는 소스 자리 그대로 업그레이드한다.

왜 레플리카가 먼저인가

이건 AWS 규칙이라기보단 MySQL/MariaDB 복제의 기본 성질이다.

1
2
3
4
5
복제는 "낮은 버전 → 높은 버전" 방향은 지원한다
       source 10.5  →  replica 10.6   (OK)

반대 방향은 지원 대상이 아니다
       source 10.6  →  replica 10.5   (지원 안 함)

공식문서 · Replication Compatibility Between MySQL Versions — “Replication from newer sources to older replicas might be possible, but is generally not supported. This is due to a number of factors: Binary log format changes. The binary log format can change between major releases. SQL incompatibilities.…”

무조건 깨진다는 게 아니라 지원 대상이 아니다가 정확한 표현이다. binlog 포맷이 안 바뀐 조합이면 우연히 돌아갈 수도 있지만 보장이 없다. 그래서 소스를 먼저 올리면 그 순간부터 구버전 레플리카들이 지원되지 않는 조합에 놓인다. 레플리카를 먼저 올려두면 진행 중에도 계속 10.5 → 10.6 방향이라 안전하다.

Multi-AZ는 롤링이 아니다

Multi-AZ 배포면 스탠바이를 먼저 올리고 페일오버시켜서 다운타임을 줄이겠거니 했는데, 아니다.

공식문서 · Considerations for MariaDB upgrades — “If your DB instance is in a Multi-AZ deployment, both the primary and standby DB instances are upgraded. The primary and standby DB instances are upgraded at the same time and you will experience an outage until the upgrade is complete.

프라이머리랑 스탠바이를 동시에 올리고, 끝날 때까지 그냥 다운이다. Multi-AZ는 장애 상황에서의 가용성을 위한 거지, 업그레이드 다운타임을 없애주는 장치가 아니었다. 이거 모르고 “Multi-AZ니까 금방 되겠지” 하고 작업 시간 잡으면 큰일 난다.

그런데 같은 Multi-AZ 인스턴스인데 OS 업데이트일 때는 동작이 완전히 다르다. 이후 설명


Aurora — 라이터를 올리면 리더도 같이 올라간다

Aurora는 아예 구조가 다르다. Aurora는 인스턴스들이 각자 데이터를 들고 있는 게 아니라 공유 스토리지 볼륨 하나를 여러 인스턴스가 같이 본다. 그래서 엔진 버전도 인스턴스별 속성이 아니라 사실상 클러스터 속성처럼 움직인다.

aurora_architecture

공식문서 · Using zero-downtime patching — “Patching the writer DB instance automatically patches readers at the same time. After performing the patch, Aurora restores the connections on both the writer and reader DB instances.” · Maintaining an Amazon Aurora DB cluster — “For upgrades to the database engine, Amazon Aurora manages the preferred maintenance window for a DB cluster and not individual instances.

리더 먼저도 아니고, 승격도 아니고, 동시다.

ZDP (Zero-Downtime Patching)

Aurora MySQL 마이너 업그레이드에는 커넥션을 살려주려고 시도하는 기능이 있다. 이름은 무중단 패칭인데, 문서를 읽어보면 어감이 좀 다르다.

공식문서 · Using zero-downtime patching — “The zero-downtime patching (ZDP) feature attempts, on a best-effort basis, to preserve client connections through an Aurora MySQL upgrade. If ZDP completes successfully, application sessions are preserved and the database engine restarts while the upgrade is in progress. The database engine restart can cause a drop in throughput lasting for a few seconds to approximately one minute.

best-effort basis. 보장이 아니라 시도다. 그리고 아래 조건이면 ZDP가 실패하고 그냥 일반 패칭(=커넥션 다 끊김)으로 돌아간다.

1
2
3
4
5
6
7
8
ZDP가 실패할 수 있는 조건
  · 오래 걸리는 쿼리/트랜잭션이 진행 중
  · 임시 테이블, user lock, table lock 사용 중 (DDL 실행 중 등)
  · 적용 대기 중인 파라미터 변경(pending parameter changes)이 있음

ZDP가 아예 적용 안 되는 것
  · OS 패치 및 업그레이드
  · 메이저 버전 업그레이드

“If no suitable time window for performing ZDP becomes available because of one or more of these conditions, patching reverts to the standard behavior.”

실무에서 걸릴 만한 건 pending parameter changes다. 파라미터 그룹 만졌는데 재부팅을 안 해서 pending 상태로 남아있으면, 그것만으로 ZDP가 날아간다. 작업 전에 파라미터 그룹 상태가 in-sync인지 확인하고 들어가는 게 좋다.

그리고 커넥션이 유지돼도 초기화되는 것들이 있다. 글로벌 변수, 상태 변수, LAST_INSERT_ID, 테이블의 인메모리 auto_increment 상태 같은 것들. 세션 변수는 복구해주지만 글로벌 변수는 안 해준다.

메이저 업그레이드는 in-place로, 라이터부터

Aurora MySQL 메이저 업그레이드(in-place) 단계는 문서에 순서대로 다 나와 있다. 이게 제일 흥미로웠다.

1
2
3
4
5
6
7
8
1. 프리체크 실행 (클러스터는 계속 running)
2. Aurora가 클러스터를 오프라인으로 내림 ← 여기부터 다운타임
3. 클러스터 볼륨의 스냅샷 생성 (수동 스냅샷으로 남음, 안 지우면 계속 있음)
4. 클러스터 볼륨을 클론 (실패 시 여기로 되돌림)
5. 라이터 인스턴스를 clean shutdown
6. 라이터 인스턴스의 엔진 버전을 업그레이드  ← 라이터가 먼저
7. 리더 인스턴스들의 엔진 버전을 업그레이드  ← 리더가 나중
8. 완료

공식문서 · How the Aurora MySQL in-place major version upgrade works — “6. Aurora upgrades the engine version on the writer DB instance… 7. Aurora upgrades the engine version on the reader DB instances.” · “Once the process begins, it runs until the upgrade either succeeds or fails. You can’t cancel the upgrade while it’s underway. If the upgrade fails, Aurora rolls back all the changes and your cluster has the same engine version, metadata, and so on as before.”

라이터가 먼저고 리더가 나중이다. 생각해보면 당연한 게, 공유 볼륨의 시스템 테이블과 데이터 포맷을 실제로 변환하는 주체가 라이터이기 때문이다. 리더는 볼륨에 쓰기를 못 하니까 변환 작업을 할 수가 없다.

그리고 4단계에서 볼륨을 클론해두기 때문에, 6단계 도중에 실패하면 클론된 볼륨의 원본 데이터로 복구된다. MariaDB의 “스냅샷 떠놨으니 알아서 복원해라”보다 훨씬 낫다.

한 가지 더, 3단계 스냅샷은 수동 스냅샷이라 자동으로 안 지워진다. 검증 끝났으면 지워야 스토리지 요금이 안 샌다. 이거 계정 여기저기 방치돼 있는 거 종종 본다.

참고로 메이저 업그레이드 전에 클러스터를 클론해서 리허설해보라는 게 문서 권장사항이다. Aurora 클론은 실제 데이터 복사가 아니라 빨리 만들어진다. 운영 클러스터로 처음 해보지 말자는 얘기. -> 클론도 재미있는데, 실제 데이터를 복사하지 않고 copy-on-write로 만들어서 빠르게 별개의 클러스터를 얻을 수 있다. 제약은 이렇다.

· 소스와 같은 리전이어야 한다 · copy-on-write 클론은 15개까지. 16번째부터는 full copy가 된다 · DB 인스턴스가 0개인 클러스터는 클론할 수 없다 · 다른 VPC에 만들 수 있는데, 이 경우 “the subnets of the VPCs must map to the same Availability Zones” — 두 VPC의 서브넷이 같은 AZ에 매핑돼야 한다 (같은 VPC면 해당 없음)

auto minor version upgrade 설정

이 기능은 서비스 다운 타임이 발생할 수 있어서 실무에서는 거의 모두 끄고 사용한다. Aurora에서 자동 마이너 업그레이드 설정은 클러스터 레벨과 인스턴스 레벨 양쪽에 있다(굳이 왜 2개로 나눴지? 적용결과는 and인데)

공식문서 · Automatic minor version upgrades for Aurora DB clusters — “If any DB instance in your cluster has this setting turned off, the DB cluster isn’t automatically upgraded.

인스턴스 하나라도 꺼져 있으면 클러스터 전체가 자동 업그레이드 대상에서 빠진다.


그렇다면 내가 처음에 착각했던건?

내가 머릿속에 그렸던 “읽기 먼저 → 승격 → 라이터” 순서는 실제로 존재한다. 다만 엔진 업그레이드가 아니라 OS 업데이트의 동작이었다. 추가적으로 Multi-AZ DB 클러스터 배포의 마이너 업그레이드도 여기에 해당한다.

RDS Multi-AZ의 OS 업데이트

공식문서 · Maintenance for Multi-AZ deployments — “Amazon RDS applies operating system updates by following these steps: 1. Perform maintenance on the standby. 2. Promote the standby to primary. 3. Perform maintenance on the old primary, which becomes the new standby.

스탠바이 먼저 → 승격 → 구 프라이머리. 내가 그린 시나리오랑 글자 그대로 같다. 리더가 아니라 스탠바이라는 것만 다르다.

그리고 같은 문서 바로 다음 문단이 대비를 확실하게 해준다.

· “If you upgrade the database engine for your DB instance in a Multi-AZ deployment, Amazon RDS modifies both primary and secondary DB instances at the same time… This operation causes downtime until the upgrade is complete.” · “If there are underlying operating system patches that need to be applied, a short Multi-AZ failover is required to apply the patches to the primary DB instance. This failover typically lasts less than a minute.

같은 Multi-AZ 인스턴스인데 OS 업데이트면 롤링(1분 미만 페일오버), 엔진 업그레이드면 동시 아웃티지다. 이 둘을 한 덩어리로 기억하고 있었던 게 내 착각의 정체였다.

Multi-AZ DB 클러스터 배포의 마이너 업그레이드

이건 OS가 아니라 엔진 업그레이드인데도 같은 순서로 동작한다. MySQL·PostgreSQL 둘 다 해당한다. 두 엔진 문서에 토씨까지 같은 문장이 들어있다.

스크린샷 2026-08-31 00.46.08

공식문서 · Upgrades of the RDS for MySQL DB engine / Upgrades of the RDS for PostgreSQL DB engine — “When you perform a minor version upgrade of a Multi-AZ DB cluster, Amazon RDS upgrades the reader DB instances one at a time. Then, one of the reader DB instances switches to be the new writer DB instance. Amazon RDS then upgrades the old writer instance (which is now a reader instance).” · Upgrading the engine version of a Multi-AZ DB cluster — “Downtime during the upgrade is limited to the time it takes for one of the reader DB instances to become the new writer DB instance. This downtime acts like an automatic failover.

통상 35초인데, 이 35초는 업그레이드 시간이 아니라 승격에 걸리는 시간이다. 그래서 replica lag이 크면 더 길어질 수 있다. 다만 이 배포 유형은 MySQL과 PostgreSQL만 지원해서, 이번에 작업한 MariaDB에는 해당이 없었다.

Aurora도 OS 업데이트는 롤링이다

Aurora도 마찬가지다. 방식만 다르다.

공식문서 · Operating system updates for Aurora DB clusters — “This method preserves read availability with rolling upgrades that automatically apply updates to a few reader DB instances at a time. To prevent multiple failovers and reduce unnecessary downtime, Aurora upgrades the writer DB instance last.” · “If you must use instance-level updates, update the reader DB instances in a DB cluster first, then update the writer DB instance. If you update reader and writer instances simultaneously, you increase the chance of failover-related downtime.”

그러니까 전체 그림이 이렇게 된다.

1
2
3
4
5
6
7
                    OS 업데이트                         엔진 업그레이드
              ──────────────────────────       ────────────────────────────
RDS Multi-AZ  standby → 승격 → 구 primary      primary·standby 동시,
              (페일오버 보통 1분 미만)            완료까지 아웃티지

Aurora        리더 몇 대씩 롤링                 마이너: 라이터·리더 동시 패치
              → 라이터 마지막                   메이저: 라이터 먼저 → 리더 나중

RDS는 스탠바이 승격으로, Aurora는 리더 롤링으로 방식은 다르지만 OS 업데이트는 양쪽 다 롤링이다. 그리고 OS 업데이트는 엔진 버전이나 인스턴스 클래스를 바꾸지 않고 보통 10분 내외로 끝난다.

system-update(OS 패치)랑 엔진 버전 업그레이드를 같은 걸로 뭉뚱그려 기억하고 있었던 거다. 콘솔의 “Pending maintenance” 항목에 둘 다 뜨니까 더 헷갈렸다. Aurora는 OS 업데이트를 클러스터 레벨(os-upgrade)로 하는 걸 권장하고, 그러면 알아서 롤링으로 처리해준다.


블루/그린 — 보통 이걸로 많이 하죠

보통 이걸로해서 인플레이스 rds 업그레이드에 대해서 잘 기억이 안났다. 그린으로 완전한 복제본에 업그레이드를 적용하는 방식이다.

blue-green-deployment

스위치오버

1
2
3
4
스위치오버 후
  auroradb-green-abc123          →  auroradb            (그린이 이름과 엔드포인트를 물려받음)
  auroradb-instance2-green-abc123 →  auroradb-instance2  (리더도 그대로 승계)
  auroradb (구 블루)              →  auroradb-old1       (지워지지 않고 남음)

공식문서 · “The switchover results in downtime. The downtime is usually under one minute, but it can be longer depending on your workload.” · “The names and endpoints in the current production environment are assigned to the newly switched over production environment, requiring no changes to your application.” · “After switchover, the previous production environment isn’t deleted so that you can use it for regression testing, if necessary.”

여기서 엔드포인트가 유지되는 건 RDS가 스위치오버 때 이름을 자동으로 넘겨주기 때문이다. 내가 맞추는 게 아니다.

원리는 RDS 엔드포인트가 식별자.해시.리전.rds.amazonaws.com 형태라는 데 있다. 가운데 해시가 계정·리전 단위로 고정이라, 같은 계정 + 같은 리전에서 식별자를 똑같이 맞추면 엔드포인트도 같아진다. 그래서 블루/그린 말고 수동으로 리네임하는 방식에서도 엔드포인트를 살릴 수 있다.

그리고 구 블루가 자동으로 안 지워진다. 롤백용으로 남겨주는 건 고마운데, 이거 요금이 그대로 나간다. 검증 끝나면 정리해야 한다. -old1 붙은 인스턴스가 몇 달째 떠 있는 계정 꽤 있다.


정리정리

 리더/레플리카 처리다운타임롤백
RDS 마이너/메이저
(단일 / Multi-AZ DB instance)
레플리카를 먼저 수동 업그레이드 → 그 다음 소스Multi-AZ여도 프라이머리·스탠바이 동시에, 완료까지 사용불가불가. 사전 스냅샷 복원으로 새 인스턴스 생성만 (백업 보존 0이면 스냅샷도 없음)
Aurora 마이너라이터 패치 시 리더 동시 패치ZDP 성공 시 수 초~1분 스루풋 저하, 실패 시 커넥션 끊김
Aurora 메이저 (in-place)라이터 먼저 → 리더 나중클러스터 오프라인, 데이터 양·스키마에 따라 김실패 시 클론 볼륨으로 자동 복구. 시작하면 취소 불가
RDS OS 업데이트
(Multi-AZ DB instance)
스탠바이 먼저 → 승격 → 구 프라이머리페일오버 보통 1분 미만, 통상 10분 내외
Aurora OS 업데이트리더 몇 대씩 롤링 → 라이터 마지막읽기 가용성 유지, 통상 10분 내외
블루/그린그린에 라이터+리더 토폴로지 그대로 복사스위치오버 보통 1분 미만구 블루가 -old1로 남아있음

표의 RDS 행은 단일 인스턴스와 Multi-AZ DB instance 기준이다. RDS에는 배포 유형이 하나 더 있는데, 라이터 1대 + 읽기 가능한 리더 2대를 3개 AZ에 두는 Multi-AZ DB cluster다. 여기서는 마이너 업그레이드 동작이 아예 다르다 — “Amazon RDS first upgrades the reader DB instances one at a time. Then, one of the reader DB instances switches to be the new writer DB instance. Amazon RDS then upgrades the old writer instance (which is now a reader instance).” / “Downtime during the upgrade is limited to the time it takes for one of the reader DB instances to become the new writer DB instance. This downtime acts like an automatic failover.” (Upgrading the engine version of a Multi-AZ DB cluster).

다만 이 배포 유형은 RDS for MySQL과 PostgreSQL만 지원해서 이번에 작업한 MariaDB는 해당이 없었다. 메이저는 엔진별로 또 갈리는데 PostgreSQL은 리더·라이터를 동시에 올려서 승격이 없고, MySQL은 마이너처럼 하나씩 올린다. 그 이유로 문서가 든 게 “so replication occurs from a lower engine version to a higher one”이라, 앞에서 본 복제 방향 원칙이 배포 유형만 바꿔서 또 나온다. (단 일반 업그레이드 문서에는 “major version upgrades are only supported for RDS for PostgreSQL”이라고 되어 있어 두 문서가 어긋난다. 실제 케이스는 describe-db-engine-versionsIsMajorVersionUpgrade로 확인하는 게 맞다.)

참고로 이름이 헷갈리는데 Multi-AZ DB cluster와 Aurora DB cluster는 다른 것이다. describe-db-clusters에 둘 다 나오고 둘 다 DBClusterIdentifier를 가져서 더 헷갈린다. 문서도 “Multi-AZ DB clusters aren’t the same as Aurora DB clusters”라고 따로 경고 박스를 달아뒀다.

MSP 업무 특성상 남의 DB를 만지는 일이 대부분이다. 그래서 “이렇게 하면 되겠지”로 접근하면 안 되는데, 이번에 딱 그렇게 접근했다가 예상과 다른 걸 보고 문서를 다시 읽었다.

다행히 이번 작업 자체는 문제없이 끝났다. 작업 절차보다 작업 전에 고객에게 뭐라고 설명 + 내가 이해하느냐가 더 중요한 일이었다.

참고

This post is licensed under CC BY 4.0 by the author.