MySQL HA(High Availability) Replication 구축

Mugeon Kim·2024년 6월 25일
0
post-thumbnail

서론


  • 이번에는 Docker로 MySQL Replication 구축 과정에 대해서 기록합니다. Replication에 관심을 가지게 된 계기는 디비를 사용하고 운영할 때 확장, 가용성이 중요하다. 일반적으로 가장 많이 사용되는 기술이 Replication이다.

  • 최종적으로 MySQL에서 Replication에서 다음과 같은 학습을 하겠습니다.

  1. MySQL Bridge Network Replication
  2. Orchestrator를 이용한 High Availability(HA) 구성
  3. 모니터링
  4. Swarm 모드 확장 및 Backup
  • 이번에는 1번 Bridge Network를 통한 Replication을 설정하겠습니다.

본론


Replication

Replication은 데이터베이스에서 데이터를 한 서버(Master)에서 다른 서버(Slave)로 복제하는 기술입니다. 이를 통해 데이터의 확장성, 가용성을 높이고, 장애 복구 시간을 줄이며, 읽기 성능을 향상시킬 수 있습니다. 특히 분산 시스템에서 자주 사용됩니다. 이를 통해 주요 서버의 부하를 줄이고 여러 서버에 걸쳐 데이터를 분산시킬 수 있습니다.

Replication의 동작 원리

MySQL의 Replication은 일반적으로 Master-Slave 구조로 구성됩니다. Master는 데이터를 변경하는 트랜잭션의 로그를 기록하고, Slave는 이를 읽어 자신의 데이터베이스에 반영합니다.

Replication의 기본 동작 흐름은 다음과 같습니다:

  1. Binlog 작성 (Master)
    Master는 데이터베이스의 변경 사항(INSERT, UPDATE, DELETE 등)을 Binary Log(binlog)에 기록합니다.
    이 로그는 트랜잭션의 순서와 상태를 포함하며 Slave에게 전달됩니다.

  2. Relay Log 수신 및 저장 (Slave)
    Slave는 Master의 Binlog를 복제하여 자신의 Relay Log에 저장합니다.
    이 과정에서 Slave는 Master의 위치를 추적하여 복제를 지속적으로 유지합니다.

  3. SQL 스레드 실행 (Slave)
    Slave는 Relay Log를 기반으로 SQL 명령을 실행하여 Master와 동일한 데이터베이스 상태를 유지합니다.

  4. 비동기적 복제
    MySQL Replication은 기본적으로 비동기 방식으로 동작합니다. Slave는 Master의 상태를 따라가지만 즉각적으로 동일한 상태가 되지는 않습니다. 필요에 따라 반동기적(Semi-synchronous) 또는 완전 동기적(Synchronous) 복제를 설정할 수도 있습니다.

Replication의 주요 특징

  1. 확장성(Scalability)
    Master는 데이터 변경 작업을 처리하고 Slave는 읽기 작업을 분담함으로써 읽기 성능을 향상시킬 수 있습니다.

  2. 가용성(High Availability)
    Master 서버에 문제가 생기더라도 Slave 서버로 빠르게 전환(Failover)하여 시스템을 계속 운영할 수 있습니다.

  3. 백업 및 분석 용이성
    Slave 서버를 이용해 데이터를 백업하거나 분석 작업을 수행할 수 있습니다. 이 과정에서 Master의 부하를 최소화할 수 있습니다.

  4. 유연성
    다양한 복제 설정(예: Single-Master Multi-Slave, Multi-Master 등)을 지원하여 요구 사항에 맞게 구성을 조정할 수 있습니다.

Replication의 한계와 고려 사항

  1. 비동기적 특성
    기본적으로 비동기적으로 동작하므로, Master와 Slave 간 데이터 지연(Lag)이 발생할 수 있습니다.
    반동기적 또는 동기적 복제를 설정하면 데이터 일관성이 향상되지만, 쓰기 성능에 영향을 미칠 수 있습니다.

  2. Failover 복잡성
    Master 장애 시 Slave를 Master로 승격(Promotion)하는 작업이 필요합니다. 이를 자동화하려면 추가적인 도구(예: Orchestrator)를 도입해야 합니다.

  3. 데이터 손실 가능성
    Master 장애 시 Binlog가 Slave에 완전히 전달되지 않았다면 데이터 손실이 발생할 수 있습니다.

Master-Slave Replication 구성하기

  • 시작에 앞서 다음과 같은 구조를 가져가겠습니다.
