1) 구성 정보

• Primary: db1

• Replica: db2, db3

• Primary IP: db1ip

• 리플리케이션 계정: repl

• 방식: GTID (SOURCE_AUTO_POSITION=1)

───

2) MySQL 8.0 설치 (3대 공통)

# dnf -y install https://dev.mysql.com/get/mysql80-community-release-el9-5.noarch.rpm
# dnf clean all
# dnf makecache
# dnf -y install mysql-community-server
# systemctl enable --now mysqld

mysql의 레포 설치 및 mysql 커뮤니티 버전 설치 후 실행합니다.

# grep 'temporary password' /var/log/mysqld.log

mysql 설치 후 사용 시 초기 비밀번호를 변경해줘야하기 때문에

/var/log/mysqld.log 파일에서 초기 비밀번호를 확인한 후

# mysql_secure_installation

명령어를 통해 비밀번호 재설정 및 보안 관련 설정을 진행합니다.

버전 확인:

# mysql --version

xtrabackup 진행할 때 mysql 버전 8.0이상 버전의 방식으로 진행하였기 때문에

버전 확인 필수적 입니다.

───

3) 리플리케이션 설정

3-1) db1 (Primary) 설정

설정 파일(/etc/my.cnf 또는 /etc/my.cnf.d/mysql-server.cnf)에 추가:

[mysqld]

server_id=1

log_bin=mysql-bin

binlog_format=ROW

gtid_mode=ON

enforce_gtid_consistency=ON

log_slave_updates=ON

해당 설정 파일 하단에 있는 [mysqld] 부분에 내용을 추가해 줍니다.

# systemctl restart mysqld

설정파일에 추가한 내용을 적용해 주고

# mysql -uroot -p

> CREATE USER 'repl'@'db대역' IDENTIFIED BY '비밀번호';

> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'db대역';

> FLUSH PRIVILEGES;

참고: 인증 플러그인 이슈가 있으면 아래처럼 변경해서 적용해 줍니다.

> ALTER USER 'repl'@'db대역' IDENTIFIED WITH mysql_native_password BY '비밀번호';

> FLUSH PRIVILEGES;

레플리케이션을 위한 유저를 생성해 줍니다. db 대역은 테스트 용도의 경우 '%'로 입력해 모두 허용해 줄 수 있습니다.

보안을 위해 해당 대역대를 입력해 주는 것을 권장합니다.

ex) '192.168.0.%'

───

3-2) db2 / db3 (Replica) 설정

db2

[mysqld]

server_id=2

relay_log=relay-bin

log_bin=mysql-bin

binlog_format=ROW

gtid_mode=ON

enforce_gtid_consistency=ON

log_slave_updates=ON

read_only=ON

db3

[mysqld]

server_id=3

relay_log=relay-bin

log_bin=mysql-bin

binlog_format=ROW

gtid_mode=ON

enforce_gtid_consistency=ON

log_slave_updates=ON

read_only=ON

적용(각 서버):

# systemctl restart mysqld

연동할 다른 db서버에도 같은 위치에 해당 설정 부분을 넣고

설정을 적용해 줍니다.

───

4) Replica에서 Primary 연결

db2, db3 각각 실행:

> STOP REPLICA;

> RESET REPLICA ALL;

> CHANGE REPLICATION SOURCE TO

> SOURCE_HOST='db1ip',

> SOURCE_PORT=3306,

> SOURCE_USER='repl',

> SOURCE_PASSWORD='비밀번호',

> SOURCE_AUTO_POSITION=1;

> START REPLICA;

> SHOW REPLICA STATUS\G;

정상 기준:

• Replica_IO_Running: Yes

• Replica_SQL_Running: Yes

• Last_IO_Error / Last_SQL_Error 없음

위 부분들이 동일하면 연동은 성공입니다.

───

5) 동기화 테스트

db1(Primary)에서 테스트 데이터 생성:

> CREATE DATABASE IF NOT EXISTS repl_test;

> USE repl_test;

> CREATE TABLE IF NOT EXISTS sync_test (

id INT AUTO_INCREMENT PRIMARY KEY, node_name VARCHAR(20), msg VARCHAR(200),

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

) ENGINE=InnoDB;

> INSERT INTO sync_test (node_name, msg) VALUES ('db1', 'replication first check');

데이터베이스 생성 후에 레플리케이션으로 연동한 db2,3에서도 정상적으로 연동 되었는지 확인해줍니다.

db2/db3(Replica)에서 확인:

SELECT * FROM repl_test.sync_test;

3대에서 동일 데이터가 조회되면 단방향 복제 구성 완료입니다.

6) 장애 발생 시 slave DB Master DB로 승격

# systemctl stop mysqld
# systemctl status mysqld

먼저 Master DB 서버의 mysqld를 중단시킨 후

db2를 Master 서버로 승격 시키며 db1 서버의 장애 대응을 진행하겠습니다.

# mysql -uroot -p

> SHOW REPLICA STATUS\G;

