MySQL을 Master-Slave 이중화로 구성하여 보자!

Terror·2024년 11월 4일

최종 프로젝트

목록 보기
17/28

Overivew

  • Master DB, Slave DB를 통해 고가용성을 유지 할 수 있습니다
  • 두개의 DB를 서로 공유하게 만들 수 있습니다

시나리오

  • 하나의 서버안에 서로 다른 DB를 둔다
  • 서로다른 DB는 Master DB (Write), Slave DB(Write)용으로 나뉜다
  • Master DB에서 장애가 발생하더라도, Master DB의 내용을 replica 하던 Slave DB를 사용함으로써 문제가 없게한다

동작방식

  • 어떤방식으로 Master DB의 데이터가, Slave DB에 복제(replica)되는걸까?
  1. Master DB가 binary log를 만들어 이벤트를 기록합니다
  2. 각 Slave DB는 어떤 이벤트까지 저장되어있는지 기억하고 있습니다
  3. Slave DB의 IO Thread를 통해서 Master DB에 이벤트를 요청하고 받아옵니다
  4. Master DB는 이벤트를 요청받으면 binary dump thread를 통해서 클라이언트에게 이벤트를 전송합니다
  5. IO thread는 전송받은 덤프 로그를 이용하여 relay log를 만듭니다
  6. SQL Thraed는 relay log를 읽어서 이벤트를 다시 실행하여 Slave DB에 데이터를 복사합니다
  • 정리하면 아래와같다 (정확히는 내가 이해한바로는..)
  1. 클라이언트로부터 저장 요청이 들어온다
  2. binary log에 저장한다 (어떤 이벤트가 일어나는지
  3. 실제 Master DB에 저장한다
  4. binary log에 저장한 binary log를 binary dump thraed를 통해 Slave DB에 옮긴다
  5. Slave DB에서는 해당 binary log를 그대로 읽고 다시 실행한다

기본적인 뼈대

root

ㄴ master
ㄴ ㄴ Dockerfile
ㄴ ㄴ my.cnf

ㄴ slave
ㄴ ㄴ Dockerfile
ㄴ ㄴ my.cnf

ㄴ docker-compose.yml

Master Dockerfile,my.cnf

FROM mysql:8.0
COPY ./master/my.cnf /etc/mysql/my.cnf

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

# MySQL 서버(daemon)의 설정을 지정한다.
[mysqld]
character-set-client-handshake = FALSE
character-set-server           = utf8mb4
collation-server               = utf8mb4_unicode_ci
default-time-zone='+9:00'

# 이진 로그를 사용해서 MySQL 서버에서 발행하는 변경 사항을 기록한다. mysql-bin은 이진로그의 파일 이름을 지정한다.
log-bin = mysql-bin

# MySQL 서버의 고유한 식별자를 설정한다. 이 식별자는 MySQL 복제(replication) 설정에서 사용된다.
server-id = 1

# MySQL 사용자의 인증 플러그인을 mysql_native_password로 지정한다 -> 5.7 이전 버전과의 호환성을 유지하기 위해 사용되는 매커니즘이다.
default_authentication_plugin=mysql_native_password

Slave Dockerfile,my.cnf

FROM mysql:8.0
COPY ./slave/my.cnf /etc/mysql/my.cnf

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-client-handshake = FALSE
character-set-server           = utf8mb4
collation-server               = utf8mb4_unicode_ci
default-time-zone='+9:00'

log_bin = mysql-bin
server_id = 2

# MySQL 슬레이브 서버에서 사용되는 중계로그(relay log)의 저장 위치를 지정한다.
relay_log = /var/lib/mysql/mysql-relay-bin

# 슬레이브 서버에서 발행하는 변경 사항도 이진 로그에 기록하도록 하게 하는 설정이다. 기본적으로 슬레이브 서버의 변경 사항은 이진 로그에 기록되지 않는다.
log_slave_updates = 1

# 슬레이브 서버를 읽기 전용 모드로 설정한다.
read_only = 1

default_authentication_plugin=mysql_native_password

Docker-compose.yml

services:
  # 서비스의 이름
  db-master:
    # 도커 이미지를 빌드하는 방법을 지정
    build:
      # 현재 디렉토리를 빌드 컨텍스트로 사용
      context: ./
      # master 디렉토리에 위치한 Dockerfile을 사용하여 도커 이미지를 빌드
      dockerfile: master/Dockerfile
    # 컨테이너가 비정상적으로 종료되었을 때 자동으로 재시작
    restart: always
    # 컨테이너가 실행될 플랫폼을 지정
    platform: linux/x86_64
    # 컨테이너 내에서 사용할 환경 변수를 설정
    environment:
      # MySQL 데이터베이스의 이름을 db로 설정
      MYSQL_DATABASE: 'db'
      # MySQL에서 사용될 사용자 이름을 설정
      MYSQL_USER: 'user'
      # MySQL에서 사용될 사용자의 비빌번호를 설정
      MYSQL_PASSWORD: '1234'
      # MySQL 루트 사용자의 비밀번호를 설정
      MYSQL_ROOT_PASSWORD: '1234'
    # 호스트와 컨테이너 간의 포트 매핑을 정의한다 -> 호스트의 3306 포트와 컨테이너의 3306 포트를 연결
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    ports:
      - '3308:3306'
    # 컨테이너 이름을 정의
    container_name: master-db
    # 데이터를 영속적으로 저장할 볼륨을 정의 -> 볼륨은 컨테이너가 시작될 때 생성되고 컨테이너가 종료되어도 데이터가 유지된다.
    volumes:
      - my-db-master:/var/lib/mysql
      - my-db-master:/var/lib/mysql-files
    # 서비스가 연결될 네트워크를 지정
    networks:
      - net-mysql
  
  db-slave:
    build:
      context: ./
      dockerfile: slave/Dockerfile
    restart: always
    platform: linux/x86_64
    environment:
      MYSQL_DATABASE: 'db'
      MYSQL_USER: 'user'
      MYSQL_PASSWORD: '1234'
      MYSQL_ROOT_PASSWORD: '1234'
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    ports:
      - '3309:3306'
    container_name: slave-db
    # Where our data will be persisted
    volumes:
      - my-db-slave:/var/lib/mysql
      - my-db-slave:/var/lib/mysql-files
    networks:
      - net-mysql

# 컨테이너에서 사용할 볼륨의 이름을 정의한다.
volumes:
  my-db-master:
  my-db-slave:

# net-mysql 이라는 이름의 네트워크를 정의한다.
networks:
  net-mysql:
    # 이 네트워크는 Docker 컨테이너들 사이의 통신을 가능하게 하는 bridge 네트워크임을 정의
    driver: bridge
  • 상세한 설명은 참조블로그의 저자분이 친절하게 달아놓았으니 참조해주길 바란다

실제 실행해보자

docker-compose up -d

  • 잘 실행이 되는 모습이다
docker network ls

  • 네트워크로 확인해봐도 정상적으로 확인된다
  • 그 다음 우리는 Master DB의 ip4Adress가 필요하기 때문에, docker의 inspect명령을 통해 확인해보자
docker inspect {bridge의 network Id}

  • master-db의 ip4Adress는 다른 메모장에 붙여주자
docker exec -it master-db mysql -u root -p'1234';
  • 도커의 master-db에 접속해준다음
show master status;
  • 상태를 확인해보고
  • 상단 File의 데이터와, Position의 데이터도 다른 메모장에 복사해주자
  • status를 확인하였다면, exit으로 나온다음
  • 똑같은 방법으로 slave-db에 접속한 다음 아래와같은 명령어를 입력해주자
CHANGE MASTER TO
    MASTER_HOST='172.19.0.2',
    MASTER_USER='root',
    MASTER_PASSWORD='1234',
    MASTER_LOG_FILE='mysql-bin.000004',
    MASTER_LOG_POS=157;
  1. master-db ip4Adress
  2. root
  3. password
  4. master-db File 데이터
  5. master-db Position 데이터
    를 차례대로 적어주자
  • 그리고 아래 명령어를 적어주자
start slave;
show slave status\G;

  • 그렇다면 여러가지가 뜰텐데,
  • slave-IO_Running
  • Slave-SQL-Runnig
  • 이 두가지가 Yes인지 확인해준다
  • 둘다 Yes라면 다시 Master-db에서 DB를 만들고 테이블만들고, 데이터까지 넣어보자
create database master;
use master;
create table member (id int, name varchar(30));
insert into member (id,name) values (1,'test');
select * from member;

  • master-db에는 정상적으로 조회되고, slave-db에서도 확인해보면..!
  • 정상적으로 들어오는 모습을 확인 할 수 있다

참조블로그

https://velog.io/@ch4570/MySQL-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%82%B0-%EC%B2%98%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-Master-Slave-%EC%9D%B4%EC%A4%91%ED%99%94%EB%A5%BC-%EA%B5%AC%EC%84%B1%ED%95%98%EB%8B%A4MySQL-Replication-%EC%84%A4%EC%A0%95%EA%B3%BC-%EA%B5%AC%EC%84%B1

profile
테러대응전문가

0개의 댓글