728x90

DB의 데이터는 아주 중요하다. 얼마나 중요하냐면 용량을 2~3배를 써서라도 안정성을 유지하려고한다.

이렇게 데이터를 백업해 두는 방식으로는 Replication이 있다.

즉 데이터를 똑같이 복제를 하는것이다.

 

출처 - https://mariadb.org/database-master-slave-replication-in-the-cloud/

 

여기서 Replication을 설명하기 앞서서 말하자면

 

첫번째로 Replication은 단방향이라는 것이다.

Replication을 해주는 녀석이 Master이고 받는 녀석이 Slave이다.

여기서 Slave는 Master와 동기화된다.

착각하지 말아야할건 Master는 Slave와 동기화되지 않는다는 점이다.

이건 아주아주아주 중요하다.

만약 Master도 Slave와 동기화를 하고싶다면 반대로도 replication이 걸려야한다.

 

두번째로 Replication이 된 DB를 관리하는건 또 별개의 문제라는 것이다.

Replication자체는 별로 어려운게 아니지만 관리하거나 설정하는건 엄청난 피로도를 요한다.

이런걸 다 설명할 만큼의 시간도 없고 너무 case by case인 경우도 많다.

 

이걸 염두해두고 Replication에 대해서 한번 논해보도록 해보자.

 

https://github.com/kukaro/Eris-DockerExampleTemplate/tree/master/Mysql.Replication

해당 예제는 필자가 이렇게 DockerShell Script를 이용해서 제작하였다.

문제는 이 예제는 맥에서만 정확히 동작한다는 것. 그 이유는 shell script때문인데,

bash를 썼긴 했지만 ipconfig명령어를 사용했기 때문이다.

따라서 리눅스의 경우 조금 변경해서 보고

shell 스크립트가 아닌 batch스크립트를 쓰는 윈도우의 경우에는 참고만 하는 것이 좋다.

 

다행히도 docker의 경우에는 mac,linux,window가 동일하게 동작하므로 shell script부분은 수동으로 동작해주길 바란다.

 

docker의 경우 이 카테고리들을 참조하는게 좋다.

docker를 이용한 예제들은 이 카테고리를 참조하는 것도 도움이 된다.

아직 설명이 부족하므로 모르겠으면 외부에 검색해서 보는것도 방법중 하나이다.

 

그리고 Docker를 모른다면 그냥 수동으로 하는것도 좋다.

Docker를 사용하는 이유는 그냥 한 컴퓨터에서 mysql을 여럿 돌리기 위해서이다.

한컴퓨터에서 docker없이 여러개 돌리는 방법에 대해서 여러가지가 있지만

윈도우는 포스팅 해놓은게 있으니 도커가 쓰기 꺼려진다면 참고 바란다.

 

프로젝트 구조는 위와 같다.

 

mymaster와 myslave는 각각 dockerimage이다.

내부를 보도록 하자.

 

그럼 일단 Master부터 보자고!

 

여기서 dockerfile과 docker-compose를 같이 봐야한다.

 

먼저 docker-compose.yml을 보도록하자.

 

version: '3.3'

services:
  db-master:
    image: mymaster
    volumes:
      - ./mysql-init-files/:/docker-entrypoint-initdb.d/
      - ./mysql-config-files/:/etc/mysql/conf.d
    restart: always
    container_name: mymaster
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD="true"
    ports:
      - '3333:3306'
    expose:
      - '3333'

해당 compose에서 보면 image는 mymaster를 사용한다.

mymaster는 필자가 만든건데 사실 별 내용이 없어서 mysql:5.7로 사용해도 무방하다.

그러나 여러분이 사용하기 전에 커스터마이징을 거칠 수도 있으므로 위 처럼 하였다.

포트번호는 3333으로 하였다. 여러분은 이 포트로 접속하도록 하자.

 

FROM mysql:5.7
MAINTAINER kukaro <justkukaro@naver.com>

#ADD ./mysql-init-files /docker-entrypoint-initdb.d
#ADD ./mysql-config-files/my.cnf /etc/mysql/my.cnf

EXPOSE 3306

CMD ["mysqld"]

 

그 다음 Dockerfile를 보면 위처럼 아무것도 하지 않는다.

다만 주석 처리된 부분을 보면 알 수 있는데 여러분이 만든 my.cnf를  /etc/my.cnf에 넣어줘야한다.

그리고 docker-entrypoint-initdb.d에 넣어주면 docker는 자동으로 해당 폴더아래의 sql을 mysql에서 실행한다.

 

직 docker-compose의 volumes에 있는 저 두줄이랑 dockerFile에 있는 저 주석처리된 두 줄은 효과가 같다.

선택해서 써주면 된다.

 

야! 난 Docker안써!

 

그런 분들은 안써도 된다.

지금 부터 하는 모든 작업을 수동으로 해주면된다.

사실 지금까지의 도커를 안쓰더라도 수동으로 하면 문제는 없다.

 

my.cnf를 보자

 

