서론
이전 포스팅에서 언급한대로, 회사에서 Azure 기반의 MariaDB에서 MySQL로 migration 하는 작업을 했다.
이유는 9월 19일부로 MariaDB에 대한 지원을 Azure에서 종료하기 때문이다.
본 포스팅에선 그 방법에 대해 작성하고자 한다. 사실 그렇게 어렵진 않은데, VM 서버의 ubuntu 버전이 호환이 안되서 삽질을 좀 많이했다.
결론부터 말하자면, ubuntu 18.04 버전에선 불가능하다. 그리고 GTID 기반 replication도 불가능하다.
바이너리 로그 기반 replication이 필요하다. 본인의 작업환경 버전을 꼭 체크하도록 하자.
정확히는 온프레미스 환경이라면 어찌저찌 온몸비틀기로 되겠지만, 적어도 Azure 기반에선 불가능하다. 이유는 후술하겠다.
서비스 안정성을 위해 먼저 MariaDB -> MySQL로 migration 및 replication 작업을 한 후에, 추가적으로 MySQL에서 replication 작업이 필요하다.
작업에 앞서, replication 관련 선수지식들을 좀 쌓고 나면 이해가 쉬울 터이니, 이전 포스팅을 톺아본 후에 진행하면 빠른 작업이 가능할 것이다.
본론
작업 환경
중개 서버 : Ubuntu 22.04, 18.04 (안됨)
MariaDB : 10.2 (Azure)
MySQL : 8.0 유동 서버 (Azure)
MySQL-shell : 8.0.41 for MySQL 8.0.41
작업 시나리오

1. MariaDB 데이터를 dump한다.
2. dump한 데이터를 MySQL에 적용한다.
3. MariaDB와 replication해 실시간 데이터를 연동시킨다.
4. Slave DB인 MySQL을 Master로 승격시킨다.
앞서 말한대로 ubuntu 18.04 버전에서 한번에 MySQL 8.0으로 마이그레이션은 불가능하다.
정말 안되는건지 해당 포스팅을 작성한 인도 햄에게 메일까지 보내봤는데, 안되면 MySQL 5.7로 마이그레이션 하고 5.7을 다시 8.0으로 업그레이드 하는 방식으로 진행해보라고 했다.
우분투 버전을 정말 못올리거나, apt 패키지의 mysql을 정말 죽어도 못쓰는 환경이라면 한 번 시도해보자.


mysql-shell (mysqlsh) 설치
$ sudo apt update
$ sudo apt install mysql-server -y
$ mysql --version
$ sudo apt-get install mysql-shell
$ mysqlsh --version
ubuntu의 apt 패키지에서 공식적으로 지원하는 것은 20.x 부터다.
18.04 버전에서 mysql-shell을 사용하려면 snap 패키지의 mysql-shell을 사용해야 하는데, 이 친구가 python 기반으로 동작한다.
mysql-shell 예제들은 다 apt 기반으로 작성되어있고, apt의 mysqlsh은 JS 기반이다.
또한 snap의 mysqlsh은 dump를 적용할 때 GTID 기반으로 적용하는데, mariaDB는 GTID 개념이 없다. 그래서 이런 오류가 발생한다.
'Unknown system variable 'GTID_EXECUTED’
mysqldump는 안쓰나요?
좋은 질문이다. 해당 명령어로 dump를 따고 적용하는 것 까지는 되는데, 문제는 원본 DB와 replication을 엮어야 한다.
이 때 바이너리 로그와 포지션을 알아야 하는데, 바이너리 로그를 남기도록 활성화하려면 MariaDB를 껐다 켜야한다...
운영 DB를 껐다 킬수는 없는 노릇아닌가.. 따라서 Azure에서 안전하게 replication도 가능한 mysqlsh를 사용해야 한다.
Dump 생성 및 적용 작업
# mysqlsh로 접속 (MariaDB로)
# mysqlsh --uri {mariadb 사용자명}%40{mariadb 접속 url}@{mariadb 서버이름@접속url}:{포트번호}
$ mysqlsh --uri dbuser%40mariadb.database.azure.com@servername.mariadb.database.azure.com:3306
# 덤프 생성
# util.dumpInstance("생성덤프경로", {threads: 16, showProgress: true, users:false})
$ util.dumpInstance("/home/user/backup/dbdump", {threads: 16, showProgress: true, users:false})
# mysqlsh로 접속 (MySQL로)
# mysqlsh --uri {MySQL 사용자명}@{MySQL 서버 접속 url}:{포트번호}
$ mysqlsh --uri dbuser@mysqldb.mysql.database.azure.com:3306
# 덤프 적용
# util.loadDump("생성해둔 덤프 경로", {threads: 16, showProgress: true, ignoreVersion: true})
$ util.loadDump("/home/user/backup/dbdump", {threads: 16, showProgress: true, ignoreVersion: true})
주의 해야 할 점은, 덤프 적용 시 igrnoeVersion 옵션을 꼭 넣어줘야한다.
MariaDB 10.2 와 MySQL 8.0 간 버전 차이가 꽤 많이 나서, 해당 옵션이 있어야 자잘한 문제를 피할 수 있다.
Replication 적용하기
덤프는 적용시켜놨다. 이제 replication으로 중단없이 데이터를 동기화시키고자 한다.
우리가 필요한 파일은 dump파일 내의 binlogFile과 binlogPosition 값이다.
$ cd /home/user/backup/dbdump
$ cat @.json
해당 파일을 까보면 이렇게 정보가 나오는데, 여기서 binlogFile, binlogPosition 값을 잘 복사해두자.

