Database/RDBMS

MySQL Master-Slave Replication with Docker

귀찮은 개발자 2024. 2. 11. 13:00

Master-Slave Replication 이란 

MySQL Master-Slave Replication 은 데이터베이스의 한 인스턴스에서 다른 인스턴스로 데이터베이스를 복제하는 하나의 방식이다. 

Master-Slave Replication 을 통해 3가지의 이점을 얻을 수 있다.

  1. 데이터의 일관성을 유지
  2. 데이터 백업
  3. 시스템의 부하 분산

Amazon RDS, Google Cloud SQL, Azure Database for MySQL 등에서도 이러한 기능을 제공해주고 있다. 

Docker & Docker Compose 이란 

Docker와 Docker Compose는 이러한 Replication 를 설정하고 관리하는 데 사용할 수 있는 오케스트레이션 도구이다. 

MySQL Master-Slave Replication with Docker

이러한 조합으로 단일 마스터 서버로 사용되던 것을 간단하게 Slave 서버를 만들 수 있으며 master/slave 별로

.env, my.conf 필요하다. 

version: "3"

services:
  mysql-master:
    image: mysql:latest
    container_name: mysql-master
    restart: always
    env_file: ./master/.env.master
    cap_add:
      - all
    volumes:
      - ./master/data:/var/lib/mysql
      - ./master/my.cnf:/etc/my.cnf
    environment:
      - MYSQL_USER:${MYSQL_USER}
      - MYSQL_PASSWORD:${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD:${MYSQL_PASSWORD}

  mysql-slave:
    image: mysql:latest
    container_name: mysql-slave
    restart: always
    env_file: ./slave/.env.slave
    cap_add:
      - all
    volumes:
      - ./slave/data:/var/lib/mysql
      - ./slave/my.cnf:/etc/my.cnf
    environment:
      - MYSQL_USER:${MYSQL_USER}
      - MYSQL_PASSWORD:${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD:${MYSQL_ROOT_PASSWORD}

필요한 폴더 및 env 

mkdir master && mkdir slave
touch master/.env.master && touch slave/.env.slave

cat <<EOF >> ~/master/.env.master
MYSQL_USER=admin
MYSQL_PASSWORD=password
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=password
EOF

cat <<EOF >> ~/master/.env.slave
MYSQL_USER=admin
MYSQL_PASSWORD=password
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=password
EOF

my.conf 파일은 길어서 접었다. 

더보기

maser/my.conf

[mysqladmin]
user=admin

[mysqld]
skip_name_resolve
explicit_defaults_for_timestamp
basedir=/opt/bitnami/mysql
port=3306
tmpdir=/opt/bitnami/mysql/tmp
socket=/opt/bitnami/mysql/tmp/mysql.sock
pid_file=/opt/bitnami/mysql/tmp/mysqld.pid
max_allowed_packet=16M
bind_address=0.0.0.0
log_error=/opt/bitnami/mysql/logs/mysqld.log
character_set_server=utf8
collation_server=utf8_general_ci
plugin_dir=/opt/bitnami/mysql/lib/plugin
server-id=1
binlog_format=ROW
log-bin

[client]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
default_character_set=UTF8
plugin_dir=/opt/bitnami/mysql/lib/plugin

[manager]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
pid_file=/opt/bitnami/mysql/tmp/mysqld.pid
!include /opt/bitnami/mysql/conf/bitnami/my_custom.cnf

 

slave/my.conf

[mysqladmin]
user=admin

[mysqld]
skip_name_resolve
explicit_defaults_for_timestamp
basedir=/opt/bitnami/mysql
port=3306
tmpdir=/opt/bitnami/mysql/tmp
socket=/opt/bitnami/mysql/tmp/mysql.sock
pid_file=/opt/bitnami/mysql/tmp/mysqld.pid
max_allowed_packet=16M
bind_address=0.0.0.0
log_error=/opt/bitnami/mysql/logs/mysqld.log
character_set_server=utf8
collation_server=utf8_general_ci
plugin_dir=/opt/bitnami/mysql/lib/plugin
server-id=2
binlog_format=ROW
log-bin

[client]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
default_character_set=UTF8
plugin_dir=/opt/bitnami/mysql/lib/plugin

[manager]
port=3306
socket=/opt/bitnami/mysql/tmp/mysql.sock
pid_file=/opt/bitnami/mysql/tmp/mysqld.pid
!include /opt/bitnami/mysql/conf/bitnami/my_custom.cnf

이제 docker-compose 을 실행할 준비를 완료 했으면 MySQL 에 접속하여 계정 생성 및 리플리케이션 설정 작업을 해야한다.

$ docker exec -it mysql-master mysql -u root -p

mysql> CREATE USER 'replication'@'%' IDENTIFIED WITH mysql_native_password BY 'password';

mysql> GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';

mysql> GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';

mysql> SHOW MASTER STATUS\G
```
File : ~~.bin.0003 -- slave 에서 replication 등록할 때 필요하다. 
Postion : 300 -- MASTER_LOG_POS 이다. 
...

```

$ docker exec -it mysql-slave mysql -u root -p

mysql> CHANGE MASTER TO
MASTER_HOST='mysql-master', -- docker host 
MASTER_USER='replication',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='~~.bin.0003',
MASTER_LOG_POS=300; -- 

mysql> START SLAVE;

mysql> SHOW SLAVE STATUS\G
...
     Slave_IO_Running: Yes 
     Slave_SQL_Running: Yes
...​

회고

여러 사이드프로젝트에서 사용할 MySQL 데이터베이스를 적은 리소스로 좋은 효율을 내기 위해 Master-Slave Replication 작업을 하게 되었다. 

이러한 작업을 수동으로 해야한다는 것이 아쉬웠지만 쉘스크립트를 이용하면 자동화 할 수 있겠다라는 생각이 든다. 

하지만 프러덕션 레벨에서는 자동화하여 나도 모르는 Master-Slave 생성하기 보단 보수적인 관점으로 최대한 수동으로 작업을 진행해야 할 것 같다. 혹은 더 많은 비용을 지불해서라도 Amazon RDS, Google Cloud SQL, Azure Database for MySQL 을 이용하는 것이 좋겠다. 인스턴스 비용이 2배로 나가겠지만 관리 포인트가 줄어든다는 점에서는 좋은 방향인 것 같다. 

 

하지만 이러한 방법으로 Master-Slave 을 관리할 경우의 이점도 좋다고 느낀다. 

  1. 인스턴스 확장
  2. 업데이트 및 롤백 
  3. 격리 
  4. 단일 호스트에 설치가 가능하다는 점 (하지만 장애 대응을 위해서라면 다른 리전에 하는게 맞다.)
Host 1 — Host 2
master A 3306 — slave A 3306
master A 3307 — slave B 3307
master A 3308 — slave B 3308