Amazon Aurora MySQL 버전 2(MySQL 5.7 호환)의 표준 지원은 2024년 10월 31일에 끝난다. 그 전에 운영 중인 DB를 8.0으로 올려야 했다.

준비하면서 가장 먼저 찾은 건 되돌리는 방법이었다. 최근 참석한 ‘Aurora MySQL 2 End of Life (EOL) 웨비나’에서도, 따로 찾아본 문서들에서도 답은 같았다. 롤백을 위한 서비스는 아직 지원되지 않는다. Blue/Green 배포는 다운타임을 줄여 줄 뿐, 되돌리는 길까지 만들어 주지는 않는다.

이 글에서는 업그레이드 전에 알았으면 좋았을 것들을 정리한다. 두 배포 방식의 다운타임과 파라미터 그룹이 겹치는 순서, 8.0에서 달라지는 기본값 두 가지를 먼저 짚고, 직접 세운 롤백 절차와 작업이 끝난 뒤에야 보인 것들로 마무리한다.

In-Place도 Blue/Green도 다운타임은 있다

In-Place는 지금 돌고 있는 DB를 그대로 업그레이드한다. 단순한 대신 업그레이드하는 동안 다운타임이 생긴다.

Blue/Green은 운영 환경(Blue)은 그대로 두고, 복제본인 스테이징 환경(Green)에서 버전을 올린 뒤 두 환경을 맞바꾼다. 무중단이 필요한 환경이라면 먼저 검토해 볼 방식이다. 그렇다고 다운타임이 아예 없지는 않고, 약 2분가량은 멈춘다. 멈추는 지점은 두 곳이다.

  1. Blue/Green을 만들기 전에 재부팅이 한 번 필요하다. Green은 Blue의 변경 사항을 계속 따라 받는데, 이 동기화를 위해 Aurora MySQL은 binlog_format 파라미터가 ROW로 켜져 있어야 한다. 파라미터를 바꾼 뒤 제대로 반영되게 하려면 인스턴스를 재부팅해야 하고, 여기서 첫 번째 다운타임이 생긴다.

  2. Switch Over를 시작하면 쓰기가 멈춘다. Green이 만들어진 뒤로 스위칭 전까지는 Blue의 변경 사항이 Green에 그대로 동기화된다. 스위칭을 시작하면 동기화가 모두 끝날 때까지 쓰기 작업이 중단되므로 Switch Over는 트래픽이 가장 적은 시간대에 하라고 권장한다.

구분In-PlaceBlue/Green
방식현재 DB를 직접 업그레이드복제본(Green)을 업그레이드한 뒤 Blue와 교체
다운타임업그레이드하는 동안약 2분 (binlog_format 반영 재부팅, Switch Over 중 쓰기 중단)
롤백용 클러스터업그레이드 전에 복제본을 따로 생성Switch Over 후 남는 기존 Blue

파라미터 그룹은 네 겹으로 겹친다

메이저 업그레이드는 엔진 버전만 올리는 일이 아니다. 파라미터 그룹도 8.0용으로 바꿔야 하는데, 이 그룹은 클러스터 파라미터 그룹과 인스턴스 파라미터 그룹 두 가지로 나뉜다. 기존 5.7 DB라면 클러스터에는 5.7 클러스터 파라미터 그룹이, 인스턴스에는 5.7 인스턴스 파라미터 그룹이 붙어 있고, 둘 다 8.0 버전으로 교체해야 한다.

헷갈리는 건 같은 파라미터가 양쪽에 다 있다는 점이다. 어느 쪽 값이 이기는지는 그 그룹이 Default냐 사용자 정의냐에 따라 달라진다. Default 파라미터 그룹은 클러스터를 만들 때 사용자 정의 그룹을 지정하지 않으면 붙는 그룹이고, 삭제할 수 없다.

  • 둘 다 Default면 인스턴스 파라미터 그룹이 우선한다. 클러스터 쪽 값은 무시된다.

  • 클러스터에 사용자 정의 클러스터 파라미터 그룹을 붙이면 그 값이 우선한다. 인스턴스 쪽에 겹치는 값은 무시된다.

  • 인스턴스에도 사용자 정의 인스턴스 파라미터 그룹을 붙이면 다시 그쪽이 우선한다.

