본문 바로가기
Database

리플리케이션의 문제와 해결방법 (복제지연, semi-sync)

by !!e!! 2021. 11. 3.

지난 시간에는 사내에서 DB 리플리케이션이 깨져서 발생한 에러를 계기로 리플리케이션을 하는 이유와 원리, 당시 에러의 원인에 대해 알아보았다. 리플리케이션은 수많은 트래픽을 고가용성으로 대응할 수 있는 해결책이기도 하지만 여느 기술들이 그러하듯 장점만 존재하지 않는다.

어떠한 기술을 받아들이고 학습할때 그 기술의 장점만 보고 무조건적으로 수용하기보다 해당 기술의 단점과 한계를 명확히 알고 비판적으로 수용하는 것이 좋다고 생각한다. 그래서 이번에는 리플리케이션의 복제 지연, 데이터 정합성 문제들을 살펴보고 리플리케이션을 어떻게 활용하는 것이 좋을지 알아보도록 하겠다.




리플리케이션의 구조적 문제와 복제지연

지난 시간의 내용을 간단히 정리해보자면, 리플리케이션은 부하 분산, 백업 등을 위해 데이터베이스를 복제해 Master-Slave 구조로 구성하는 Scale-Out 솔루션이다.

클러스터링이라고도 불리는 동기 복제방식은 데이터 정합성을 보장하는 대신 각 트랜잭션 내에 다른 노드들과 동기화하기 때문에 성능상의 이슈가 있다. (클러스터링에도 논리적 복제를 통한 방식, 물리적 스토리지를 공유하는 방식 등 여러 종류가 있다)

리플리케이션을 고려하는 이유는 결국 백업과 캐싱으로 해결되지 않는 수많은 트래픽에 대응하기 위함이다. 따라서 리플리케이션은 일반적으로 동기 복제방식이 아닌 비동기 복제방식이나 반동기(Semi-Sync) 복제방식을 사용하게 된다. 대부분의 DB 요청이 읽기 작업인 특징을 이용하여 메인 노드는 쓰기작업, 복제 노드들은 읽기 작업으로 사용하여 부하분산하게 된다.

비동기 복제방식은 데이터 정합성이 보장되지 않는 다는 점을 제외한다면 큰 문제가 없어보이지만, 메인 노드와 복제 노드 사이의 동기화 과정을 자세히 보면 필연적으로 병목이 발생할 수 밖에 없다는 것을 알수 있다.

리플리케이션 원리

2 ~ 4번의 과정에서 Master DB의 접속 스레드는 여러 스레드로 분기되어 동시다발적으로 쓰기를 수행하지만, 5 ~ 7번 과정은 Slave DB의 단일 스레드에 의해 순차적으로 수행된다.

즉, 다중 스레드로 쓰기 작업을 수행하는 Master 와 단일 스레드로 쓰기 작업을 수행하는 Slave 간의 속도차에 의해 병목이 발생하게된다. 리플리케이션 과정 중 이러한 병목 현상을 복제 지연이라고 한다.


복제 지연의 원인과 해결 방법

앞서 이야기한 것처럼 복제 지연은 리플리케이션의 구조적인 문제이지만 이를 직접적으로 유발하는 원인들이 있다.

1. 장기 실행 Query

SBR (Statement Based Replication, SQL을 전송하여 복제하는 방식) 방식의 문제이기도한데, 예를 들어 1시간 동안 수행되는 쿼리는 복제본에서 replay 되는 시간도 1시간인것을 고려하여 총 2시간의 지연시간을 가지게 된다.

해결 방법

해당 원인은 SBR 방식의 문제이기도하다. RBR (Row Based Replication, 변경된 결과를 복제하는 방식)방식이나 MBR (Mixed Based Replication, 비결정적 동작(Usafed Statement)의 경우에만 RBR 방식으로 동작) 방식을 통해 해결하기도 하고, 튜닝이나 인덱스를 활용하여 쿼리 성능 자체를 향상시켜 해결하기도 한다.

2. Write 쿼리량 증가

트래픽이 증가하거나 특정 배치 작업으로 인한 쓰기 사용이 많아지면서 발생하는 경우이다.

특히 트래픽 증가로 인한 복제지연의 경우 마스터의 처리 속도를 따라가지 못해 바쁜 시간대에는 갭이 커졌다가 한가한 시간대에 다시 좁혀지는 현상을 반복하게 될수도 있다.

해결 방법

Multi-Threaded Replication 설정을 통해 복제를 적용하는 worker 스레드 개수를 늘려서 처리 속도를 향상시 킬수 있다. 만약 데이터 양 자체도 많고 사용량도 계속 증가하는 경우 샤딩이나 비즈니스적으로 도메인 자체를 분리하여 경량화 하는 것도 도움이된다.

3. Slave(복제본)의 로드 증가

Slave(복제본)에서 실행되는 서비스 조회 트래픽으로 인해 처리 성능이 지연되면서 복제 지연이 발생하는 경우이다.

해결방법

이 경우에는 조회에 대한 트래픽을 감당할 복제본의 양이 부족하다는 의미이기 때문에 복제본을 추가 구성하여 해결할 수 있다.


Semi-Sync Replication + MHA(Master High Availability)

리플리케이션(비동기 복제방식)의 가장 큰 단점은 데이터 정합성이 보장되지 않는다는 것이다. 데이터 정합성이 보장되지 않아도 되는 서비스에서는 비동기 복제방식을 사용해도 되지만, 데이터에 민감한 금융, 결제와 관련된 서비스에서는 어떻게 해야할까? 느리더라도 동기 복제방식만을 고려해야할까?