를 입력할 경우 제일 위에 줄인 부분과

Replica_IO_State: Reconnecting after a failed source event read

Last_IO_Errno: 2003

Last_IO_Error: Error reconnecting to source 'repl@db1_ip:3306'. This was attempt 7/86400, with a delay of 60 seconds between attempts. Message: Can't connect to MySQL server on 'db1_ip:3306' (111)

가 뜨게 됩니다. db1의 mysqld를 중단 했기 때문에 해당 서버와 통신이 끊겼다는 것을 의미하며

db2를 마스터 서버로 승격시켜 이를 해결하겠습니다.

> STOP REPLICA;

> SET GLOBAL super_read_only=OFF;

> SET GLOBAL read_only=OFF;

빠른 장애 대응과 추후 복구할 db1을 다시 마스터 서버로 사용하기 위해

/etc/my.cnf를 수정하는 대신 SQL 내부에서 해당 명령어를 실행해 레플리케이션 중단합니다.

> SHOW REPLICA STATUS\G

명령어를 통해 레플리케이션 상태를 확인해보면

Replicate IO가 발생하고 있지 않은 것을 확인할 수 있습니다.

이후 db3에서

> STOP REPLICA;

> RESET REPLICA ALL;

> CHANGE REPLICATION SOURCE TO

> SOURCE_HOST='db2_ip',

> SOURCE_PORT=3306,

> SOURCE_USER='repl',

> SOURCE_PASSWORD='비밀번호',

> SOURCE_AUTO_POSITION=1;

를 통해 복제를 중단하고 이전에 설정한 레플리케이션 설정을 초기화한 후

새롭게 db2와 연결을하기 위한 설정을 진행합니다.

> START REPLICA;

> SHOW REPLICA STATUS\G

서버 ip는 db2로 변경되어서 올라온 점을 확인할 수 있으며, Replica_IO도 정상적으로 이루어지는 것을 확인할 수 있습니다.

db2에서 새로운 데이터 베이스를 생성하고 이후 테이블을 작성하여 정상적으로 db3와 연결이 되었는지 테스트하겠습니다.

> CREATE DATABASE db2_test_db;

> USE db2_test_db;

> CREATE TABLE t1 (

id INT PRIMARY KEY AUTO_INCREMENT,

msg VARCHAR(100),

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);

> INSERT INTO t1 (msg) VALUES ('db2 master write test');

> SELECT * FROM t1;

정상적으로 데이터 베이스 및 테이블이 작성되었으며,

db3에서도 정상적으로 읽히는 것을 확인할 수 있습니다.

───

7) 후속 검증: XtraBackup 설치

# dnf -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# percona-release enable-only tools release
# dnf clean all && sudo dnf makecache
# dnf -y install percona-xtrabackup-80
# xtrabackup --version

* 버전은 mysql 8.0 버전에서 사용 가능한 방법이며 버전 확인이 필수적입니다.

───

8) 후속 검증: 백업/복구

8-1) db1에서 백업 계정 생성

> CREATE USER 'backup'@'localhost' IDENTIFIED BY '비밀번호';

> GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup'@'localhost';

> FLUSH PRIVILEGES;

운용 편의성을 위해 리플리케이션 유저와 백업 유저를 구분해서 사용할 수 있도록 설정하였습니다.

8-2) db1에서 풀백업

# mkdir -p /backup/mysql/full_날짜시간
# BACKUP_DIR=/backup/mysql/full_날짜시간
# xtrabackup --backup --target-dir=$BACKUP_DIR --user=backup --password='비밀번호'
# xtrabackup --prepare --target-dir=$BACKUP_DIR

파일이 정상적으로 생성 되었는지 확인 후에 복원을 진행합니다.

8-3) db2 또는 db3에서 복원 리허설

* db1에서 실행

# scp -r /backup/mysql/full_날짜시간 root@db2ip:/backup/mysql/

db1에서 db2로 백업한 파일을 원격으로 보내줍니다.

* db2에서 복원 전 사전 준비

# RESTORE_DIR=/backup/mysql/full_날짜시간

변수를 지정해 주고

db2 데이터 디렉토리 교체 후 복원 작업을 진행합니다.

# systemctl stop mysqld
# mv /var/lib/mysql /var/lib/mysql.bak_날짜시간

기존 디렉토리를 다른 곳으로 옮겨주고

# mkdir -p /var/lib/mysql

새로운 기본 디렉토리를 생성해 줍니다.

# xtrabackup --copy-back --target-dir=$RESTORE_DIR
# chown -R mysql:mysql /var/lib/mysql

디렉토리 복구를 진행한 다음 소유자 변경을 진행해 줍니다.

# systemctl start mysqld

다시 mysql 서비스를 실행해준 후 다음 복원이 정상적으로 이루어졌는지 확인합니다.

복원 확인:

> SHOW DATABASES;

repl_test 데이터 베이스가 정상적으로 생성되었는지 확인되면 백업 및 복구가 정상적으로 이루어졌습니다.