같은 VPC 내 서로 다른 서버에 위치한 MySQL 인스턴스 간의 Replication 구성

MySQLReplicationmasterslave
avatar
2025.04.20
·
7 min read

이전에는 하나의 서버 내에서 Docker-Compose 기반으로 MySQL Replication을 구성하였으나,
이번에는 같은 VPC 내 서로 다른 서버에 위치한 MySQL 인스턴스 간의 Replication 구성 과정을 기록하였습니다.

현재 구성

  • 서버 1: Docker, MySQL (Master)

  • 서버 2: Docker, MySQL (Slave)


DB 환경 설정

Master DB 설정

인증서 생성

  • MySQL Replication에서 caching_sha2_password 인증 방식을 그대로 유지하려면 SSL 연결이 필수입니다. 이를 위해 서버 측에서 사용할 인증서를 직접 생성합니다.

mkdir -p /etc/mysql/certs && cd /etc/mysql/certs

# 1. CA 생성
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem -subj "/CN=MySQL_CA"

# 2. Server 인증서
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-req.pem -subj "/CN=MySQL_Server"
openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem

# 3. Client 인증서
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-req.pem -subj "/CN=MySQL_Client"
openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem

# 4. 권한 설정
chmod 644 server-key.pem server-cert.pem ca.pem

Slave 서버로 인증서 복사

  • SSL 연결을 위해 Master에서 생성한 인증서를 Slave 쪽에도 복사해줍니다.

  • Slave에도 동일한 디렉터리 구조(/etc/mysql/certs/)가 있어야합니다.

scp /etc/mysql/certs/* root@{슬레이브 서버 IP}:/etc/mysql/certs/

my.cnf 작성

vim /home/ubuntu/my.cnf
[client]
# 클라이언트의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4

[mysql]
# MySQL의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4

[mysqld]
# SSL 인증을 위한 CA, 서버 인증서, 서버 키 경로 설정
ssl-ca=/etc/mysql/certs/ca.pem
ssl-cert=/etc/mysql/certs/server-cert.pem
ssl-key=/etc/mysql/certs/server-key.pem

# 보안 연결(SSL)만 허용
require_secure_transport=ON

# MySQL 서버의 문자 집합을 utf8mb4로 설정합니다.
character-set-server = utf8mb4

# MySQL 서버의 정렬을 utf8mb4_unicode_ci로 설정합니다.
collation-server = utf8mb4_unicode_ci

# 서버의 기본 시간대를 GMT+9로 설정합니다.
default-time-zone = '+9:00'

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

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

MySQL 실행

docker run -d \
  --name master \
  -e MYSQL_ROOT_PASSWORD=rootpassword \
  -e MYSQL_USER=admin_ohy \
  -e MYSQL_PASSWORD=adminpassword \
  -e MYSQL_DATABASE=today-table \
  -p 3306:3306 \
  -v /home/ubuntu/mysql_data:/var/lib/mysql \
  -v /etc/mysql/certs:/etc/mysql/certs \
  -v /home/ubuntu/my.cnf:/etc/mysql/conf.d/my.cnf \
  mysql:8.0.33

Slave DB 설정

Slave는 Master에서 전달받은 데이터를 그대로 반영하는 역할을 하므로, 읽기 전용 설정 및 relay log 설정이 필요합니다.

my.cnf 작성

vim /home/ubuntu/my.cnf
[client]
# MySQL 클라이언트의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4

[mysql]
# MySQL의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4

[mysqld]
# MySQL 서버의 문자 집합을 utf8mb4로 설정합니다.
character-set-server = utf8mb4

# MySQL 서버의 정렬을 utf8mb4_unicode_ci로 설정합니다.
collation-server = utf8mb4_unicode_ci

# 서버의 기본 시간대를 GMT+9로 설정합니다.
default-time-zone = '+9:00'

# 복제를 위해 바이너리 로깅을 활성화합니다.
log_bin = mysql-bin

# 복제를 위한 서버 식별자를 설정합니다.
server_id = 2

# MySQL 슬레이브 서버에서 중계 로그를 저장할 위치를 지정합니다.
relay_log = /var/lib/mysql/mysql-relay-bin

# 슬레이브 서버에서 변경 사항을 이진 로그에 기록하도록 합니다.
log_replica_updates = ON

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

MySQL 실행

docker run -d \
  --name slave \
  -e MYSQL_ROOT_PASSWORD=rootpassword \
  -e MYSQL_USER=admin_ohy \
  -e MYSQL_PASSWORD=adminpassword \
  -e MYSQL_DATABASE=today-table \
  -p 3306:3306 \
  -v /home/ubuntu/mysql_data:/var/lib/mysql \
  -v /etc/mysql/certs:/etc/mysql/certs \
  -v /home/ubuntu/my.cnf:/etc/mysql/conf.d/my.cnf \
  mysql:8.0.33

MySQL Replication 설정

Master 쪽 EC2의 퍼블릭 IP 또는 프라이빗 IP 확인

  • 같은 VPC라면 프라이빗 IP

  • 다른 VPC/인터넷 상이라면 퍼블릭 IP

curl ifconfig.me       # 퍼블릭 IP
hostname -I            # 프라이빗 IP

보안 그룹에서 포트 열기

  • Master 쪽 EC2 보안 그룹에서 3306 포트를 Slave 서버의 IP에만 허용해야 합니다.

Master 설정

docker exec -it master bash # Master 계정에 접속하기 위해 명령어 입력
mysql -u root -p # mysql을 root 계정으로 접속
grant all privileges on *.* to '계정이름'@'%' with grant option;
flush privileges;

Slave 설정을 위해 master 에서는 특정 정보만 가져오면 됩니다.

아래의 명령어를 콘솔에 입력해줍니다.

show master status;
5377

Slave 설정에 필요하므로 File(mysql-bin.000001), Position(564)를 기억해둡니다.

Slave 설정

docker exec -it slave bash # Slave 계정에 접속하기 위해 명령어 입력
mysql -u root -p # mysql을 root 계정으로 접속
grant all privileges on *.* to '계정이름'@'%' with grant option;
flush privileges;
stop slave;

CHANGE MASTER TO MASTER_HOST='{master-db의 네트워크 IP}',
 MASTER_USER='{계정 이름}',
 MASTER_PASSWORD='{계정 비밀번호}',
 MASTER_LOG_FILE='{master-db의 바이너리 파일 이름}',
 MASTER_LOG_POS={master-db에서 조회한 파일 포지션},
 MASTER_SSL=1,
 MASTER_SSL_CA = '/etc/mysql/certs/ca.pem',
 MASTER_SSL_CERT = '/etc/mysql/certs/client-cert.pem',
 MASTER_SSL_KEY = '/etc/mysql/certs/client-key.pem';

start slave;

상태 확인

show slave status\G;

정상적으로 연결되었다면 아래와 같은 항목들을 확인할 수 있습니다:

  • Slave_IO_Running: Yes

  • Slave_SQL_Running: Yes

  • Using_SSL: Yes

  • Seconds_Behind_Master: 0


Spring과 JPA 설정은 여기를 참고해주세요.







- 컬렉션 아티클