Docker를 이용하여 MySQL Replication 구성해보기

Database Replication?

Database Replication은 한 DB 서버의 데이터를 다른 DB 서버들에 복제하는 기술이다.

여기서 복제의 대상이 되는 DB 서버를 보통 master 서버라 하고, 데이터가 복제된 DB 서버를 slave 서버라 부른다. master 서버는 쓰기 연산을 담당하고, slave 서버는 읽기 연산을 담당한다. 따라서 slave 서버를 여러 대 돌린다면 읽기 연산을 분산시켜 서버의 부하를 상당히 줄일 수 있다(일반적으로 DB의 읽기 연산이 상당한 비중을 차지하므로).

이 때 Docker를 이용하면 DB 서버를 가상화할 수 있기 때문에, 실제 물리 서버를 여러 대 돌릴 필요없이 내 로컬 PC 한 대에서 이를 간단히 구성하여 테스트해볼 수 있다.

Docker로 구동하였기 때문에 master, slave 컨테이너라 부르는 것이 정확한 표현일테지만, 일반적인 Replication의 구성을 생각하여 master, slave 서버라 혼용하여 표현하였다.

MySQL master, slave 컨테이너 실행하기

우선 MySQL를 master, slave 서버로 실행하기 위한 설정이 필요하다. 아래와 같이 master, slave 컨테이너가 사용할 각각의 .cnf 파일을 작성해주어야한다.
(반드시 확장자가 .cnf 로 끝나야한다. 실수로 .conf 로 했더니 MySQL에서 설정을 불러오지 못했다;;;)

# /Docker/mysql/master/config_file.cnf

[mysqld]
log-bin=mysql-bin  
server-id=1  
# /Docker/mysql/slave/config_file.cnf

[mysqld]
server-id=2  

log-bin 은 업데이트되는 모든 query들을 바이너리 파일에 로그로 남기겠다는 의미이다.
기본적으로 바이너리 파일은 MySQL의 datadir인 /var/lib/mysql/호스트명-bin.000001, 호스트명-bin.000002 형태로 생성된다.
위에서처럼 log-bin=... 식으로 뒤에 덧붙이면 바이너리 파일의 경로와 파일명의 접두어를 입맛에 맞게 정할 수 있다. log-bin=mysql 이라 설정하였으므로 mysql-bin.000001, mysql-bin.000002 형태의 바이너리 파일이 생성될 것이다.

여기서 server-id 는 Replication Group에서 식별하기 위한 서버의 고유 ID 값이므로 master, client 각각 다르게 해주어야 한다.

이제 .cnf 파일의 설정을 적용하여 두 컨테이너를 실행해주면 된다.

$ docker run --name mysql-master -v /Docker/mysql/master:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=masterpw -d mysql
$ docker run --name mysql-slave -v /Docker/mysql/slave:/etc/mysql/conf.d —link mysql-master -e MYSQL_ROOT_PASSWORD=slavepw -d mysql

mysql-slave 컨테이너에서 mysql-master 컨테이너 이름을 Host 주소로 사용하기 위해 --link mysql-master 옵션을 추가한 점을 주목하자.

생성한 master 컨테이너의 mysql에 접속해보자.
(mysql 비밀번호는 master 컨테이너를 실행할 때 설정한 'MYSQL_ROOT_PASSWORD' 입력)

$ docker exec -it mysql-master /bin/bash
$ 
mysql -u root -p  

아래의 명령어를 쳤을 때 이미지와 같이 나온다면 앞에 작성한 .cnf 파일의 설정이 정상적으로 적용된 것이다.

mysql> SHOW MASTER STATUS\G  

위의 명령어는 추후 slave 서버에서 master 서버와 연동하기 직전에 다시 한번 입력해야하므로 자세한 설명은 그때 다루도록 할 것이다.

master 서버에서 User 생성하기

이제 slave 서버에서 접근이 가능하도록 master 서버에 REPLICATION SLAVE 권한을 가진 User 계정을 하나 생성해주어야 한다.

$ docker exec -it mysql-master /bin/bash
mysql> CREATE USER 'repluser'@'%' IDENTIFIED BY 'replpw';  
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'%';  

user 테이블을 확인하여 User가 생성되었는지 확인한다.