[mysqld]
log-bin=mysql-bin
server-id=1

my.cnf의 내용을 보면 위와 같다.

log-bin은 쿼리를 실행하면서 남기는 로그이다.

그리고 server-id는 말그대로 서버아이디인데 보통 서버를 1번으로 둔다.

이 로그를 slave로 던져서 동기화를 시키는 것이다. 그러므로 위와 같은 설정은 꼭 필요하다.

 

그리고 실행할 쿼리를 보자.

 

CREATE DATABASE mydb;

CREATE TABLE mydb.user(
  id VARCHAR(100) PRIMARY KEY,
  name VARCHAR (100),
  age INT
);

#create masteruser and grant privileges
create user masteruser@'%' identified by 'masterpassword';
grant all privileges on *.* to masteruser@'%' identified by 'masterpassword';

#replication
grant replication slave on *.* to 'slaveuser'@'%' identified by 'slavepassword';

 

여기서 db와 table은 우리가 동기화 시킬건데 사실 별로 중요한 구문은 아니다.

그리고 아래의 #create어쩌구 역시 중요한건 아니므로 패스한다.

중요한건 제일 아래의 유저이다.

 

grant replication slave on *.* to 'slaveuser'@'%' identified by 'slavepassword';

우리는 replication전용 유저로 slaveuser를 만들어준다. 이름도 여러분 마음대로 패스워드도 여러분 마음대로 하면된다.

 

이제 server의 준비는 끝났다.

설정이 끝났으면 서버를 재시작해준다.

docker로 지정했다면 당연히 재시작할 필요는 없다.

 

show master status\G;

해당 명령어를 사용하면 알겠지만 우리가 한것이 제대로 적용된걸 확인할 수 있다.

 

그럼 이제  Slave를 보자!

slave의 경우 master와 동일한 docker를 가진다.

조금 다른건 docker이미지의 이름이 myslave라는 점과 포트번호만 빼고 말이다.

 

version: '3.3'

services:
  db-slave:
    image: myslave
    volumes:
      - ./mysql-init-files/:/docker-entrypoint-initdb.d/
      - ./mysql-config-files/:/etc/mysql/conf.d
    restart: always
    container_name: myslave
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD="true"
    ports:
      - '2222:3306'
    expose:
      - '2222'

여러분은 Dockerfile은 볼 필요가 없다. Master와 동일하다.

우리는 docker-compose의 포트번호를 2222로 사용하도록 하자.

물론 여러분이 원하는 포트번호를 사용해도 무방하다.

 

야! 난 Docker안쓴다니까.

 

이제 지금 부터 보면된다...

먼저 my.cnf를 보도록 하자.

 

[mysqld]
server-id=2
replicate-do-db='mydb'

서버의 id는 master와 다르기만 하면된다.

그리고 여러분은 db를 replication할거니까 해당 복제할 db를 정해준다.

 

이제 실행할 쿼리를 보자.

CREATE DATABASE mydb;

CREATE TABLE mydb.user(
  id VARCHAR(100) PRIMARY KEY,
  name VARCHAR (100),
  age INT
);

#create masteruser and grant privileges
create user slaveuser@'%' identified by 'slavepassword';
grant all privileges on mydb.* to slaveuser@'%' identified by 'slavepassword';

replication을 하기 앞서서 일단 db와 table을 똑같이 만들어준다.

이게 중요한데 replication이 되기 직전에 데이터는 동기화가 죽었다 깨어나도 되지 않는다.

그렇기 때문에 테이블이나 db는 이미 Master에 존재하기 때문에 여러분도 똑같이 Slave에서 만들어줘야한다.

단 replication이 되고나서 부터는 db나 table을 새로만드는 작업을 인식해서 똑같이 반영된다.

#주석 이하의 내용은 사실 안해도 되므로 안해줘도 된다.

 

설정이 끝났으면 마찬가지로 서버를 재시작한다.

 

이제 동기화에 대한 마지막 작업을 하도록 하겠다. init.sh를 보면되는데 여러분이 shell을 쓸수 없거나 잘 모른다고해서 무서워할건없다.

그냥 해당작업들을 여러분이 수동으로 작업해주면 끝날 일이기 때문이다.

#!/usr/bin/env bash

#make mymaster image
docker build -t mymaster ./mymaster/
docker-compose -f ./mymaster/docker-compose.yml up -d

#sleep 10s

#make myslave image
docker build -t myslave ./myslave/
docker-compose -f ./myslave/docker-compose.yml up -d

sleep 10s

myaddress=`ipconfig getifaddr en0`
myaddress=${myaddress}

master_log_file=`mysql -h127.0.0.1 --port 3333 -uroot -e "show master status\G" | grep mysql-bin`
master_log_file="${master_log_file}"

re="[a-z]*-bin.[0-9]*"

if [[ ${master_log_file} =~ $re ]];then
    master_log_file=${BASH_REMATCH[0]}
fi

master_log_pos=`mysql -h127.0.0.1 --port 3333 -uroot -e "show master status\G" | grep Position`
master_log_pos="${master_log_pos}"

