스마트스토어, Oracle 탈출! MySQL 전환으로 성능과 비용 두 마리 토끼를 잡다

by DD
4개월 전
조회수 32

Oracle DBMS의 라이선스 비용 증가와 성능 불안정 문제를 해결하기 위해 MySQL로의 마이그레이션(Migration)을 결정

이중 쓰기(Dual Write) 방식을 통해 서비스 중단 없이 데이터 정합성(Data Consistency)을 유지하며 전환

JPA 이중 쓰기(JPA Dual Write), MyBatis 이중 쓰기(MyBatis Dual Write) 구현 및 쿼리/DBMS 성능 검증을 통해 안정성 확보

성능 모니터링(Performance Monitoring)을 통해 쿼리 튜닝(Query Tuning)을 수행하여 API 응답 지연 시간(Latency) 개선

Airflow를 활용한 데이터 정합성 검증 자동화로 데이터 불일치(Data Inconsistency)를 100% 해결

Oracle 세션 수 감소 및 메모리 자원 확보로 서비스 확장성(Service Scalability)을 위한 기반 마련

무중단 전환을 위한 이중 쓰기(Dual Write) 전략

스마트스토어센터는 무중단 배포(Zero-downtime Deployment)를 위해 이중 쓰기(Dual Write) 방식을 채택했다. 이 전략은 모든 쓰기 트랜잭션(Transaction)을 기존 Oracle DB와 신규 MySQL DB에 동시에 반영하는 방식으로, 신규 시스템의 안정성을 검증하는 기간 동안 두 DB 간의 데이터 동기화(Data Synchronization)를 보장한다.

전환 전 단계: Oracle DB에 모든 Read/Write 트래픽 처리, CUD(Create, Update, Delete) 작업 시 MySQL에 이중 쓰기 수행

데이터 마이그레이션: 신규 애플리케이션 배포 전 Oracle 데이터를 MySQL로 마이그레이션하여 데이터 정합성(Data Consistency) 확보

전환 후 단계: MySQL에서 모든 Read/Write 트래픽 처리, CUD 작업 시 Oracle에 이중 쓰기 수행

이러한 구조를 통해 롤백(Rollback)이 필요한 경우에도 별도의 데이터 복구 과정 없이 즉시 롤백할 수 있는 유연성을 확보했다.

JPA 이중 쓰기(Dual Write) 구현과 트랜잭션 처리

JPA를 사용하는 환경에서 이중 쓰기(Dual Write)를 구현하기 위해, datasource-proxy 라이브러리(Library)를 활용하여 Oracle에서 수행되는 쿼리를 캡처하고 MySQL DataSource로 실행하도록 설정했다. 하지만, 트랜잭션(Transaction) 내에서 여러 쿼리가 수행될 때 두 DB 간의 정합성(Consistency) 문제가 발생할 수 있다.

ChainedTransactionManager 또는 분산 트랜잭션(Distributed Transaction) 사용 지양: MySQL 쿼리 실패 시 트랜잭션 롤백으로 인해 Oracle과 MySQL 간 데이터 불일치 발생 가능성

MySQL 쿼리 실패 허용: MySQL 쿼리는 트랜잭션에 포함하지 않고, 실패하더라도 롤백되지 않도록 설정

TransactionSynchronizationManager 활용: 트랜잭션 커밋 시점에 MySQL 쿼리를 한꺼번에 실행하여 Oracle 커넥션 점유 시간(Connection Time)을 최소화

결과적으로, MySQL 쿼리 실패를 용인하고 주기적인 정합성 검증을 통해 불일치 문제를 해결하는 방식을 선택했다.

MyBatis 이중 쓰기(Dual Write) 구현

MyBatis 이중 쓰기(Dual Write) 구현 시, 비즈니스 로직 코드 수정 없이 Oracle과 MySQL 양쪽으로 쓰기 작업을 수행하기 위해 CombinedSqlSessionFactory를 활용했다. 이는 비즈니스 로직의 순수성을 유지하면서 이중 쓰기 로직을 중앙 집중화하여 관리하고, 마이그레이션 완료 시점에 이중 쓰기 코드를 쉽게 제거할 수 있도록 하기 위함이다.