mysql> USE mysql;  
mysql> 
SELECT user, host FROM user;  

User가 성공적으로 생성되었다면, Replication 테스트를 위한 DB와 테이블을 생성한다.

mysql> CREATE DATABASE repldb;  
mysql> USE repldb;  
mysql> CREATE TABLE repltable ( no INT(8), PRIMARY KEY (no) );  
mysql> DESC repltable;  

master 서버의 DB dump하기

우선, master 서버의 현재 DB 상태를 slave에 그대로 반영하기 위해 dump한다.

$ docker exec -it mysql-master /bin/bash
$ mysqldump -u root -p repldb > dump.sql
$ exit

dump한 파일을 내 로컬 PC(호스트 PC)로 복사해온다.

$ docker cp mysql-master:dump.sql .
$ cat dump.sql

slave 서버에서 dump한 데이터 불러오기

로컬 PC의 dump한 파일을 slave 서버로 복사한 후, DB를 복구한다.
(mysql 비밀번호는 slave 컨테이너를 실행할 때 설정한 'MYSQL_ROOT_PASSWORD' 입력)

$ docker cp dump.sql mysql-slave:.
$ docker exec -it mysql-slave /bin/bash
$ mysql -u root -p
mysql> CREATE DATABASE repldb;  
mysql> exit  
$ mysql -u root -p repldb < dump.sql

다시 mysql에 접속하였을 때 repldb DB에 repltable 테이블이 생성되어 있다면 정상적으로 복구된 것이다.

$ mysql -u root -p
mysql> USE repldb;  
mysql> SHOW TABLES;  

slave 서버에서 master 서버 연동하기

이제 마지막으로 slave 서버에서 master 서버와 연동하는 작업만 해주면 된다.

그 전에 master 서버의 mysql에 한번 더 접속하여 바이너리 로그 파일의 현재 상태를 읽어야 한다. 이 로그 파일을 통해 master, slave의 DB가 동기화되므로 반드시 동일한 로그의 위치를 서로 참조하고 있어야 한다.

$ docker exec -it mysql-master /bin/bash
$ 
mysql -u root -p  
mysql> SHOW MASTER STATUS\G  

출력된 결과에서 File, Position 필드의 값을 기억하도록 한다.
File 은 현재 바이너리 로그 파일명이고, Position 은 현재 로그의 위치를 나타낸다. 앞서 DB와 테이블을 생성한 query가 추가됐으므로 이전에 mysql> SHOW MASTER STATUS\G 를 실행했을 때보다 Position 값이 증가했음을 볼 수 있다.

이제 slave 서버의 mysql에 접속하여 master 서버와의 연결에 필요한 변수들을 적절히 설정해주어야 한다.

$ docker exec -it mysql-slave /bin/bash
$ 
mysql -u root -p  
mysql> CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='repluser', MASTER_PASSWORD='replpw', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=965;  
mysql> START SLAVE;  
  • MASTER_HOST : master 서버의 호스트명
  • MASTER_USER : master 서버의 mysql에서 REPLICATION SLAVE 권한을 가진 User 계정의 이름
  • MASTER_PASSWORD : master 서버의 mysql에서 REPLICATION SLAVE 권한을 가진 User 계정의 비밀번호
  • MASTER_LOG_FILE : master 서버의 바이너리 로그 파일명
  • MASTER_LOG_POS : master 서버의 현재 로그의 위치

아래의 명령어를 실행하여 결과를 확인해보자.

mysql> SHOW SLAVE STATUS\G  

Last_Error, Last_IO_Error 필드에 아무 값이 없다면 성공적으로 Replication이 구성된 것이다.

Replication 테스트하기

테스트를 위해 master 서버의 mysql에 접속하여 테이블에 레코드를 추가해보자.

$ docker exec -it mysql-master /bin/bash
$ 
mysql -u root -p  
mysql> USE repldb;  
mysql> INSERT INTO repltable VALUES (1);  
mysql> SELECT * FROM repltable;  

slave 서버의 테이블에도 똑같이 반영되었음을 확인해 볼 수 있다.

$ docker exec -it mysql-slave /bin/bash
$ 
mysql -u root -p  
mysql> USE repldb;  
mysql> SELECT * FROM repltable;  

참고