re="[0-9]+"

if [[ ${master_log_pos} =~ $re ]];then
    master_log_pos=${BASH_REMATCH[0]}
fi

query="change master to master_host='${myaddress}', master_user='slaveuser', master_password='slavepassword', master_log_file='${master_log_file}', master_log_pos=${master_log_pos}, master_port=3333"

mysql -h127.0.0.1 --port 2222 -uroot -e "${query}"
mysql -h127.0.0.1 --port 2222 -uroot -e "start slave"

해당 구문을 처음부터 보자.

 

#make mymaster image
docker build -t mymaster ./mymaster/
docker-compose -f ./mymaster/docker-compose.yml up -d

#make myslave image
docker build -t myslave ./myslave/
docker-compose -f ./myslave/docker-compose.yml up -d

도커를 빌드해준다. 당연하다.

 

sleep 10s

그 다음 db가 열릴 때 까지 10초정도 기다려준다.

여러분이 수동으로한다면 스크립트를 쓸것도 없고 잠시 기다려주자.

 

myaddress=`ipconfig getifaddr en0`
myaddress=${myaddress}

그 다음 여러분의 현재 ip주소를 받아온다.

중요한건 127.0.0.1같은 루트백 주소를 사용하지말고 진짜 주소를 알아와야한다는 점이다.

이때 이 myaddress는 master의 주소를 의미한다.

수동으로 하고있다면 master의 주소를 적어준다.

 

master_log_file=`mysql -h127.0.0.1 --port 3333 -uroot -e "show master status\G" | grep mysql-bin`
master_log_file="${master_log_file}"

re="[a-z]*-bin.[0-9]*"

if [[ ${master_log_file} =~ $re ]];then
    master_log_file=${BASH_REMATCH[0]}
fi

그 다음 master의 log file의 위치를 받아온다.

위의 로직을 설명하자면 master status를 mysqld에서 커맨드라인으로 실행시킨다.

그 다음 grep으로 결과중에서 mysql-bin이라는 문구가 적힌 라인을 긁어온다.

그리고 이를 정규표현식으로 뽑아온다.

수동으로 한다면 mysql-bin<숫자>형식의 데이터를 그냥 기억해 두면된다.

 

master_log_pos=`mysql -h127.0.0.1 --port 3333 -uroot -e "show master status\G" | grep Position`
master_log_pos="${master_log_pos}"

re="[0-9]+"

if [[ ${master_log_pos} =~ $re ]];then
    master_log_pos=${BASH_REMATCH[0]}
fi

그 다음 position도 똑같이 가져와야한다.

로직 설명은 위와 같다.

수동으로 한다면 Position값의 숫자를 긁어오면된다.

 

query="change master to master_host='${myaddress}', master_user='slaveuser', master_password='slavepassword', master_log_file='${master_log_file}', master_log_pos=${master_log_pos}, master_port=3333"

mysql -h127.0.0.1 --port 2222 -uroot -e "${query}"
mysql -h127.0.0.1 --port 2222 -uroot -e "start slave"

그 다음 change master to 구문을 slave서버에 넣고 실행시켜준다.

위 구문은 slave에서 master를 지정하는 방법이며 우리가 위애서 가져온 master의 주소, position, logfile을 몽땅 가져온다.

그리고 start slave로 실행시켜준다.

 

change master to
master_host='10.0.0.4',
master_user='slaveuser',
master_password='slavepassword',
master_log_file='mysql-bin.000003',
master_log_pos=154,
master_port=3333;

수동으로 스크립트를 넣는다면 slave에서 위같은 형식으로 넣어주면된다.

 

재시작할필요는 없고 기다리면 알아서 master와 연결된다.

 

연결 됬는지는 어떻게 아냐?

 

확인해 보면되지 뭐.

필자가 짠 스크립튼데 위는 master의 서버로 연결되고 아래는 slave와 연결된다.

물론 수동으로 하겠다면 아래같이 명령어를 치면된다.

 

mysql -h<주소> --port <포트> -uroot <-p : 필요하다면>

 

먼저 Master부터 보자.

show processlist\G

Master에서 위처럼 실행했을 때 프로세스가 slaveuser로 시작하고

command가 Binlog Dump로 시작되는게 있다면 동작중인 것이다.

 

이번엔 Slave로 가보자.

 

show processlist\G

 

위 처럼 검색했을 때 State가 Waiting for masgter라고 되어있는 프로세스,

그리고 Slave has read all이라고 State가 되이었는 프로세스가 돌고있으면 성공한것이다.

 

그럼 진짜 replication이 되는지 한번 보도록 하자.

 

 

영상을 보기 귀찮다면 움짤도 있다.

근데 움짤 로딩하는데 시간걸릴수 있다.

 

이렇게 replication이 되는걸 확인했다.

그러나 replication이 됬다고 끝나는게 아니라 이걸 어떻게 관리하느냐도 중요하다는걸 알아두길 바란다.

+ Recent posts