[10분 테코톡] ✌️ 영이의 Replication을 들으며 정리한 글입니다..
Replication이란?
- 한 서버에서 다른 서버로 데이터를 동기화하는 것
- 원본 데이터를 가지는 서버를 Source 서버
- 복제된 데이터를 가지는 서버를 Replica 서버
Why?
- 부하를 줄이기 위해서 (Scale-out)
- 갑자기 늘어나는 트래픽을 대응하는데 유연한 구조
- 데이터 백업
- 레플리카를 안하더라도 백업을 해야함
- 백업 과정은 실제 실행중인 쿼리들에 영향을 줄 수 있음
- 레플리카 서버에서 데이터 백업을 실행하여 소스 서버에서 백업 시 발생하는 문제 해결
- 데이터 분석
- 분석용 쿼리는 대량의 데이터를 조회하고, 쿼리 자체가 무거운 경우가 많음
- 소스 서버에서 하게 되면 문제가 될 수 있으니, 레플리카 서버에서 분석용 쿼리만 전용으로 하는 것이 좋음
- 데이터의 지리적 분산
- 데이터베이스와 애플리케이션 서버가 멀리 떨어져있다면 응답을 늦게 받게됨
- 빠른 응답을 위해 애플리케이션 서버에 가깝게 서버를 구성하는 것이 좋음
- ex) 넷플릭스 디비가 미국에 있다면 한국 사용자는 속이 터지겠죠?
복제를 어떻게 하는가?
바이너리 로그 (binlog)
MySQL 서버에서 발생하는 모든 변경사항을 별도의 로그 파일에 순서대로 저장
- 데이터의 변경내역
- 데이터베이스나 테이블의 구조 변경
- 계정이나 권한의 변경 정보
MySQL에서 다음 명령어로 확인 가능하다.
show binary logs; // binlog 확인
show master status; // 파일명과 위치 정보 파악
소스 서버에서 생성된 binlog가 레플리카 서버로 전송되고, 레플리카 서버에서는 해당 내용을 로컬 디스크에 저장한 뒤 자신이 가진 데이터에 반영하므로써 동기화가 이루어진다.
이는 세개의 스레드에서 이루어진다.
- Binary Log Dump Thread
- 소스 서버에 존재
- binlog를 레플리카 서버로 전송하는 역할
- 레플리카 서버가 소스 서버에 연결되면 소스 서버에서 내부적으로 Binary Log Dump Thread를 생성
- Replication I/O Thread
- 레플리카 서버에 존재
- Binary Log Event를 가져와 로컬 서버의 파일(Relay Log)로 저장하는 역할
- 복제가 시작될 때 스레드가 생성되고 복제가 끝나면 스레드 종료
- Connection Metadata
- 소스 서버에 연결할 때 사용하는 정보를 가짐
- mysql.slave_master_info 테이블에 저장
- Replay Log
- 가져온 바이너리 로그 이벤트를 레플리카 서버에 파일로 저장한 것
- Replication SQL Thread
- 레플리카 서버에 존재
- 릴레이 로그 파일의 이벤트들을 읽고 실행
- Applier Metadata
- 릴레이 로그에 저장된 소스 서버의 이벤트들을 서버에 저장하는 컴포넌트
- 소스서버에 연결할 때 사용하는 정보를 가짐
- mysql.slave_relay_log_info 테이블에 저장
어떻게 변경 내용을 식별하는가?
기본적으로 레플리케이션을 사용하려면 소스 서버에 반드시 binlog가 활성화되어 있어야한다.
바이너리 로그 파일 위치 기반
레플리카 서버에서 소스 서버의 binlog 파일명과 파일 내에서 위치로 binlog 이벤트를 식별해서 복제한다.
이벤트가 최초로 발생한 MySQL 서버를 식별하기 위해 server_id를 사용한다.
기본값은 1인데 레플리케이션을 하게 된다면 레플리카 서버에 반드시 server_id를 각각 다르게 지정해주어야 한다.
글로벌 트랜잭션 ID 기반 (GTID)
GTID
복제에 참여한 서버들에서 고유하도록 각 이벤트에 부여된 식별 값을 의미한다.
MySQL 5.5 버전까지는 바이너리 로그 파일 위치 기반 방식으로만 레플리케이션이 가능했다.
하지만 이 방식은 식별 과정이 소스 서버에서만 유효하다.
동일한 이벤트가 레플리카 서버에서 동일한 위치와 동일한 파일명으로 저장된다는 보장이 없다.
어떤 경우에는 동일한 이벤트인데, 서로 다른 식별 값을 가지는 경우가 있을 것이다.
이 문제를 해결하기 위해 각 이벤트들이 복제에 참여한 모든 MySQL 서버들에서 동일한 고유 식별 값을 가지게 하는 방법이다.
바이너리 로그는 어떻게 생겼을까?
Statement 방식
- SQL 문을 바이너리 로그에 그대로 기록
- MySQL에 binlog가 처음 도입되었을 때부터 있던 방식
- 트랜잭션의 격리 수준이 반드시 REPEATABLE-READ 이상이어야 한다.
- 그 이하에서는 하나의 트랜잭션에서도 각 쿼리가 실행되는 시점마다 스냅샷이 달라질 수 있어 이로 인해 복제 시 서버와 레플리카 서버의 데이터가 일치하지 않을 수 있기 때문에
장점
- 손쉽게 SQL문들을 확인할 수 있다.
단점
- 비확정적(delete/update에 order by 없이 limit 사용 등 결과가 매번 달라질 수 있는 상황)으로 처리될 수 있는 쿼리가 실행된 경우 Statement 포맷에서는 복제 시 소스 서버와 레플리카 서버 간 데이터가 달라질 수 있다.
Row 방식
- 변경된 데이터 자체를 기록
- MySQL 5.7.7 버전 이후부터 바이너리 로그 기본 포맷
장점
- 어떤 형태의 쿼리든지 복제 시 소스 서버와 레플리카 서버의 데이터를 일관되게 한다.
단점
- 많은 데이터를 변경하면 모든 데이터가 전부 기록되어 바이너리 로그 파일이 단 시간에 매우 커진다.
- 어떤 쿼리가 실행되었는지는 확인하기 어렵다.
Mixed 방식
- 위 두 방식을 혼합
- 쿼리의 대부분은 Statement 방식으로 기록될 확률이 높은데, 실행된 쿼리가 Statement 포맷으로 기록되어 복제됐을 때 문제가 될 가능성 있는 안전하지 못한 쿼리라면 Row 방식으로 기록
다음과 같은 명령어로 변경이 가능하다.
set global binlog_format = 'STATEMENT';
복제 동기화 방식
소스 서버가 레플리카 서버에 이벤트들이 잘 보내졌는지 안보내졌는지 확인하냐 안하냐에 따라 복제 동기화 방식을 설정할 수 있다.
비동기 복제
소스 서버가 레플리카 서버에서 변경 이벤트가 정상적으로 전달 되었는지 확인하지 않는다.
소스 서버에 장애가 일어나면 소스 서버에서 최근까지 적용된 트랜잭션이 레플리카 서버로 전송되지 않을 수 있다.
반동기 복제
소스 서버는 레플리카 서버가 소스 서버로부터 전달받은 변경 이벤트를 릴레이 로그에 기록 후 응답을 보내면 그때 트랜잭션을 완전히 커밋한다.
하지만 전송이 보장된 것이지 적용이 보장된 것은 아니다.
또한 서버의 응답을 기다리기 때문에 비동기 방식보다 트랜잭션 처리가 길어질 수 있다.
소스 서버는 일정 시간동안 기다리다 응답이 없으면 비동기 방식으로 변경된다.
어떻게 구성할까?
싱글 레플리카 복제
하나의 소스서버에 하나의 레플리카 서버만을 둔다.
이 경우 소스 서버에 문제가 생겼을 때 예비 서버 및 데이터 백업 수행을 위한 용도로 많이 사용된다.
멀티 레플리카 복제
하나의 소스 서버에 2개 이상의 레플리카 서버를 연결한 복제 형태이다.
하나의 서버는 예비용으로 구성하고, 다른 서버는 읽기 전용으로 구성한다.
체인 복제
하나의 소스 서버에 연결된 레플리카 서버 수가 많다면 바이너리 로그를 읽고 전달하는 작업 자체가 부하가 될 수 있을 때 사용한다.
소스 서버가 해야하는 바이너리 로그 배포 역할을 새로운 서버로 넘긴다.
듀얼 소스 복제
두개의 서버가 서로 소스 서버이자 레플리카 서버로 구성되어 있다.
두 서버 모두 쓰기가 가능하며, 각 서버에서 변경한 데이터는 복제를 통해 다시 각 서버에 적용되므로 양쪽에서 쓰기가 발생하지만 두 서버는 서로 동일한 데이터를 갖게 된다.
목적에 따라 ACTIVE-PASSIVE 형태, ACTIVE-ACTIVE 형태로 사용할 수 있다.
싱글 레플리카와 비슷해보이지만 한 서버에 장애가 일어날 경우 전환을 바로 가져갈 수 있다.
멀티 소스 복제
하나의 레플리카 서버가 둘 이상의 소스 서버를 가진다.
여러 서버에 존재하는 다른 데이터를 하나의 서버로 통합하거나, 샤딩되어 있는 테이블 데이터를 하나이 테이블로 통합할 때 사용할 수 있다.