프로젝트를 진행하며 Primary와 Replication 데이터베이스를 구분했던 방법에 대해 정리한 글입니다. 학습과정에서 작성한 글이기 때문에 잘못된 부분이 있을 수 있습니다.
1. 사용 이유
Replication을 사용하는 이유는 다양하겠지만 크게 장애격리, 분산 두 가지 목적으로 분류할 수 있습니다.
데이터베이스에 접근해서 처리하는 일이 많은데 읽기, 쓰기, 수정의 모든 연산이 하나의 데이터베이스에서 일어난다면 트래픽이 늘어나면 병목 현상이 발생할 수 있습니다. 이를 방지하기 위해 쓰기는 원본 서버에서만, 읽기는 복제 서버에서만 읽도록 하여 병목현상을 감소시킬 수 있습니다. 또한 Replication은 항상 복제를 진행하는게 아닌, 일시중지가 가능합니다. 따라서 원천 데이터를 손상시키지 않고 복제본에서 백업 서비스를 작동시키는게 가능하게 됩니다.
이 과정에서 지역분산도 고려해볼 수 있는데, 만약 글로벌 서비스를 한다면 지역(Region) 별로 다른 Replication을 구성할 수도 있습니다. 이 과정에서 레이턴시가 중요한 서비스들이 있는데 이 경우 데이터베이스는 공유하고 지역별로 서버를 별도로 둔 뒤 서버 메모리 캐시 같은 것을 사용합니다. replication을 사용하면 이런 복잡한 작업을 간단히 해결할 수 있습니다.
2. 동작방식
MySQL의 Replication은 기본적으로 비동기 복제 방식을 사용하고 있습니다. 마스터노드에서 변경되는 데이터에 대한 이력을 Binary Log에 기록하면 Replication Master Thread가 비동기적으로 이를 읽어 Replication 쪽으로 전송하는 방식입니다. 일반적으로 SELECT 명령문은 데이터베이스 구조나 내용을 수정하지 않기 때문에 Binary Log에 기록되지 않습니다.
클라이언트가 커밋을 수행하면 Connection Thread는 스토리지 엔진에 해당 트랜잭션에 대한 커밋 준비를 합니다. 커밋을 수행하기 전 먼저 Binary Log에 변경사항을 기록하고 이후 스토리지 엔진에 커밋을 수행합니다. Replication Master Thread는 비동기적으로 Binary Log를 읽어 Replication으로 데이터를 전송합니다. Replication의 I/O Thread는 마스터로부터 수신한 변경된 데이터를 Relay Log에 기록하고, Replication의 SQL Thread는 Relay Log에 기록된 변경 데이터를 읽어 스토리지 엔진에 적용합니다.
즉, 아래와 같은 과정을 거쳐 마스터의 데이터가 Replication으로 전송되는 것입니다. 이 과정에서 알아야하는 I/O Thread, SQL THread 등의 개념이 등장하는데 이에 대해 하나씩 살펴보겠습니다.
- 커밋된 시점에 마스터 서버의 Binary log에 변경사항을 기록
- Master Thread는 비동기적 으로 Binary log를 읽어 Replication 서버로 전송
- Replication 의 I/O Thread는 마스터로 부터 받은 변경 데이터들을 Relay log에 기록
- Replication의 SQL Thread 는 Replay log의 기록을 읽어 자신의 스토리지 엔진에 적용
2-1. Master Thread
백그라운드에서 다양한 작업을 수행하는 InnoDB 스레드 입니다. Binary Log 를 읽어Replication으로 전송하는역할을 수행하며 Binlog Sender 또는 Binlog Dump 라고도 불립니다. Replication Thread와 Master Thread는 클라이언트-서버 구조를 지니는데, 하나의 마스터에는 동시에 여러개의 Replication Thread가 접속할 수 있습니다. 이때 Replication Thread 당 하나의 Master Thread가 대응되어 생성되며, 따라서 Replication Thread가 Master Thread 쪽으로 접속을 요청하기 위해서는 Master 에는 Replication Thread가 로그인할 수 있는 계정과 권한이 필요합니다.
데이터를 복제하기 위해서는 마스터가 Replication의 접속을 알아야 합니다. 하지만 마스터 입장에서 Replication의 접속이 일반 클라이언트의 접속과 구분되지 않기 때문에 해당 접속이 Replicatio으로부터의 접속인지 일반 애플리케이션의 접속인지 구분할 수 있는 방법이 있어야 합니다. 이를 위해 Replication Thread는 마스터에 접속 후 Binary Log의 송신을 요청하는 명령어(Protocol)를 전송하는데 이를 com_binlog_dump 와 com_binlog_dump_gtid 라고 합니다. Replication은 해당 프로토콜을 통해 통신한 후 com_query라는 프로토콜로 제 데이터의 송신을 요청하게 됩니다.
| 변수 | 설명 |
|---|---|
| com_binlog_dump | 파일명, 포지션으로 Replication이 마스터에 바이너리 로그의 송신을 의뢰하는 명령어 |
| com_binlog_dump_gtid | GTID에 의해 Binary Log의 포지션 결정 |
2-2. Replication I/O thread
마스터로부터 연속적으로 수신한 데이터를 Relay Log 로그 파일에 순차적으로 기록합니다. Relay Log 파일의 형식은 마스터의 Binary Log Format과 일치하며 이는 Replication을 시작하면 자동으로 생성됩니다. Relay Log 파일의 이름은 기본적으로 ‘호스트명-relay-bin’ 이며, 이는 호스트 이름이 변경될 경우 오류가 발생할 수 있으므로 relay_log 옵션을 이용하여 사용자가 의도한대로 정하는 편이 좋습니다.
1
2
# Relay Log의 내용을 확인하기 위해서는 아래 명령어를 사용한다.
mysql> SHOW RELAYLOG EVENTS
2-3. Replication SQL thread
Relay Log에 기록된 변경된 데이터 내용을 읽어 스토리지 엔진을 통해 Replication에 기록하는 쓰레드. Relay Log를 기록하는 I/O Thread 보다는 실제 데이터베이스의 내용을 변경하는 SQL Thread가 처리량과 연산이 많으며, 따라서 SQL Thread가 Replication 처리의 병목 지점이 될 수도 있습니다. 이의 해결하기 위해 MySQL 5.7 이후 버전에서는 MTS(Multi Thread Slave)가 등장하며 Replication에서의 SQL 쓰레드가 병렬로 데이터베이스 갱신을 수행할 수 있도록 개선된 기능입니다.
2-4. Relay log
I/O thread를 통해서 받은 이벤트 로그입니다. 이는 SQL thread가 이벤트를 읽고 나면 제거하기 때문에 일정 이상의 크기를 넘지 않습니다. 하지만 SQL thread가 동작하지 않으면 relay log 파일은 계속해서 크기가 커지게 됩니다. 이 경우 I/O thread는 자동으로 새로운 relay log 파일을 만들어 파일이 커지는 것을 방지합니다.
3. 정리
MySQL은 binary log를 기반으로 Replication의 데이터를 동기화합니다. 이때 아래와 같은 과정을 거치게 되며 동기화 과정에서 일부 지연이 발생할 수 있습니다.
- 커밋된 시점에 마스터 서버의 Binary log에 변경사항을 기록
- Master Thread는 비동기적 으로 Binary log를 읽어 Replication 서버로 전송
- Replication 의 I/O Thread는 마스터로 부터 받은 변경 데이터들을 Relay log에 기록
- Replication의 SQL Thread 는 Replay log의 기록을 읽어 자신의 스토리지 엔진에 적용