Default Cluster PG < Default Instance PG < Custom Cluster PG < Custom Instance PG

DB 인스턴스마다 서로 다른 설정을 줄 수 있게 설계했다고 보면 이 순서가 납득된다. 이걸 알고 나면 5.7 파라미터 그룹을 바탕으로 8.0 그룹을 어떻게 만들지 계획이 선다. 클러스터와 인스턴스 파라미터 그룹 각각에 대해 다음 순서로 확인했다.

  1. 적용된 5.7 파라미터 그룹이 Default인지 아닌지 확인한다.

  2. Default 파라미터 그룹과 비교해 값이 다른 파라미터를 찾는다. 값이 다르면 사용자가 정의한 파라미터다.

  3. 그 파라미터가 8.0 Default 파라미터 그룹에도 있으면 사용자 정의 값으로 적용한다.

Blue/Green으로 간다면 여기에 binlog_format을 ROW로 바꾸는 작업이 하나 더 붙는다.

8.0에서 달라지는 두 파라미터

utf8은 utf8mb3의 별칭이고, 곧 사라진다

5.7 파라미터 그룹을 보면 문자셋 파라미터가 utf8로 잡혀 있다.

utf8은 utf8mb3의 별칭이다. MySQL 공식 문서는 utf8(utf8mb3)을 8.0.x과 8.4.x LTS release까지만 지원하고, 이후 주요 릴리스에서 제거할 예정이라고 안내한다. 두 타입은 내부적으로 한 문자를 표현하는 데 쓰는 byte 크기가 다르다.

  • utf8(utf8mb3): 3 byte

  • utf8mb4: 4 byte

어차피 사라질 문자셋이라면 메이저 업그레이드 때 같이 넘어가는 편이 낫다. 8.0 업그레이드는 utf8mb4로 설정해 테스트했고, 이상이 없는 것을 확인한 뒤 운영까지 utf8mb4로 적용했다.

emoji나 외국어를 쓰는 서비스에는 utf8mb4가 특히 권장된다. 다만 이런 데이터가 이미 utf8 DB에 들어 있는데 업그레이드하면서 갑자기 utf8mb4로 바꾸면 문제가 생길 수 있으니, 이 경우는 충분히 테스트하고 넘어가야 한다.

event_scheduler는 8.0에서 켜진 채로 올라온다

event_scheduler 파라미터는 5.7과 8.0 모두 기본으로 ‘-’(Dynamic)로 설정되어 있지만, 실제로는 5.7에서 false(비활성), 8.0에서 true(활성)로 적용된다. 각 버전 DB에서 직접 조회해 보면 결과가 다르다.

-- 5.7과 8.0에서 결과가 다르게 나온다
SHOW VARIABLES LIKE 'event%';

-- 8.0에서는 event_scheduler Daemon이 계속 대기 중인 것이 보인다
SHOW PROCESSLIST;

롤백은 클러스터 이름을 맞바꾸는 방식으로 준비했다

롤백 서비스가 없으니 번거롭더라도 절차를 먼저 세워 두었다. 핵심은 애플리케이션이 바라보는 엔드포인트를 코드 수정 없이 이전 클러스터로 돌려놓는 것이다.

  1. 업그레이드 전에 롤백용 클러스터를 확보한다. 일종의 백업이다.
  • In-Place라면 업그레이드 전에 복제본을 생성한다.

  • Blue/Green이라면 Switch Over 뒤 남는 기존 Blue 환경이 곧 롤백용 클러스터다. 스위칭이 끝나면 기존 Blue 클러스터명 뒤에 -old가 붙는다.

  1. 업그레이드 후 롤백해야 한다고 판단하면 클러스터 이름을 맞바꾼다. 업그레이드된 클러스터를 A, 롤백용 클러스터를 B라고 하면 이렇다.
A → A-bak   # 업그레이드된 클러스터를 비켜 둔다
B → A       # 롤백용 클러스터가 기존 이름, 즉 기존 엔드포인트를 넘겨받는다