db001
|-- conf
|-- data
|   |-- #innodb_redo
|   |-- #innodb_temp
|   |-- mysql
|   |-- performance_schema
|   `-- sys
`-- log
db002
|-- conf
|-- data
|   |-- #innodb_redo
|   |-- #innodb_temp
|   |-- mysql
|   |-- performance_schema
|   `-- sys
`-- log
db003
|-- conf
|-- data
|   |-- #innodb_redo
|   |-- #innodb_temp
|   |-- mysql
|   |-- performance_schema
|   `-- sys
`-- log
  • 해당 경로를 살펴보면 크게 conf, data, log로 설정이 되어져 있습니다. 해당 부분은 docker는 stateless이기 때문에 결국에는 운영단계에서 사용하기 위해서는 volumn을 통해서 관련 정보를 저장합니다.

  • db 3개를 사용하기 때문에 3개의 폴더에 conf, data, log를 추가하겠습니다. 또한 권한을 추가가 필요합니다.

적절한 권한을 설정
테스트를 위해서 chmod 777를 주었을 때 mysql에서 권한의 범위가 매우 넓기 때문에 무시한 경우가 있습니다. 적절한 권한을 주기 위해서는 파일에 644, 폴더에는 755를 통해서 권한을 설정합니다.

chmod 644 *
chmod 755 *
  • 각 conf에 간단한 my.cnf파일을 설정을 합니다. 해당 파일을 db001, db002, db003에 따라서 각각 처리를 합니다. 이때 가장 중요한 부분은 server-id, report_host를 적절하게 각 mysql에 맞게 설정을 합니다.
[mysqld]
log_bin                     = mysql-bin
binlog_format               = ROW
gtid_mode                   = ON
enforce-gtid-consistency    = true
server-id                   = 100
log_slave_updates
datadir                     = /var/lib/mysql
socket                      = /var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links              = 0

log-error                   = /var/log/mysql/mysqld.log
pid-file                    = /var/run/mysqld/mysqld.pid

report_host                 = db001

[mysqld_safe]
pid-file                    = /var/run/mysqld/mysqld.pid
socket                      = /var/lib/mysql/mysql.sock
nice                        = 0

Docker 컨테이너 실행

  • 가장 간단한 방법으로 docker에 mysql을 3개 올리겠습니다. 관련 정보를 살펴보면 volume에서 log, conf, data를 설정하였습니다. 이후 가장 간단하게 docker ps를 통해서 docker의 유무를 체크하고 바로 다음 단계로 넘어가겠습니다.
docker run -d -p 3306:3306 --name db001 \
-e MYSQL_ROOT_PASSWORD=1234 \
-v /Users/mugeon/docker/db/db001/log:/var/log/mysql \
-v /Users/mugeon/docker/db/db001/data:/var/lib/mysql \
-v /Users/mugeon/docker/db/db001/conf:/etc/my.cnf.d \
percona/percona-server:8.0.39-aarch64

docker run -d -p 3307:3306 --name db002 \
-e MYSQL_ROOT_PASSWORD=1234 \
-v /Users/mugeon/docker/db/db002/log:/var/log/mysql \
-v /Users/mugeon/docker/db/db002/data:/var/lib/mysql \
-v /Users/mugeon/docker/db/db002/conf:/etc/my.cnf.d \
percona/percona-server:8.0.39-aarch64


docker run -d -p 3308:3306 --name db003 \
-e MYSQL_ROOT_PASSWORD=1234 \
-v /Users/mugeon/docker/db/db003/log:/var/log/mysql \
-v /Users/mugeon/docker/db/db003/data:/var/lib/mysql \
-v /Users/mugeon/docker/db/db003/conf:/etc/my.cnf.d \
percona/percona-server:8.0.39-aarch64
  • 처음에 db001을 접근하여 master계정을 추가하겠습니다.
docker exec -it -uroot db001 mysql -u root -p 
# > 비밀번호 입력

docker exec -it -uroot db001 mysql -u root -p 
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
# 권한 즉시 적용
FLUSH PRIVILEGES;
  • 해당 과정을 통해서 master db에서 유저를 만들 고 해당 db의 ip를 확인한다. ifconfig 명령어를 통해서 확인이 가능하다.
  • 해당하는 ip를 slave db002, db003에 기본적인 ip로 설정을 합니다.

  • 이후 db002, db003에서 접속하여 다음과 같은 작업을 수행합니다.
reset master;

CHANGE MASTER TO MASTER_HOST='${master_IP}', 	MASTER_USER='repl',
 MASTER_PASSWORD='repl',
 MASTER_AUTO_POSITION=1,
 MASTER_SSL=1;
START REPLICA;

show slave status\G

  • 위 과정을 통해서 가장 간단하게 mysql replication을 수행할 수 있었습니다.

