MySQL Replication with Docker
[#๐ฌBoard] Replication์ผ๋ก DB ๋ถํ ๋ถ์ฐํ๊ธฐ
Board ์๋ฒ๋ ๋๋ถ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์์ ๊ทธ๋ ๋ฏ์ด ์ฐ๊ธฐ ์ฐ์ฐ(์์์ ๋ฑ๋กํ๊ธฐ, ์ฃผ๋ฌธํ๊ธฐ ๋ฑ)์ ๋นํด ์ฝ๊ธฐ ์ฐ์ฐ(์์์ ๋ฆฌ์คํธ ์กฐํ, ์ฃผ๋ฌธ ๋ฆฌ์คํธ ์กฐํ ๋ฑ) ๋น์ค์ด ํจ์ฌ ํฝ๋๋ค. ๋ฐ๋ผ์ ํฅํ ๋ง์ TPS/QPS๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด Board DB ์๋ฒ์ ๋ค์คํ๊ฐ ํ์ํ์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ธํฐ๋ท์์๋ ์์๋ณด๋ค docker-compose๋ฅผ ์ด์ฉํ ๋จ๋ฐฉํฅ ๋ณต์ ์ ๋ํ ์์ ๊ฐ ๋ถ์กฑํ๊ณ , Github์ ์๋ ์์ค๋ค์ ์ ๊ฐ ์ํ๋ ๋ฐฉ์์ด ์๋๊ฑฐ๋ ๋ง์ดํธ ๊ณผ์ ์์์ ๋ฒ๊ทธ๊ฐ ์ข ์ข ๋ฐ์ํ์ต๋๋ค.
๊ทธ๋์ ์ด ๊ธ์์๋ ๊ธฐ๋ก ๊ฒธ ๊ณต์ ๋ชฉ์ ์ผ๋ก Board DB ์๋ฒ์ Replication์ ์ด๋ป๊ฒ ์ ์ฉ์์ผฐ๋์ง์ ๋ํด Docker๋ฅผ ์ค์ฌ์ผ๋ก ๋ค๋ฃน๋๋ค. Spring Boot ์๋ฒ์ ์ฝ๋๋ ์๋ตํฉ๋๋ค.
๐กdocker-compose.yml ๊ตฌ์ฑ
version: "3.9"
services:
mysql_master:
image: mysql:latest
container_name: mysql_master
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_PORT: 3306
MYSQL_USER: master
MYSQL_PASSWORD: password
MYSQL_DATABASE: board
ports:
- "3307:3306"
volumes:
- ./mysql/master/conf/mysql.conf.cnf:/etc/mysql/conf.d/mysql.conf.cnf
- ./mysql/master/data:/var/lib/mysql
- ./mysql/master/initdb.d:/docker-entrypoint-initdb.d
command: ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_general_ci"]
networks:
- mysql-server
mysql_slave:
image: mysql:latest
container_name: mysql_slave
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_PORT: 3306
MYSQL_USER: slave
MYSQL_PASSWORD: password
MYSQL_DATABASE: board
ports:
- "3308:3306"
depends_on:
- mysql_master
volumes:
- ./mysql/slave/conf/mysql.conf.cnf:/etc/mysql/conf.d/mysql.conf.cnf
- ./mysql/slave/data:/var/lib/mysql
- ./mysql/slave/initdb.d:/docker-entrypoint-initdb.d
command: ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_general_ci"]
networks:
- mysql-server
networks:
mysql-server:
mysql_master์ ์ธ๋ฐ์ด๋๋ฅผ 3307 ํฌํธ๋ก, mysql_slave์ ์ธ๋ฐ์ด๋๋ฅผ 3308 ํฌํธ๋ก ์ก์์ต๋๋ค. ๋ง์ฝ 3306 ํฌํธ๊ฐ ๋ ์์ง ์๋๋ค๊ณ ํ์ ํ๋ค๋ฉด master๋ฅผ 3306์ผ๋ก ์ก๋ ๊ฒ์ด ๊น๋ํด๋ณด์ด๋, ๊ฐ๋ฐ ๋จ๊ณ์์์ ๋ถํธ์ ๊ฐ์ํ์ง ์๊ธฐ ์ํด 3307๋ก ์ค์ ํ์ต๋๋ค.
๋ณผ๋ฅจ์ ๋ฐ๋ก ์ค์ ํ ๊ฐ์ด ์์ผ๋ฉด ๋ฌด์ํ์ฌ๋ ๋ฉ๋๋ค.
mysql-server ์ปจํ ์ด๋์ mysql-master ์ปจํ ์ด๋๋ฅผ ๊ฐ์ ๋คํธ์ํฌ(mysql-server)์ ๋ฌถ์์ต๋๋ค.
๐กbuild.sh ์ค์
#!/bin/bash
docker-compose down -v
rm -rf ./mysql/master/data/*
rm -rf ./mysql/slave/data/*
docker-compose build
docker-compose up -d
until docker exec mysql_master sh -c 'export MYSQL_PWD=root; mysql -u root -e ";"'
do
echo "Waiting for mysql_master database connection..."
sleep 4
done
priv_stmt='CREATE USER "slave"@"%" IDENTIFIED WITH mysql_native_password BY "password"; GRANT REPLICATION SLAVE ON *.* TO "slave"@"%"; FLUSH PRIVILEGES;'
docker exec mysql_master sh -c "export MYSQL_PWD=root; mysql -u root -e '$priv_stmt'"
until docker-compose exec mysql_slave sh -c 'export MYSQL_PWD=root; mysql -u root -e ";"'
do
echo "Waiting for mysql_slave database connection..."
sleep 4
done
MS_STATUS=`docker exec mysql_master sh -c 'export MYSQL_PWD=root; mysql -u root -e "SHOW MASTER STATUS"'`
CURRENT_LOG=`echo $MS_STATUS | awk '{print $6}'`
CURRENT_POS=`echo $MS_STATUS | awk '{print $7}'`
start_slave_stmt="SET GLOBAL server_id=2; CHANGE MASTER TO MASTER_HOST='mysql_master',MASTER_USER='slave',MASTER_PASSWORD='password',MASTER_LOG_FILE='$CURRENT_LOG',MASTER_LOG_POS=$CURRENT_POS; START SLAVE;"
start_slave_cmd='export MYSQL_PWD=root; mysql -u root -e "'
start_slave_cmd+="$start_slave_stmt"
start_slave_cmd+='"'
docker exec mysql_slave sh -c "$start_slave_cmd"
docker exec mysql_slave sh -c "export MYSQL_PWD=root; mysql -u root -e 'SHOW SLAVE STATUS \G'#!/bin/bash
docker-compose down -v
rm -rf ./mysql/master/data/*
rm -rf ./mysql/slave/data/*
docker-compose build
docker-compose up -d
until docker exec mysql_master sh -c 'export MYSQL_PWD=root; mysql -u root -e ";"'
do
echo "Waiting for mysql_master database connection..."
sleep 4
done
priv_stmt='CREATE USER "slave"@"%" IDENTIFIED WITH mysql_native_password BY "password"; GRANT REPLICATION SLAVE ON *.* TO "slave"@"%"; FLUSH PRIVILEGES;'
docker exec mysql_master sh -c "export MYSQL_PWD=root; mysql -u root -e '$priv_stmt'"
until docker-compose exec mysql_slave sh -c 'export MYSQL_PWD=root; mysql -u root -e ";"'
do
echo "Waiting for mysql_slave database connection..."
sleep 4
done
MS_STATUS=`docker exec mysql_master sh -c 'export MYSQL_PWD=root; mysql -u root -e "SHOW MASTER STATUS"'`
CURRENT_LOG=`echo $MS_STATUS | awk '{print $6}'`
CURRENT_POS=`echo $MS_STATUS | awk '{print $7}'`
start_slave_stmt="SET GLOBAL server_id=2; CHANGE MASTER TO MASTER_HOST='mysql_master',MASTER_USER='slave',MASTER_PASSWORD='password',MASTER_LOG_FILE='$CURRENT_LOG',MASTER_LOG_POS=$CURRENT_POS; START SLAVE;"
start_slave_cmd='export MYSQL_PWD=root; mysql -u root -e "'
start_slave_cmd+="$start_slave_stmt"
start_slave_cmd+='"'
docker exec mysql_slave sh -c "$start_slave_cmd"
docker exec mysql_slave sh -c "export MYSQL_PWD=root; mysql -u root -e 'SHOW SLAVE STATUS \G'"
https://github.com/vbabak/docker-mysql-master-slave
์ ๋งํฌ์ build.sh๋ฅผ ์ฐธ๊ณ ํ์๋๋ฐ, ๊ทธ๋๋ก ์คํํ์ ๋ master ์๋ฒ์ slave ์๋ฒ ๋๋ค server-id๊ฐ 1๋ก ์ค์ ์ด ๋์ด ์ค์ ๋ก replication ๋์ค ์๋ฌ๋ฅผ ๋ ๋๋ค. ๊ทธ๋์ slave ์๋ฒ์์ server-id๋ฅผ 2๋ก ์ค์ ํ๋ ๋ช ๋ น์ ์ถ๊ฐํ์ต๋๋ค.
์ ์คํฌ๋ฆฝํธ ๋์์ Docker ๋ช ๋ น์ด์ ๋ํ ์ดํด๋๊ฐ ์๋ค๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์์ ๊ฒ ๊ฐ๋ค์.
์ฃผ์๊น๊ฒ ๋ณด์์ผ ํ ๊ฑด ๋ค์ MySQL ๋ช ๋ น์ด์ ๋๋ค.
CREATE USER "slave"@"%" IDENTIFIED WITH mysql_native_password BY "password";
GRANT REPLICATION SLAVE ON *.* TO "slave"@"%"; FLUSH PRIVILEGES;
Master ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ slave ์ ์ ๋ฅผ ์์ฑํ๊ณ , replication ๊ถํ์ ๋ถ์ฌํฉ๋๋ค. ๊ถํ์ด ๋ถ์ฌ๋ slave ์ ์ ๋ Master ์๋ฒ์์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ฉด Slave ์๋ฒ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณ ๊ฐ์ ๋ณต์ ํ๋ ์ญํ ์ ์ํํฉ๋๋ค.
SET GLOBAL server_id=2;
CHANGE MASTER TO ...
START SLAVE;
Slave ์๋ฒ์ ์์คํ ๋ณ์ server_id๋ฅผ 2๋ก ์ค์ ํ ํ, Slave ์๋ฒ๊ฐ Master ์๋ฒ๋ก๋ถํฐ ๋ณต์ ๋ฅผ ์์ํ๊ธฐ ์ํ ์ค์ ์ ํ๊ณ ๋ณต์ ํ๋ก์ธ์ค๋ฅผ ์คํํฉ๋๋ค.
๐กMaster ์๋ฒ ํ์ธ
build.sh์ ์คํํ๊ณ ๋ค์ ๋ช ๋ น์ด๋ก Master ์๋ฒ์ ์ ์ํด๋ด ์๋ค.
docker exec -it mysql_master mysql -uroot -proot --database=board
์ ์ ์ดํ slave ์ ์ ๊ฐ ์์ฑ๋๋์ง ํ์ธํ๊ณ , ๋ณต์ ํ๋ก์ธ์ค๊ฐ ๋์๊ฐ๊ณ ์๋์ง ํ์ธํฉ๋๋ค.
mysql> SELECT user, host FROM mysql.user;
mysql> SHOW PROCESSLIST;
๐กSlave ์๋ฒ ํ์ธ
Slave ์๋ฒ์์ replication ์ํ๋ฅผ ํ์ธํด๋ด ๋๋ค. replication ๋์ค ๋ฌธ์ ๊ฐ ์๊ธธ ๊ฒฝ์ฐ ์ด ๊ณณ์์ ์๋ฌ ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
docker exec -it mysql_slave mysql -uroot -proot --database=board
๐กMaster -> Slave ๋จ๋ฐฉํฅ ๋ณต์ ํ ์คํธ
์ด์ Master ์๋ฒ์์ ์ผ์ด๋ ์์ฑ, ์์ , ์ญ์ ํ์๋ Slave ์๋ฒ์์๋ ๋ชจ๋ ์ ์ฉ๋ผ์ผ ํฉ๋๋ค. ์ค์ ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ฑํด๋ณด๊ณ ์ ๋ณต์ ๋๋์ง ํ์ธํด๋ด ์๋ค.
Master ์๋ฒ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค eden
์ ์์ฑํฉ๋๋ค.
mysql> CREATE DATABASE eden;
Slave ์๋ฒ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํํด๋ณด๋ฉด eden
์ด ์์ฑ๋ผ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
ํ์ฌ๋ Master DB ์๋ฒ ์ ์ฒด๋ฅผ ๋ณต์ ํ๊ณ ์๋๋ฐ, ์ฐ๋ฆฌ๊ฐ ํ์ํ ๊ฒ์ board
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณต์ ์ด๊ธฐ ๋๋ฌธ์ ํฅํ ์๊ฐ์ด ๋ ๋ ์ค์ ์ ๋ณ๊ฒฝํ ํ์๊ฐ ์๊ฒ ์ต๋๋ค. ๋ํ Replication์ ๊ตฌ์ฑํ ๊น์, ํฅํ Fail-over๊ฐ ๋๋๋ก ๊ตฌ์ฑํ์ฌ DB ์๋ฒ ์ฅ์ ์ ๋ํ ์ ์ฐํ ์ฒ๋ฆฌ๋ฅผ ํ ๊ณํ์
๋๋ค.
๐ฏ์ ๋ฆฌ
docker compose๋ฅผ ์ด์ฉํ์ฌ Master ์๋ฒ์ Slave ์๋ฒ๋ฅผ ๋์๋๋ค.
Master ์๋ฒ์์ ๋ณต์ ๋ฅผ ๋ด๋นํ ๊ณ์ ์ ์์ฑํ๊ณ , ๊ถํ์ ๋ถ์ฌํฉ๋๋ค.
Slave ์๋ฒ์์
CHANGE MASTER TO ...
๋ช ๋ น์ผ๋ก ๋ณต์ ์ค์ ์ ํฉ๋๋ค.Slave ์๋ฒ์์
START SLAVE;
๋ก ๋ณต์ ๋ฅผ ์์ํ ํ, ์ค์ ๋ก Master ์๋ฒ๋ก๋ถํฐ ๋ณต์ ๊ฐ ์ ๋๋์ง ํ์ธํด ๋ด ๋๋ค.