Aurora의 클러스터 엔드포인트는 클러스터 이름으로 만들어진다. 이름을 넘겨받으면 엔드포인트도 함께 넘어오니 기존 A 엔드포인트를 바라보던 애플리케이션은 코드를 고치지 않고도 이전 DB로 돌아간다.

이 방법에는 한계가 두 가지 있다.

  • 클러스터 이름을 바꾸는 동안 다운타임이 생긴다.

  • 업그레이드 후 롤백 시점까지 생긴 변경 사항은 롤백용 DB에 반영되지 않는다. 서비스 종류에 따라 다르지만 사실상 크리티컬한 문제다.

그 사이 변경 사항까지 롤백용 DB로 동기화할 방법을 갖춰야 제대로 된 롤백이다. 이 부분은 더 찾아보려고 남겨 둔 숙제다.

작업이 끝나고 나서 보인 것들

엔드포인트가 코드 곳곳에 하드코딩되어 있었다

작업 대상 DB와 같은 인프라 안의 애플리케이션들은 RDS 엔드포인트를 하드코딩해서 직접 바라보고 있었다. 그것도 여러 모듈의 아주 많은 코드에서였다. 프로젝트에 투입된 지 얼마 안 돼 애플리케이션 구성을 다 알지 못했고, 고쳤을 때의 영향도를 가늠할 수 없었다. 운영 DB 업그레이드 기간도 넉넉하지 않아서 인프라를 함부로 손볼 수도 없었다.

작업 기간이 충분하고 인프라를 바꿀 수 있었다면 ELB와 PrivateLink를 구성해 트래픽을 제어하고, 사전 테스트도 더 제대로 해 봤을 것이다. 속도와 보안까지 같이 개선할 수 있었을 텐데, 이 부분은 아쉬움으로 남았다.

고객사는 엔드포인트가 아니라 Private IP로 붙고 있었다

이번 업그레이드 대상 고객사는 자기 쪽 가상환경에서 Aurora MySQL에 연결할 때 엔드포인트가 아니라 IP를 쓰고 있었다. RDS의 IP는 동적으로 바뀐다. AWS도 IP가 아니라 엔드포인트로 DB에 연결하는 것을 모범 사례로 설명한다.

그런데도 IP를 쓴 이유는 통신장비에서 RDS 엔드포인트 형식의 값을 쓸 수 없어서라고 했다. 콘솔에서는 확인할 수도 없는 Private IP를 아마 nslookup 같은 명령으로 찾아 써 왔던 것 같다. 지금까지는 운 좋게 IP가 한 번도 바뀌지 않았지만, 이번 업그레이드로 IP가 바뀌면서 결국 접속 문제가 생겼다. 다행히 크리티컬하지는 않았다.

다음 업그레이드에는 체크포인트가 하나 늘었다. 고객사 쪽에서 RDS에 IP로 붙고 있지 않은지 먼저 확인하는 것이다. 그렇게 붙고 있다면 IP가 바뀔 수 있다고 미리 안내하고, 별도 프록시 서버 구성을 제안하는 것도 방법이다.

실제로 걸린 시간

작업소요 시간
복제본 생성 (스토리지 약 200GB, db.r6.xlarge 사이즈 Aurora MySQL)약 10분
DB 버전 업그레이드약 20분
재부팅약 1분

정리

  • Blue/Green도 다운타임은 있다. binlog_format을 ROW로 반영하기 위한 재부팅, 그리고 Switch Over 중 쓰기 중단. 약 2분이다.

  • 파라미터 그룹은 Default Cluster < Default Instance < Custom Cluster < Custom Instance 순으로 우선한다. 5.7에서 Default와 값이 다른 것만 골라 8.0 그룹에 옮기면 된다.

  • 8.0은 utf8을 utf8mb4로 바꿀 기회이고, event_scheduler가 기본으로 켜진다.

  • 롤백은 직접 만들어야 한다. 클러스터 이름을 맞바꿔 엔드포인트를 되돌릴 수 있지만, 업그레이드 후 변경분은 따라오지 않는다.

업그레이드 자체는 30분 남짓이었다. 정작 문제는 그 바깥, 코드에 박힌 엔드포인트와 고객사의 IP 접속에서 나왔다.