AWS 기술 블로그
Sendbird의 Amazon Aurora MySQL 에서의 대용량 테이블 스키마 변경을 위한 SB-OSC 개발 및 적용 사례
Sendbird는 채팅, 음성/비디오 콜, In App Notification, AI Chatbot등의 메세징/커뮤니케이션 플랫폼을 통해 고객의 비즈니스에 가치를 제공하는 글로벌 SaaS 기업입니다.
Sendbird는 전 세계 10개 AWS Region을 통해 매달 3억명의 사용자가 생성하는 70억건의 메세지를 Amazon Aurora MySQL을 활용해 처리하고 저장하고 있습니다. 이번 게시글에서는 Sendbird가 대용량 Amazon Aurora MySQL을 어떻게 효율적으로 관리하고 운영하는지 알아봅니다.
Amazon Aurora MySQL 대용량 테이블의 효율적인 스키마 변경을 멀티스레딩 기반 SB-OSC
Sendbird는 2023년 5월에 신규 출시된 Amazon Aurora I/O-Optimized 클러스터 구성을 적용하여 Amazon Aurora MySQL을 운영하면서 발생하는 비용을 절감하고 대량의 I/O가 필요한 Schema 변경, Amazon Aurora Cluster Migration(주요 버전 업그레이드), Data retention 관리 등과 같은 작업들을 효율적으로 진행하기 위한 계획을 수립하였습니다.
Sendbird에서는 메세징/커뮤니케이션 플랫폼 특성상 실시간으로 대량의 쓰기 작업과 읽기 작업이 빈번하게 일어나고 있습니다. Sendbird와 같이 I/O 집약적 환경에서 Amazon Aurora MySQL을 운영하는 환경에서는 향상된 성능과 예측 가능한 요금을 제공하는 새로운 클러스터 구성인 Amazon Aurora I/O-Optimized의 사용이 고객의 워크로드 운영및 비용 효율화에 많은 도움이 됩니다.
Amazon Aurora MySQL 버전2(AMS2)를 사용하고 있던 Sendbird에서는 Amazon Aurora I/O-Optimized 적용을 통한 성능 향상과 비용 효율화를 위해 Amazon Aurora MySQL 버전3(AMS3)로 업그레이드를 진행하였고 이 과정에서 Amazon Aurora MySQL의 특성을 살리며 작업의 효율성을 높일 수 있는 SB-OSC 툴을 개발하여 오픈소스로 공개하였습니다.
Sendbird의 SB-OSC 개발 배경 및 구성
온라인 스키마 변경은 MySQL 데이터베이스를 기반으로 서비스를 개발하고 운영하는 데 있어서 매우 자주 사용되고 필요한 작업입니다. 데이터베이스 운영 환경에서는 데이터 구조의 지속적인 최적화, 새로운 기능의 추가, 성능 개선, 또는 데이터 보안 강화를 위해 기존 테이블 구조를 변경해야하는 작업들이 자주 발생합니다. 이러한 변경을 오프라인으로 수행하게 되면 서비스 중단이 불가피해지며, 이는 사용자 경험 저하 및 비즈니스에 심각한 영향을 미칠 수 있습니다. 따라서 다운타임 없이 데이터베이스 스키마를 변경할 수 있는 온라인 스키마 변경 방식이 매우 중요합니다.
기존의 온라인 스키마 변경을 도와주는 gh-ost, fb-osc, pt-osc와 같은 툴은 각각 싱글 프로세스 툴로 작업의 진행 상황을 저장하지 않습니다. 스키마 변경은 다양한 원인들(ex 프로세스 오류, 테이블 락 경합, 부하로 인한 OS Kill)로 중단되거나 종료될 수 있으며, 이 경우 스키마 변경을 재개 할 수 없었습니다. 중단된 작업을 처음부터 재시작하기 위해서는 잔여 테이블을 정리해야 하며, pt-osc와 fb-osc의 경우 남아 있는 트리거도 제거하야 합니다. 특히 대규모 테이블에서 이러한 문제는 더욱 심각한 상황으로 발전할 수 있습니다. 수백 Gbytes에서 수 TBytes에 이르는 데이터를 갖는 테이블에 대한 온라인 스키마 변경 작업이 수 주에서 수 개월까지 늘어나게 되면, 비즈니스의 빠른 변화와 성장에 데이터베이스가 대응하지 못할 수 있으며 이는 곧 큰 기술 부채로 이어질 수 있습니다.
Sendbird는 대용량 테이블 스키마 변경의 경험을 바탕으로 멀티스레딩 기반의 새로운 MySQL 온라인 스키마 변경 툴을 통해 기존 툴들의 시간적 한계를 극복하며, 대규모 테이블에서도 스키마 변경 작업을 수 일 이내로 대폭 단축시킵니다. 또한, SB-OSC는 작업이 어떻게 실패하더라도 binlog만 살아있다면 끊어진 지점에서 완벽하게 작업을 재개할 수 있는 강력한 기능을 제공합니다. 이는 기존에 수 개월이 소요되던 작업 시간을 혁신적으로 개선하며, 기존에 거의 불가능에 가까웠던 대규모 OLTP 테이블에서의 스키마 변경을 가능하게 하였습니다.
SB-OSC의 설계는 두 가지 핵심 철학에 근거합니다.
- 작업이 중단되거나 재시작 될 때 중단 시점에서 재개할 수 있는 능력을 갖추는 것입니다. 이를 위해, SB-OSC는 작업을 명확히 정의된 단계별로 나누고, 각 단계의 진행 상황을 데이터베이스에 기록합니다. 또한, 각 단계의 진행 정도를 복구할 수 있도록 필요한 최소한의 데이터를 데이터베이스에 저장합니다. 이렇게 함으로써, 작업이 중단되었을 때 중단된 단계에서부터 재개할 수 있습니다. 이는 작업의 중단 및 재시작에 따른 복잡성과 위험을 대폭 줄여줍니다.
- SB-OSC는 멀티스레딩을 통한 성능 최적화를 추구합니다. 이를 위해, SB-OSC는 원본 데이터를 복사하는 ‘Bulk import’ 단계와 ‘DML 이벤트 반영’ 단계를 분리하였으며, DML 이벤트를 기존의 구문 반영 방식이 아닌, 원본 데이터를 primary key(이하 PK)로 조회하여 복사하는 방식으로 처리합니다. 이러한 설계는 복잡한 DML 이벤트의 순서에 신경 쓰지 않아도 되며, 원본 테이블의 최종 상태만 정확하게 맞추면 되기 때문에 멀티스레딩을 적용하는 데 큰 이점을 제공합니다.
특히, binlog를 파싱하는 단계에서도 분당 수 GBytes의 binlog가 생성되는 상황을 극복하기 위해 멀티스레딩을 지원할 수 있도록 구현하였습니다. SB-OSC는 binlog 파일 단위로 멀티스레딩을 적용하여, 일반적인 상황에서는 단일 스레드로 운영되지만, 필요에 따라 여러 binlog 파일을 동시에 처리할 수 있습니다. 대량의 DML 이벤트가 발생하여 단일 스레드로 binlog 파싱 속도가 쌓이는 속도를 따라가지 못하는 상황에서 SB-OSC는 이를 통해 초당 수천 개의 DML 이벤트가 발생하는 테이블에서도 실시간에 가까운 binlog 파싱을 가능하게 합니다.
일반적으로 스키마 변경 작업에서 속도를 향상시키기 위해 멀티스레딩을 사용하게 되면 데이터 정합성을 보장하기 어려워질 수 있습니다. SB-OSC는 실제 운영 환경에서 발생할 수 있는 duplicate key, deadlock, connection error, timeout과 같은 다양한 문제들을 자체적으로 해결하고 정합성을 보장하기 위해, 여러 안전장치와 데이터 정합성 검증 로직을 구현하고 있습니다.
SB-OSC는 binlog 파싱과 bulk import 두 구간에서 모두 높은 성능을 보입니다.
테스트 환경
SB-OSC는 AWS Aurora MySQL과 EKS위에서 동작하는 것으로 설계가 되었습니다
- AWS Aurora MySQL 버전2와 AWS Aurora MySQL 버전 3 클러스터
- EKS 클러스터
- Redis (EKS 위의 컨테이너)
- binlog_format: ROW
- binlog-ignore-db: sbosc (권장)
- Controller : 전체 프로세스를 제어하고 데이터 검증 단계를 수행합니다.
- EventHandler : Binlog를 파싱해서 DML 이벤트를 캡처합니다.
- Worker : 새 테이블에 DML 쿼리를 수행합니다. 원본 테이블에서 데이터를 복사하고 EventHandler가 캡처한 DML 이벤트를 반영합니다.
- Monitor : AWS CloudWatch 메트릭을 모니터링하여 처리량을 제어하고 Prometheus 형식으로 메트릭을 내보냅니다.
SB-OSC는 총 4개의 컴포넌트로 구성되는데, 각각은 별도의 StatefulSet으로 배포됩니다. Binlog를 파싱하는 컴포넌트가 약 2 vCPU를 사용하고 나머지 컴포넌트들은 대부분의 경우에 0.5 vCPU 이하를 점유합니다.
gh-ost와 비교
기존 스키마 변경 툴과의 성능을 비교하기 위해, 동일한 조건 내에서 SB-OSC와 gh-ost 의 전체 작업 시간을 비교해 보았습니다. gh-ost도 SB-OSC와 같이 binlog를 파싱해서 DML 이벤트를 가져오기 때문에 비교군으로 채택되었습니다. 다음은 테스트 환경 명세입니다.
- 약 2억 개의 레코드가 있는 테이블
- Aurora MySQL v3 클러스터, r6g.8xlarge 인스턴스
- 인덱스 2개
- batch_size (gh-ost는 chunk-size): 50000
- (gh-ost) —allow-on-master
추가 DML 부하가 없는 경우
스키마 변경 툴 | 전체 작업 시간 | CPU 사용량 (%) |
SB-OSC | 22분 | 60.6 |
gh-ost | 1시간 52분 | 19.7 |
추가 DML 부하 발생 시
작업 시간 동안 추가 DML 부하는 테이블 C에만 발생시켰습니다. (~1.0K inserts/s, ~0.33K updates/s, ~0.33K deletes/s)
스키마 변경 툴 | 전체 작업 시간 | CPU 사용량 (%) |
SB-OSC | 27분 | 62.7 |
gh-ost | 1일 이상 | 27.4 |
gh-ost의 경우 약 50% (~12h) 진행률인 상황에서 종료 예정 시간이 계속 늘어나고 있어 작업을 중단하였습니다. SB-OSC는 큰 DB 인스턴스가 제공하는 CPU를 충분히 사용하여 높은 insert throughput으로 데이터를 복사할 수 있었습니다. DML 이벤트 반영 단계의 최적화로 인해, 추가 DML 부하가 발생하는 환경에서는 기존 스키마 변경 툴과 더 큰 차이를 보여줍니다.
SB-OSC를 활용한 대용량 Amazon Aurora MySQL 관리사례
SendBird에서는 SB-OSC를 온라인 스키마 변경이외에 대용량Amazon Aurora MySQL을 운영하면서 다양한 사례에 활용하고 있습니다.
1. Amazon Aurora MySQL Migration (AMS2 에서 AMS3으로 Major Version Upgrade 시)
운영중인 데이터베이스를 업그레이드 하는것은 매우 복잡하고 많은 공수가 발생하는 작업입니다. Sendbird는 Amazon Aurora I/O-Optimized 클러스터를 적용하기 위해서 기존에 사용하고 있는 AMS2를 AMS3으로 Upgrade 해야 했습니다.
가장 많이 사용하는 Blue/Green Deployment를 활용한 Upgrade 방식은 Sendbird의 서비스에서 생성되는 Binlog를 처리하기 위한 성능적인 이슈에 부담이 되었습니다. 특히, MySQL의 기본 복제가 외부 마스터를 따라잡을 수 없을 때 높은 Binlog 읽기 처리량을 통해 클러스터 복제를 따라갈 수 있도록 SB-OSC를 사용했습니다. 원본 AMS2 데이터베이스를 복제하고, 복제본을 AMS3로 업그레이드한 후, 소스 클러스터를 외부 마스터로 설정하여 MySQL binlog 복제를 트리거 하였습니다.
이 사례에서 SB-OSC를 사용하면 대량 가져오기 단계를 건너뛸 수 있으며, 지정된 파일과 위치에서 시작하는 DML 이벤트만 설정하면 SB-OSC가 적용하게 됩니다. 쓰기 부하가 많은 클러스터의 경우 복제가 따라잡지 못해 쓰기 부하가 가장 높은 한두 개의 테이블은 SB-OSC로 복제하고, 나머지는 앞의 경우와 유사하게 ‘replicate-ignore-table’을 설정하여 MySQL binlog 복제로 복제했습니다.
2. 데이터 보존 주기 관리
Amazon Aurora I/O-Optimized 클러스터는 Standard 클러스터 유형보다 인스턴스 비용은 30%, 스토리지 비용은 125% 상승하게 됩니다.(단, 별도의 IO 비용은 과금 되지 않습니다) 따라서 데이터 보존 주기 관리는 매우 중요합니다. 삭제 할 데이터의 양이 적은 경우에는 Delete 쿼리를 사용하여 데이터 보존 주기 관리를 수행하는 것으로 충분합니다. 그러나 TBytes 단위의 데이터를 삭제해야 하는 경우, 운영 환경에서 Delete 쿼리를 실행하면 I/O 처리량이 증가할 뿐만 아니라 서비스 지연 시간 측면에서 아주 중요한 교착 상태가 발생할 수 있으므로 매우 위험할 수 있습니다. 이 경우 만료되거나 일회용 데이터 없이 테이블을 재구축하는 것이 더 적절한 해결책이 될 수 있으며 이 때 SB-OSC를 활용할 수 있습니다. SB-OSC를 사용하면 사용자 정의 작업 클래스를 정의하여 테이블을 복사할 때 사용되는 쿼리를 재정의할 수 있습니다. 이 기능을 활용하여 사용자, 채널 등에 따라 달라지는 복잡한 데이터 보존 주기 관리정책을 사용자 정의 작업 클래스에 활용하여 여러 클러스터에 성공적으로 적용할 수 있었습니다.
Limitations
SB-OSC는 멀티스레딩을 효과적으로 활용하고 중단된 작업의 재개가 용이하기 때문에, 대규모 테이블에서의 대량 DML 처리와 관련하여 기존의 오픈 소스 툴들보다 뛰어난 성능을 제공합니다. 그러나 SB-OSC 역시 몇 가지 한계점을 가지고 있습니다.
- 정수형 Primary Key 필요성
SB-OSC는 bulk import 단계에서 테이블을 정수형 PK를 기준으로 나누어 멀티스레드로 작업을 수행합니다. 이는 batch 처리 등도 모두 정수형 PK를 기준으로 설계되었기 때문입니다. 그 결과, PK가 정수형이 아닌 테이블에서는 SB-OSC를 사용할 수 없습니다.
- Primary Key 업데이트 이슈
SB-OSC는 PK를 기준으로 원본 테이블의 레코드를 다시 복사하는 형태로 DML 이벤트를 반영합니다. 따라서 테이블의 PK에 업데이트가 발생하는 경우, 데이터의 정합성을 보장하기 어려워집니다.
- Binlog의 해상도 제한
SB-OSC는 binlog의 해상도가 초(second) 단위라는 점에서 제한을 받습니다. 이는 SB-OSC의 설계 특성상 대부분의 상황에서 큰 영향을 주지 않지만, 초 단위에 과도한 이벤트가 발생하는 경우, timestamp를 기준으로 하는 로직에 일부 영향을 줄 수 있습니다.
- 소규모 테이블에서의 효율성 저하
소규모 테이블에서는 SB-OSC의 초기 테이블 생성, chunk 생성, 여러 단계로 나뉜 프로세스 등이 오히려 오버헤드로 작용할 수 있습니다. 이는 전체적인 속도를 저하시킬 수 있어, 작은 테이블에 SB-OSC를 적용하는 것은 그다지 효과적이지 않을 수 있습니다.
결론
이 게시글에서는 실시간 대량 트랜잭션 환경을 운영하는 Sendbird에서 다년간 Amazon Aurora MySQL 을 운영하며 얻은 경험과 노하우를 바탕으로 대용량 Aurora MySQL 에서의 업그레이드 및 복제를 위해 개발한 SB-OSC 에 대한 개발 과정과 실무 적용 사례를 살펴보았습니다.
현재 대용량 Amazon Aurora MySQL을 운영하면서 스키마 변경, 데이터 이관, 버전 업그레이드 등의 운영 작업에서 Sendbird의 사례와 같은 고민을 가지고 계시다면 SB-OSC(소스코드)를 검토해보시면 도움이 되실 수 있을것입니다.