CombinedSqlSessionFactory: Oracle과 MySQL 두 개의 SqlSession을 생성하고, Proxy 객체(Proxy Object)를 통해 양쪽 DB에 쿼리 실행

CombinedSqlSessionHandler: Oracle과 MySQL SqlSession을 모두 보유하며, CUD(Create, Update, Delete) 액션 시 양쪽 DB에 쿼리 실행

READ 쿼리: Oracle DB의 결과 사용

이러한 구조를 통해 MyBatis XML 쿼리를 MySQL 문법에 맞게 재작성하여 이중 쓰기를 구현했다.

쿼리/DBMS 성능 검증 및 Read 트래픽 복제

MySQL로의 전환 과정에서 기존 Oracle 환경에서 안정적으로 처리되던 대규모 트랜잭션(Transaction)과 복잡한 쿼리가 MySQL 환경에서도 동일한 성능을 보장하는지 검증하는 것이 핵심 과제였다. 이를 위해, Read 트래픽 복제(Read Traffic Replication) 방식을 채택하여 운영 환경에 영향을 주지 않으면서 성능 검증을 수행했다.

Read 메서드 캡처: 기존 Oracle로 향하는 Repository 계층의 Read 메서드 호출 시 실행 시간, 메서드 이름, 매개변수 값 캡처

Kafka 메시지 큐 활용: 캡처된 데이터를 JSON으로 직렬화하여 Kafka 메시지 큐로 전송

Java Reflection API 활용: MySQL을 바라보는 Repository 인터페이스의 동일한 메서드를 찾아 매개변수를 주입하고 호출

이러한 과정을 통해 쿼리 실행 시간 분포를 시각화하고, 성능이 좋지 않은 쿼리에 대한 튜닝(Tuning)을 수행했다.

데이터 정합성 검증 자동화

데이터 정합성(Data Consistency) 확보를 위해, Airflow를 활용하여 정합성 검증 프로세스를 자동화했다. 이는 이중 쓰기(Dual Write) 로직의 문제로 인한 데이터 불일치를 사전에 방지하고, 최종 전환 전에 두 DBMS 간의 데이터 일치 여부를 정량적으로 검증하기 위한 필수적인 과정이었다.

Airflow 파이프라인: 주기적으로 Oracle DB와 MySQL DB의 주요 테이블 데이터를 추출하여 Hive 데이터 웨어하우스로 통합

Hive 분산 쿼리: 두 데이터셋을 비교하여 레코드 수 비교, 핵심 칼럼 값의 해시 비교, 주요 비즈니스 통계 값의 차이 검출

불일치 건 분석 및 수정: 발견된 불일치 건에 대해 상세 분석 및 수정을 거쳐 두 데이터베이스 간의 정합성 100% 보장

이러한 엄격한 검증 단계를 통해 신규 MySQL 환경으로의 최종 컷오버(Cutover)를 위한 안전성을 확보했다.

MySQL 환경에서의 트러블슈팅(Troubleshooting) 및 성능 개선

MySQL로의 전환 과정에서 겪은 몇 가지 트러블슈팅(Troubleshooting) 사례와 성능 개선을 위한 고려 사항을 공유한다. 특히, MySQL의 Index Merge Optimization과 Spring Batch를 활용한 마이그레이션 배치 성능 이슈에 대한 해결 방안을 제시한다.

Index Merge Optimization: OR 조건이 복잡한 경우 풀스캔(Full Scan)을 사용하는 문제 발생, UNION 쿼리로 변경하여 해결

Spring Batch 페이징 쿼리 튜닝: 다중 PK 테이블의 페이징 쿼리 성능 저하 문제 발생, 커스텀 QueryProvider 구현을 통해 최적화

HikariCP 설정: MySQL에 권장되는 설정 적용(cachePrepStmts, useServerPrepStmts 등)

이러한 트러블슈팅과 성능 개선 노력을 통해, Oracle 데이터베이스의 세션 수 감소 및 메모리 사용량 감소를 달성하고, 서비스 API의 Latency(응답 지연 시간)를 유의미하게 개선했다.

스마트스토어센터 Oracle에서 MySQL로의 무중단 전환기

댓글 0

첫 번째 댓글을 남겨보세요!