이제 Replication을 적용해보자.
# replica로 만들 db로 접속 (MySQL)
# mysql -h {db서버 접속url} -P {포트} -u {사용자명} -p
$ mysql -h mydb.mysql.database.azure.com -P 3306 -u dbuser -p
# I/O replica thread 종료
mysql> CALL mysql.az_replication_stop;
# replication 실행 전 설정
# mysql> CALL mysql.az_replication_change_master('mariadb 서버 url', '사용자명@mariadb 서버 url', '비밀번호', {포트}, 'binlogFile', binlogPosition, '');
mysql> CALL mysql.az_replication_change_master('dbserver.mariadb.database.azure.com', 'dbuser@dbserver.mariadb.database.azure.com', 'password123!@#', 3306, 'mysql-bin.000560', 41152681, '');
# 정상 적용 확인
mysql> show slave status\G;
# replication 실행
mysql> call mysql.az_replication_start;
성공적으로 됐다면 show slave status\G; 를 실행했을 때 이렇게 나와야되고,

아니라면 에러가 떴을 것이다.

에러는 MySQL에서 해당 쿼리를 통해 확인하고, 해결해보도록 하자.
select * from performance_schema.replication_applier_status_by_worker;
짚고 넘어가야 할 점
replication 과정에서 에러가 발생했을 때 mysql의 replica_skip_errors 를 사용할 수 있는데, 여기서 또 Azure가 방해한다.
Azure에서 DB를 생성할 때 주는 관리자는 완전한 root권한이 아닌, root에 준하는 권한이 있는 또다른 관리자다.
즉, root 밑에 관리자 역할로 뭔가가 있는거임.
그래서 MySQL의 문법을 그대로 사용하는게 불가능하고, 대신 Azure가 제공해주는 비슷한 역할을 수행하는 프로시저로 조작해야한다.
바로 위 replication 작업을 할 때 az_replication_change_master() 이런것들 말이다.
이것 때문에 애를 많이 먹었다...
아무튼 MySQL 8.0부터는 이러한 에러를 자동으로 스킵해주는 기능이 있는데, Azure라서 해당 기능을 사용할 수 없다.
따라서 비슷한 역할을 하는 아래 프로시저로 대체할 수 있다.
그러나 어떤 에러가 발생하는지 다 확인해야하고, 데이터의 무결성과 정합성을 보장할 수 없으므로 추천하진 않는다.
관련해서는 해당 문서를 참고해보자.
CALL mysql.az_replication_skip_counter(N); -- N: 건너뛸 이벤트 수
Master DB로 승격하기
이제 마지막으로 기존 Master를 대체하는 작업을 수행한다. 생각보다 간단하지만, 위험도가 있는 작업이므로 꼭 테스트 환경에서 제대로 동작하는지 확인해보고 운영에 적용하도록 하자.
# 실행 전 아래 사항들 꼭 확인하기
mysql> SHOW VARIABLES LIKE '%read_only%';
# 만약 read-only mode가 ON이라면, OFF 해주기 (마스터 되야하니까)
mysql> SET GLOBAL read_only = OFF;
mysql> UNLOCK TABLES;
# 마스터로 승격
mysql> call mysql.az_replication_stop;
mysql> call mysql.az_replication_remove_master;
이렇게 하면 중단 없이 MariaDB 10.2 에서 MySQL 8.0으로 무사히 이관이 가능하다.
아직까지는 별 트러블이 없다. 생각보다 Azure 에서 관리가 잘 되는듯 하다. 그래도 지속적인 모니터링은 필요하다.
Troubleshooting log
혹시 도움이 될까봐 트러블슈팅 로그를 남겨놓는다. 모종의 이유로 잘 되지 않는다면 도움이 되길 바란다.

결론
이렇게 Azure 기반으로 MariaDB -> MySQL로 무사히 마이그레이션 작업을 완료했다.
올해 9월까지 종료니까... 미뤄왔던 누군가는 이런 작업을 할텐데, 도움이 되길 바란다.
해당 작업을 진행하면서 Replication의 원리도 알아서, 재밌게 공부한 좋은 기회가 됐던 것 같다.
참고
Migrating from Azure Database for MariaDB to Azure Database for MySQL
MySQL 활용해 DB Replication 적용해보기 (Master - Slave 구조)
GRANT SUPER privilege on Azure Database for MySQL
Installing MySQL Shell on Linux
How to configure Azure Database for MySQL - Flexible Server data-in replication
'Backend > DB' 카테고리의 다른 글
[DB] Replication에 대해 알아보자 (0) | 2025.02.08 |
---|---|
[DB] 조회 시 트랜잭션을 걸어야 하는 이유? (Feat. 트랜잭션 격리수준) (2) | 2024.06.26 |
[Oracle] 오라클 시퀀스가 동시성 이슈를 보장해주는 이유 (2) | 2024.06.11 |
[MySQL, JPA] Schema-validation: missing column [컬럼명] in table [테이블명] (0) | 2023.10.26 |
[ORACLE] TRUNC 함수 사용법 (3) | 2021.01.21 |