2024년, 아무 준비 없이 MySQL 5.7을 계속 쓰면 어떻게 될까요?
AWS가 5.7 지원을 종료하면서, 월 70%의 추가 비용이 붙습니다. 심지어 Aurora도 올해 10월이면 끝입니다. 지금 이 글을 통해, MySQL 업그레이드 시 주의해야 할 점들을 알아보세요.
MySQL 5.7이 2023년 10월 31일에 커뮤니티 지원이 종료하게 되었고 그에 따라 AWS에서는 MySQL 5.7의 지원을 본격적으로 종료하기 시작했습니다.
RDS for MySQL 5.7의 경우 2024년 2월 29일에 종료되었고 Aurora MySQL 5.7은 2024년 10월 31일에 종료됩니다. 1개월의 유예 기간을 거쳐 12월부터 지원 종료에 따른 Extended Support Mode가 진행되었습니다. 이 뜻은 AWS에서 MySQL 5.7을 사용할 경우 추가 비용을 더 지불하게 됨을 의미합니다.
그 비용은 db.r6i.2xlarge 기준, 기존의 서버 운영비의 약 70%에 달합니다. 따라서 비용절감이 화두가 되고 있는 지금 MySQL 5.7을 AWS에 유지하고 있다면 반드시 MySQL 8.0으로 업그레이드를 고려하는 것이 좋습니다.
MySQL 8.0 버전업을 위해 주의해야 할 사항들이 있습니다. 주로 5.7과 8.0의 버전 차이에서 기인하는 문제들인데 꼼꼼하게 짚고 분석해보시길 추천드립니다.
현재 Aurora 버전이 최소 2.11 이상이어야 3.x대로 업그레이드가 가능합니다. AWS 콘솔이나 CLI에서 아래 명령어를 통해 버전을 확인할 수 있습니다.
aws rds describe-db-engine-versions --engine aurora-mysql \\ --engine-version 5.7.mysql_aurora.2.07.10 \\ --query 'DBEngineVersions[].ValidUpgradeTarget[].EngineVersion’
MySQL 8.0에서는 이전에 없었던 예약어가 도입되었습니다. 테이블, 컬럼 이름으로 예약어를 사용할 수 없게 됩니다. 예약어는 MySQL 8.0 인플레이스 업그레이드 시 prechecks를 통해 찾아낼 수 있습니다. RANK, SYSTEM, WINDOW 등이 새로 예약어로 추가되었으니 충돌나는 것은 반드시 수정해야 합니다.
MySQL 8.0의 기본 캐릭터셋이 utf8mb4로 변경되었고 기본 Collation도 utf8mb4_0900_ai_ci로 변경되었습니다. utf8mb3 캐릭터셋을 사용한다면 utf8mb4를 사용하도록 권고합니다. 이 부분은 업그레이드에 영향을 주진 않습니다. 하지만 변경월 원할 시에 아래 주의할 점이 있습니다.
문자열 정렬 순서가 달라지는 것을 검토해야 합니다. 가령 5.7에서는 대문자 이후 소문자를 정렬하는 경우가 있고 8.0은 소문자 > 대문자 순으로 정렬됩니다.
# MySQL 5.7
Apple
Banana
apple
banana
# MySQL 8.0
apple
Apple
banana
Banana
Collation 변경 시 테이블 및 인덱스 리빌드가 발생합니다. 따라서 운영 중에 변경을 하게 되면 리빌드 시간이 길게 걸리고 메타데이터 잠금이 걸릴 수 있습니다. 버전업 당일 전에 해당 작업을 완료할 수 있도록 적절한 조치가 필요합니다.
현재의 설정은 아래 쿼리로 검토 가능합니다.
# 데이터베이스 단위
SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA;
# 테이블 단위
SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys');
MySQL 5.7에서 mysql_native_password를 사용 중이라면 caching_sha2_password 인증 방식으로 변경됩니다. 다만 mysql_native_password을 명시적으로 설정해 계속 사용할 수는 있습니다. 또한 아래 코드를 통해 mysql_native_password 형식으로 암호화하는 방식을 사용할 수 있습니다.
CONCAT('*', UPPER(SHA1(UNHEX(SHA1(_STR))))
MySQL 5.7에서는 datetime = ‘’로 빈 값을 처리 가능하지만 MySQL 8.0에서는 빈 값이 허용되지 않습니다. 만약 데이터에 빈 값이 들어있다면 null로 치환해야 합니다. 또한 최저 가능 날짜가 DATE/DATETIME: '1000-01-01', TIMESTAMP: '1970-01-01’로 허용되니 만약 ‘0000-00-00’로 저장되어 있다면 값을 수정해야 합니다.
만약 잘못 저장된 Datetime의 값이 방대하고 사이드이펙트가 우려된다면 권고하진 않지만 SQL mode에서 NO_ZERO_INDATE, NO_ZERO_DATE 옵션을 비활성화해서 현행을 유지할 수 있습니다. 너무 오래된 레거시가 있어서 검토 및 수정이 엄두가 안 난다면 적용해볼만 합니다.
아래처럼 특수문자를 사용할 경우 8.0에서는 엄격한 룰로 인해 문법 파싱이 되지 않을 수 있습니다. 만약 사용할 수 없다면 Aurora 업그레이드 prechecks에서 에러를 발생시키게 됩니다. 사용하는 변수에서 특수문자를 제거하는 것이 좋습니다.
DELIMITER $$
CREATE PROCEDURE `p`()
BEGIN
DECLARE `temp-var` INT;
SET `temp-var` = 1;
SELECT `temp-var`;
END $$
DELIMITER ;
아래와 같은 스크립트를 통해 특수문자 사용 케이스를 확인하고 수정해야 합니다.
SELECT ROUTINE_SCHEMA, ROUTINE_NAME
FROM information_schema.routines
WHERE ROUTINE_DEFINITION LIKE '%@%'
OR ROUTINE_DEFINITION LIKE '%-%'
OR ROUTINE_DEFINITION LIKE '%$%'
OR ROUTINE_DEFINITION LIKE '%#%';
MySQL 5.7은 innodb_large_prefix 파라미터를 지원해 row_format이 dynamic이 아니어도 인덱스 길이 767 bytes 이상을 지원했지만 MySQL 8.0은 row_format을 dynamic으로 설정해야만 가능합니다.
SHOW TABLE STATUS LIKE 'table';
# row_format이 compact 또는 redundant인 경우
ALTER TABLE table ROW_FORMAT = DYNAMIC;
MySQL 8.0에서는 함수로 디폴트를 설정하는 것을 허용하지 않습니다. 따라서 아래와 같은 경우 변경이 필요합니다.
CREATE TABLE settings (
id INT PRIMARY KEY,
config JSON DEFAULT JSON_OBJECT() -- 함수 사용 → 오류
);
->
CREATE TABLE settings (
id INT PRIMARY KEY,
config JSON DEFAULT ('{}') -- 허용: 리터럴 문자열로서 유효한 JSON
);
5.7에서는 허용되던 암시적 GROUP BY가 오류 발생 가능합니다. 아래 쿼리처럼 불완전한 group by가 있다면 정상적으로 변경해줘야 합니다.
SELECT department, employee_name
FROM employees
GROUP BY department;
->
SELECT department, employee_name
FROM employees
GROUP BY department, employee_name;
쿼리 실행 계획이 5.7과 다를 수 있습니다. EXPLAIN을 재실행해서 쿼리가 효율적으로 잘 동작하는지 확인할 필요가 있습니다. 다만 많은 쿼리를 사용할 경우 이 부분을 전수 조사하기에는 리소스가 부족할 수 있으니 안전하게 진행해야 할 경우 권고하는 사항입니다.
전환 시에 블루그린 배포 방식을 쓸 경우 논리적으로 중복 키 에러가 발생할 수 있습니다. 블루 클러스터에서 쓰기 중에 그린 클러스터에서도 일부 쓰기가 발생할 경우 트래픽이 그린으로 전환되면서 충돌하는 primary key가 발생할 수 있습니다. 다만 AWS에서는 자체적으로 블루그린 배포 시 그린 복제본을 구성한 후 쓰기를 제한하니 문제는 되지 않습니다.
MySQL 8.0으로의 전환, 어렵지 않습니다. 단계별로 체크리스트를 뽑고, 반드시 운영 반영 전에 테스트를 해보는 것이 중요합니다.
우리 팀은 이 과정을 거쳐,
수천만 건의 데이터 문제 없이 마이그레이션했고
월 5,000달러 이상의 비용을 절감했으며
장애 없이 릴리즈를 마쳤습니다.
현재 사용하고 있는 환경이나 상황에 따라 MySQL 8.0 클러스터를 신규 생성하고 이전하는 과정에서 오류가 날 각종 상황이 존재할 수 있습니다. 따라서 아래의 절차를 따라 운영에 배포 전에 미리 테스트를 해볼 필요가 있습니다.
운영 중인 데이터베이스를 클론해서 생성
데이터베이스를 Clone해서 테스트, 개발환경에서 테스트를 꼼꼼히 진행한 후에 운영에서 진행하면 좋습니다. 개발환경에서 사용하는 데이터베이스가 이미 있다고 하더라도 다음을 고려해야 합니다.
버전업 테스트하다가 장애 발생 시 내부 고객인 개발자들이 개발 환경을 사용할 수 없습니다
개발 환경의 데이터베이스에 들어있는 데이터가 최신화가 안되어 있을 수 있습니다. 또한 운영의 데이터가 다르므로 운영에서 내포하고 있을 문제들을 재현할 수 없습니다.
클론한 데이터베이스로 버전업 테스트
버전업을 하면서 prechecks에서 발생하는 문제를 해결하고, 실제 상용에서 할 것처럼 똑같은 프로세스로 클러스터를 구성하고 데이터를 마이그레이션해 봅니다. 그 과정에서 발견되는 문제들을 리스트업하고 정리합니다. 배포 시점에 적용해야 될 사항들이 있는 경우 론칭 플랜 문서를 작성하고 필요 내용을 기술해서 실수를 미연에 방지합니다
클론한 데이터베이스로 일정기간 사용하거나 QA
데이터베이스를 사용 중에 특정 쿼리의 문제로 동작하지 않을 수 있습니다. 때문에 전수, 혹은 중요한 로직들을 QA해보거나 개발환경 대신 해당 환경으로 내부에서 사용해보는게 필요합니다.
위 3가지 과정에서 미리 테스트를 해본다면 충분히 상용에서 MySQL 버전업을 할 수 있는 자신감이 생기리라 생각합니다.
FinOps 커뮤니티에 함께 하실래요?
저는 최근 48%, $36000의 AWS 비용절감을 달성했습니다.
클라우드 비용을 효율화하고 싶은 분들, 비슷한 고민을 나누고 싶다면 제가 운영 중인 AWS-FINOPS-KR Slack 커뮤니티에 참여하세요. 실제 절감 사례, 질문, 전략 공유를 나누실 수 있습니다.