반동기 복제방식 (Semi-Sync Replication)

MySQL 5.5 부터 반동기 복제방식(Semi-Sync Replication)이 도입되었다. 이 방식은 복제 DB의 데이터 동기화 보장이 아닌 최소 1대이상의 복제본에 복제에 필요한 릴레이 로그(바이너리 로그) 동기화를 보장한다는 것이 핵심이다.

https://gywn.net/wp-content/uploads/2017/06/mysql-semisync-5.7.png

특히 MySQL 5.7.2 부터는 AFTER_SYNC 모드 방식으로 마스터 엔진에 커밋되기 전에 Slave 릴레이 로그 저장을 기다리도록 수정되었다. 이 모드는 중간에 장애가 발생하더라도 엔진에 데이터가 적용되지 않았기 때문에 보다 안정적인 구조가 되었다. (이전의 AFTER_COMMIT 모드는 마스터 엔진 커밋후 릴레이 로그 저장을 기다렸기 때문에 이미 데이터가 적용되어버리는 구조였다)

Semi-Sync Replication은 위와 같은 릴레이 로그 복제 방식을 통해 Slave DB의 모든 데이터 복제과정을 기다리지 않고 더 나아가 여러 Slave 중 단 1대만이라도 릴레이로그 수신했다면 Master DB는 해당 트랜잭션을 완료한다. 따라서 릴레이 로그 보장으로 최소한의 데이터 정합성을 확보하면서도 특정 Slave DB의 지연이 트랜잭션 지연으로 이어지지 않게 된다.

MHA (Master High Availability)


https://hoing.io/storage/2020/12/mha4.png

MHA는 Master DB의 고가용성을 위해 개발된 오픈소스로서 리플리케이션 환경에서 Master DB의 장애 발생시 Master 헬스 체크를 주기적으로 수행하던 Slave에서 자동으로 가장 최신 상태의 Slave DB를 Master DB로 승격시켜 Fail-Over 하는 것을 말한다. 또한 MHA는 Slave DB 간의 릴레이 로그(바이너리 로그) 차이를 해결하는 기능을 하여 고가용성 상태를 유지하게 된다.

반동기 복제방식(Semi-Sync Replication) 과 MHA 가 조합되게 되면 마지막에 커밋된 릴레이 로그는 항상 Slave 어딘가에 존재하게 되고, 마스터에 장애가 발생하더라도 릴레이 로그 복구 과정을 통해 동기화하기 때문에 데이터 유실 가능성은 결국 동기방식과 차이가 없게 된다.

https://gywn.net/wp-content/uploads/2017/06/semi-sync-repl.png

코딩 수업 선생님과 학생들

위 과정을 쉽게 설명하기 위해 '코딩 수업'에 비유하여 예를 들어 보겠다.

리플리케이션 과정을 코딩 수업이라고 했을때, Master는 코딩 수업의 선생님, Slave는 코딩 수업의 학생이라고 할 수 있다.

동기 방식은 코딩 선생님이 모든 학생들이 선생님의 코딩 현황과 일치할때까지 다음 진도를 나가지 않고 기다리는 것과 같다. 모든 학생들이 선생님의 코딩 현황과 같겠지만, 당연히 수업진도가 많이 느려질 것이다.

비동기 방식은 코딩 선생님이 PPT로 코딩하는 방법을 순차적으로 보여주며 수업을 진행하고 학생들은 PPT에 적힌 수업내용을 받아적는다. 선생님은 학생들의 코딩 현황을 고려하지 않고 수업 진도를 나가고 학생들은 받아적은 내용을 따라하며 코딩 선생님의 코딩 현황과 최대한 맞춰가는 방식이 비동기 방식이라고 할 수 있다. 수업 진도는 빠르지만, 학생들이 선생님의 진도에 맞춰 따라왔는지에 대한 부분은 보장할 수 없을 것이다.

반동기 방식(Semi-Sync)은 코딩 선생님이 PPT로 수업을 하며 단 1명의 학생이라도 수업내용을 받아 적었다는 것이 확인되면 다음 진도로 진행하는 것이다. 이렇게 진행하면 수업 진도는 동기 방식보다 훨씬 빠르게 진행되고, 항상 현재까지의 모든 수업 내용을 받아적은 학생이 반드시 있게된다.

여기서 MHA(Master High Availability)까지 적용해보면, 코딩 선생님이 중요한 통화로 수업에 잠시 빠지더라도, 모든 수업 내용을 받아적은 학생의 필기를 공유하며 결국 모든 학생들은 선생님의 코딩 현황까지 완료하게되고 해당 우수 학생이 코딩 수업을 잠시 진행하는 선생님이 되게 된다.

https://hoing.io/storage/2020/12/mha3.png


결론

이번 내용들은 개발자로서 DB에 대한 이해도가 높이는것 뿐만 아니라 서버를 운영하는 과정에서도 인사이트가 될만한 지점들이 많이 있었다고 생각한다. 다음 시간에는 트래픽 뿐만아니라 데이터의 양 자체가 많은 경우에 고려하게되는 샤딩에 대해 정리해보도록 하겠다.


참고 링크

Amazon RDS for MySQL을 사용하여 긴 복제 지연 문제 해결

MySQL Replication

[MySQL][Master-Slave] 복제 환경에서 Binary Log 특징

[MySQL] 슬레이브 하나 더 추가했을 뿐인데.. :-)

MySQL MHA(Master High Availability) 1 - MHA 기능 설명 및 아키텍처 설명