복제(Replication)
한 서버에서 다른 서버로 데이터를 동기화하는 것을 의미한다.
원본 데이터를 가지는 서버를 Primary 또는 Source 라고 부르고, 복제된 데이터를 가지는 서버를 Secondary 또는 Replica 라고 부른다.
복제를 하는 이유
1. 스케일 아웃
사용자의 트래픽이 증가하는 경우, 데이터베이스에 가해지는 부하도 자연스럽게 증가한다.
이를 처리하기 위 해 복제를 통한 스케일 아웃을 적용하여 애플리케이션에서 사용하는 쿼리들을 각각의 데이터베이스로 분산 시킬 수 있다.
2. 데이터 백업
실제 운영되는 서비스가 사용하고 있는 DB에서 백업을 진행하는 경우, 서비스에 영향을 미칠 수 있다.
따라서 실제 서비스에 영향이 가지 않도록 복제를 통해 Replica 서버를 구축하여, Replica 서버에서 복제를 진행하는 방법으로 영향을 최소화 할 수 있다.
3. 데이터 분석
백업과 마찬가지로 복잡하고 무거운 분석용 쿼리의 서비스에 영향을 미칠 수 있다.
마찬가지로 복제를 사용해 분석용 쿼리를 사용할 수 있는 환경을 만들 수 있다.
4. 데이터의 지리적 분산
빠른 응답을 위해 애플리케이션 서버에 가깝게 서버를 구성하거나, 고가용성(High Availability)을 위해서도 사용된다.
바이너리 로그 파일 위치 기반 복제
MySQL 서버에서 발생하는 변경사항에 대한 로그 파일을 바이너리 로그라고 한다.
바이너리 로그를 통해 데이터 변경, 테이블 구조 변경, 계정이나 권한 변경에 대한 정보가 저장된다.
MySQL의 복제는 바이너리 로그 기반으로 구현되어 있다. 이를 Replica 서버로 전달하고 바이너리 로그 기반으로 데이터를 변경 사항을 반영한다.
Binary Log Dump Thread: 바이너리 로그의 내용을 Replica 서버로 전달
Replication I/O Thread: Binary 로그 이벤트를 가져와 로컬 서버의 파일(Relay Log)로 저장
Replication SQL Thread: 릴레이 로그 파일의 이벤트를 읽고 실행
바이너리 로그 방식의 문제점
바이너리 로그 방식은 서버에 장애가 발생했을 때 복제 토폴로지 변경이 까다롭다.
토폴로지란 네트워크의 요소들을 물리적으로 연결해 놓은 것, 또는 그 연결 방식을 말한다.
위와 같이 Source 서버, Replica 2대가 존재하고, C 서버에 복제 지연이 되었을 때 문제가 발생한다.
A 서버에서 장애가 발생한다면 B 서버를 Source 서버로 승격하고, C에게 조회 쿼리를 분산시킨다.
하지만 여기서 C 서버에는 A 서버와 동기화가 안되었으니 조회 시 문제가 발생한다.
뒤늦게 B 서버와 동기화를 하려고 해도, 어떤 바이너리 로그, 어떤 위치와 동기화해야하는지 알기 어렵다.
글로벌 트랜잭션 아이디(GTID) 기반 복제
GTID 방식을 사용하여 참여한 모든 데이터베이스가 발생한 이벤트에 고유한 식별값을 부여한다면, 동기화에 대한 문제를 간단하게 해결할 수 있다.
위의 예시와 같이 복제 지연과 함께 장애가 발생한다해도 특정 GTID 부터 복제를 재개하면 된다.
복제 토폴로지에 참여한 모든 서버에서 고유하도록 각 이벤트에 부여된 식별값
[source_id]:[transaction_id]로 구성되며, source_id는 서버를 식별하기 위한 값이고 transaction_id는 커밋된 트랜잭션을 식별하기 위한 값으로 1씩 증가하는 형태로 발급된다.
복제 토폴로지
싱글 레플리카 복제 구성
가장 간단한 구성으로 제일 많이 사용하는 형태다.
replica 서버를 읽기 전용, 예비 서버, 백업 용도로 많이 사용한다.
멀티 레플리카 복제 구성
2개의 replica 서버를 사용하는 형태다.
하나의 replica는 예비 용도로 남겨두는 형태다.
추후에 트래픽이 증가하는 경우 예비 용도의 replica를 사용함으로 읽기 요청의 부하 분산을 할 수 있다.
체인 복제 구성
replica 서버가 많은 경우 바이너리 로그를 전달하는 작업 자체가 부하가 될 수 있다.
따라서 1:M:M 구조로 체인 복제 구성을 고려할 수 있다.
듀얼 소스 복제 구성
2개의 MySQL 서버 모두 읽기와 쓰기가 가능하도록 하는 구성이다.
각 서버에서 변경된 데이터는 다른 서버에 반영된다.
목적에 따라 ACTIVE-ACTIVE 형태 또는 ACTIVE-PASSIVE 형태로 사용할 수 있다.
ACTIVE-PASSIVE 형태인 경우 싱글 레플리카 복제 구성과 동일해보이지만, ACTIVE 서버에서 문제가 발생하면 설정의 변경없이 PASSIVE 서버로 쓰기 작업을 전환할 수 있다는 것이 장점이다.
ACTIVE-ACTIVE: 2개의 서버 모두 쓰기 작업을 수행하는 형태
ACTIVE-PASSIVE: 하나의 서버에서만 쓰기 작업을 수행하는 형태
멀티 소스 복제 구성
여러개의 source 서버와 하나의 replica 서버를 사용하는 구성이다.
이는 source 서버의 데이터를 한 곳에 백업하는 용도로 사용, 여러 서버에 존재하는 데이터를 통합, 샤딩되어있는 테이블 데이터를 통합할 때 사용한다.
바이너리 로그 방식 Replication 구성하기
mysql 2대를 이용하여 replication을 구성하고, spring boot application으로 source, replica 데이터베이스에 접근해보는 예제이다.
https://github.com/bbiac/db-replication
MySQL 환경 구성
MySQL 버전은 8.1 을 사용했다.
13306, 13307 포트를 사용해서 MySQL 서버 2대를 띄웠다.
또한 사실 IP 대역으로 통신할 수 있도록 커스텀 네트워크를 추가했다.
version: '3.8'
services:
source:
platform: linux/x86_64
image: mysql:latest
restart: always
container_name: mysql-source
environment:
TZ: 'Asia/Seoul'
MYSQL_DATABASE: 'db'
MYSQL_USER: 'user'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- "13306:3306"
volumes:
- db-source:/var/lib/mysql
- db-source:/var/lib/mysql-files
- ./docker/source.cnf:/etc/mysql/my.cnf
networks:
- mysql_network
replica:
platform: linux/x86_64
image: mysql:latest
restart: always
container_name: mysql-replica
environment:
TZ: 'Asia/Seoul'
MYSQL_DATABASE: 'db'
MYSQL_USER: 'user'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- "13307:3306"
volumes:
- db-replica:/var/lib/mysql
- db-replica:/var/lib/mysql-files
- ./docker/replica.cnf:/etc/mysql/my.cnf
networks:
- mysql_network
volumes:
db-source:
db-replica:
networks:
mysql_network:
driver: bridge
또한 source, replica 각각 다음과 같이 db 설정을 했다.
설정 | 설명 |
---|---|
server_id | 각각의 mysql 마다 고유한 값을 가져야 한다. |
log_bin | 바이너리 로그 파일 경로 설정으로 절대경로를 사용하지 않는다면 /var/lib/mysql 아래 해당 log_bin에 설정된 값으로 로그가 생성된다. |
sync_binlog | N개의 트랜잭션 당 바이너리 로그를 디스크와 동기화 작업을 하도록 한다. 1은 기본값으로 안정적이지만, 가장 느리다. |
relay_log | 릴레이 로그 파일 경로 설정 |
relay_log_purge | 필요 없는 릴레이 로그 파일을 자동으로 삭제하는 옵션 |
read_only | 읽기 전용 설정 |
log_replica_updates | Replication SQL Thread로 인해 실행되는 정보를 바이너리 로그에 기록 추후에 소스 서버로 승격되는 경우를 고려하면 설정하는 것이 좋다. |
- Source
- Replica
[mysqld]
server_id=1
log_bin=mysql-bin
sync_binlog=1
[mysqld]
server_id=2
relay_log=mysql-relay-bin
relay_log_purge=ON
read_only
log_replica_updates
도커 실행
docker-compose up 명령어로 docker-compose 설정으로 docker를 띄운다.
-d 옵션을 붙이면 백그라운드 모드로 실행된다.
docker-compose up -d