MySQL Replication with Docker

Photo by Ivy Farm on Unsplash

MySQL Replication with Docker

[#๐ŸฌBoard] Replication์œผ๋กœ DB ๋ถ€ํ•˜ ๋ถ„์‚ฐํ•˜๊ธฐ

ยท

4 min read

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 ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ณต์ œ๊ฐ€ ์ž˜ ๋˜๋Š”์ง€ ํ™•์ธํ•ด ๋ด…๋‹ˆ๋‹ค.


๐Ÿ”–์ฐธ๊ณ 

ย