Master/Slave 구조를 사용하는 이유
서버에 트래픽이 몰려들 때 해결하는 방법으로,
컴퓨터 성능을 1) Scale-up 하거나, 컴퓨터를 여러대 두는 2) Scale-out이 있다.
DB로 다수의 트랜잭션이 몰리면 race condition이 발생할 수 있다.
Replication(복제)으로 Master/Slave 구조를 형성하면 DB에 가해지는 부하를 분산하여 이러한 race condition을 미연에 방지할 수 있다. 일반적으로 Master에서 write(쓰기)를 하도록 하고, Slave에서는 read(읽기)를 하도록 하여, 부하를 분산한다.
MySQL에서 Master/Slave가 동작하는 방식은 아래와 같다.
[1] Insert/Update/Delete 트랜잭션이 들어오면 Master에서 이를 처리하고 Binary Log에 변경사항을 기록한다.
[2] Master Thread가 비동기로 Binary Log를 읽어 Slave 서버로 전송한다.
[3] Slave의 I/O Thread는 [2]에서 전달한 Binary Log를 Relay Log에 저장한다.
[4] Slave의 SQL Thread는 [3]에서 저장한 Relay Log를 읽어 Storage engine에 최종 적용한다.
Binary Log는 my.cnf에서는 binlog라는 명칭으로 사용되는데,
MySQL에서 발생하는 모든 변경사항을 담고 있는 로그 파일을 말한다.
MySQL의 디폴트 설정값에서는 이 Binary Log가 비활성화 되어 있기 때문에 my.cnf에 binlog를 활성화해주어야한다.
my.cnf에서 binlog 설정과 관련된 내용은 아래와 같다.
# Master에서 binlog 설정을 꼭 해주어야 binlog 내용을 replica에 전달할 수 있다.
[mysqld]
log_bin=mysql-bin #binlog의 파일명을 mysql-bin으로 시작하게 설정
binlog_format=ROW #binlog의 포맷을 row로 설정 (자세한 세팅은 앞선 블로그 내용 참고)
log_slave_updates=ON #slave업데이트 여부
expire_logs_days=90 #로그 저장 시간 (지정하지 않으면 로그가 계속 쌓인다)
Docker를 통해 Master/Slave 서버 구축하기
[1] 호스트 OS에서 Master와 Slave my.cnf 파일 설정하기
db/db001, db/db002, db/db003 경로를 각각 만든 후에, 각 경로에 data, log, conf 디렉토리를 만들고, 권한을 777 준뒤,
conf 디렉토리에 my.cnf 파일을 각각 만들어 주었다.
Master인 db001의 my.cnf 파일은 아래와 같다.
[mysqld]
server-id=100 <-- server-id는 master, slave가 달라야한다.
report_host=db001
basedir=/var/lib/mysql
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log_bin=mysql-bin <-- master에 log_bin 설정은 필수!
binlog_format=ROW
log-error=/var/log/mysql/mysql.log
gtid_mode=ON
enforce-gtid-consistency=true
symbolic-links=0
pid-file=/var/run/mysqld/mysqld.pid
expire_logs_days=90 <-- log는 최대 90일만
[mysqld_safe]
socket=/var/lib/mysql/mysql.sock
pid-file=/var/run/mysqld/mysqld.pid
nice=0
Slave의 my.cnf 파일은 아래와 같다.
[mysqld]
server-id=300 <-- slave id는 master와 달라야한다.
report_host=db003
basedir=/var/lib/mysql
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log_bin=mysql-bin
binlog_format=ROW
log-error=/var/log/mysql/mysql.log
gtid_mode=ON
enforce-gtid-consistency=true
log_slave_updates=ON <-- relay log 정보를 slave bin log에도 저장
symbolic-links=0
pid-file=/var/run/mysqld/mysqld.pid
expire_logs_days=90
[mysqld_safe]
socket=/var/lib/mysql/mysql.sock
pid-file=/var/run/mysqld/mysqld.pid
nice=0
[2] Docker를 통해 Master, Slave MySQL 서버를 각각 생성하기 ([1]의 my.cnf 파일 경로 마운트)
Master는 미리 만들어둬서, Slave를 두개 더 만들어줬다.
[root@dev opc]# docker run -it --name db002 -p 3307:3306 -h db002 -v /home/opc/db/db002/dat a:/var/lib/mysql -v /home/opc/db/db002/log:/var/log/mysql -v /home/opc/db/db002/conf:/etc/percona-server.conf.d -e MYSQL_ROOT_PASSWORD="root" -d percona:5.7.30
[root@dev opc]# docker run -it --name db003 -p 3308:3306 -h db003 -v /home/opc/db/db003/dat a:/var/lib/mysql -v /home/opc/db/db003/log:/var/log/mysql -v /home/opc/db/db003/conf:/etc/percona-server.conf.d -e MYSQL_ROOT_PASSWORD="root" -d percona:5.7.30
[3] Master 컨테이너에서 Replication User생성하기
Docker를 통해 Master 컨테이너의 MySQL에 접속한 뒤,
[root@dev opc]# docker exec -it -uroot db001 /bin/bash
[root@db001 /]# mysql -uroot -p
Slave에서 Master MySQL에 접속할 수 있도록 User를 하나 생성한 뒤, Replication 권한을 줬다.
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'repl';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
Query OK, 0 rows affected (0.01 sec)
그리고 ifconfig를 통해 Master의 ip주소를 확인했다.
ifconfig
[4] Slave 컨테이너에서 Master 지정하기
Slave 컨테이너의 MySQL에 접속하는 방법은 동일하다.(위 참조)
[3]에서 확인한 Master MySQL의 ip/user 정보를 통해 master를 지정해준다.
mysql> reset master;
Query OK, 0 rows affected (0.04 sec)
mysql> CHANGE MASTER TO MASTER_HOST='{{Master의 ip주소}}', \
-> MASTER_USER='repl', MASTER_PASSWORD='repl', \
-> MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
그리고 slave를 시작한 후, 상태를 확인하면 Master가 제대로 지정된 걸 확인할 수 있었다.
start slave;
show slave status\G;
# 결과에 아래 내용이 있다면 slave 적용 완료됨
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
[5] 테스트해보기
Master, Slave에 동일명의 database와 테이블을 생성한 뒤, Master에서 insert 작업 후, Slave에서 확인한다.
[참고]
- 서버 분산 처리 환경에서 MySQL을 MasterSlave로 이중화하기
- https://jupiny.com/2017/11/07/docker-mysql-replicaiton/
'Infra > Docker' 카테고리의 다른 글
[Docker] Proxy Layer 구성하기 (2) | 2024.01.08 |
---|---|
[Docker] Orchestra를 통해 High Availability(HA) 구축하기 (1) | 2024.01.08 |
[Docker] 브리지를 통해 컨테이너 통신 (1) | 2024.01.08 |
[Docker] 호스트OS에 log, config 연결 (+my.cnf) (1) | 2023.12.29 |
[Docker] Docker란? Docker로 Mysql 설치해보기 (1) | 2023.12.28 |