하지만 조금의 문제점이 있습니다. 해당 docker를 통해서 꺼졌다가 켜지게 되면 IP가 변경이 됩니다. 또한 docker run을 통해서 관리하기 너무 힘들다는 문제가 있기 때문에 이 2가지 문제를 network, compose를 통해서 처리하겠습니다.

Bridge Network Replication

  • 컨테이너는 언제든지 재 시작될 수 있고 Container가 재 시작하게 되면 IP가 변경될 수 있다. 기존의 Ifconfig를 통해서 Master DB의 IP를 기반으로 설정을 하여 HA 구성을 처리했다.

  • 하지만 IP가 바뀐다면 Replication이 깨질 수 있기 때문에 Bridge Network를 구성하고 alias를 통해서 변경이 되어서 문제를 해결할 수 있게 하겠다.

1. 네트워크 생성

docker network create --driver bridge mybridge

2. Docker-compose.yml

  • 해당 과정을 통해서 이제는 docker run을 여러번 할 필요가 없어지고 관련설정을 따로 변수로 관리할 수 있습니다.

  • 이제 생성된 Bridge Network를 이용하여 각 MySQL 서버의 컨테이너를 생성합니다. 각 컨테이너는 'mybridge'라는 이름의 네트워크에 연결되며, 'db001', 'db002', 'db003'라는 net alias를 각각 부여받습니다. 이를 통해 각 컨테이너는 서로 통신할 수 있는 환경을 구성하게 됩니다.

version: '3.8'

networks:
  mybridge:
    driver: bridge

services:
  db001:
    image: percona/percona-server:8.0.39-aarch64
    container_name: db001
    networks:
      mybridge:
        aliases:
          - db001
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "1234"
    volumes:
      - /Users/mugeon/docker/db/db001/log:/var/log/mysql
      - /Users/mugeon/docker/db/db001/data:/var/lib/mysql
      - /Users/mugeon/docker/db/db001/conf/my.cnf:/etc/my.cnf 

  db002:
    image: percona/percona-server:8.0.39-aarch64
    container_name: db002
    networks:
      mybridge:
        aliases:
          - db002
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "1234"
    volumes:
      - /Users/mugeon/docker/db/db002/log:/var/log/mysql
      - /Users/mugeon/docker/db/db002/data:/var/lib/mysql
      - /Users/mugeon/docker/db/db002/conf/my.cnf:/etc/my.cnf  

  db003:
    image: percona/percona-server:8.0.39-aarch64
    container_name: db003
    networks:
      mybridge:
        aliases:
          - db003
    ports:
      - "3308:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "1234"
    volumes:
      - /Users/mugeon/docker/db/db003/log:/var/log/mysql
      - /Users/mugeon/docker/db/db003/data:/var/lib/mysql
      - /Users/mugeon/docker/db/db003/conf/my.cnf:/etc/my.cnf 

Replication 설정

  • 이전과 동일하게 Master DB에 계정과 권한을 설정합니다.
docker exec -it -uroot db001 mysql -u root -p 
# > 비밀번호 입력

docker exec -it -uroot db001 mysql -u root -p 
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
# 권한 즉시 적용
FLUSH PRIVILEGES;
  • 이후 Slave 설정을 할때 기존의 Ifconfig를 통해 얻은 IP가 아닌 alias를 통해 연결합니다.
docker exec -it db002 mysql -u root -p
# 비밀번호 입력

CHANGE MASTER TO
    MASTER_HOST='db001',
    MASTER_USER='repl',
    MASTER_PASSWORD='repl',
    MASTER_AUTO_POSITION=1;
START REPLICA;

SHOW SLAVE STATUS\G;

docker exec -it db003 mysql -u root -p
# 비밀번호 입력

CHANGE MASTER TO
    MASTER_HOST='db001',
    MASTER_USER='repl',
    MASTER_PASSWORD='repl',
    MASTER_AUTO_POSITION=1;
START REPLICA;

SHOW SLAVE STATUS\G;

결론


이번 글에서는 Docker와 MySQL을 활용하여 Master-Slave Replication 환경을 구축하는 방법을 다뤘습니다. Replication을 통해 장애 복구 및 읽기 성능을 향상시킬 수 있음을 확인했습니다.

다음 단계에서는 Orchestrator를 활용하여 High Availability를 구현하고, 모니터링 도구를 통해 상태를 관리하는 과정을 다룰 예정입니다.

참고


https://www.inflearn.com/course/mysql-docker/dashboard
https://kimdubi.github.io/cloud/docker_mysql_repl/
https://jane096.github.io/project/mysql-master-slave-replication/

profile
빠르게 실패하고 자세하게 학습하기

0개의 댓글