MySQL Replication(복제) 구성 및 설정 - Async - Semi Async

Last Updated on 2월 15, 2021 by 태랑(정현호)

복제를 사용하여 부하분산및 고가용성 확보


리플리케이션(Replication)은 DB의 내용을 복제하여 사용하는 의미 하며 복제 대상인 Master 가 1개 또는 다수의 Slave(Standby) 가 복제를 하여 사용하는 것을 의미 합니다.
* DBMS에 따라 Primary Standby 등의 표현이 있습니다.

장애를 대비하기 위한 고가용성 측면과 ReadWrite Query 와 ReadOnly 쿼리를 구분하여 수행하여 DB의 부하분산, 백업 수행 등의 목적으로 사용 합니다.



Mysql의 Replication 방식


첫번째는 먼저 Async Replication 입니다.
Mysql 은 기본적으로 예전부터 사용한 Async Replication 을 사용 하게 됩니다.
Binary Log 에는 Mysql의 모든 변경 사항이 기록이 되고 Slave DB에서는 이 Binary Log(이하 binlog) 를 이용 하여 Replication 이 수행됩니다.

참고) Oracle에서는 이런 역활을 RedoLog 와 ArchiveLog file이 수행하고 Mysql의 InnoDB의 Redo와 Orace의 Redo의 씌임세에 차이가 있습니다.
InnoDB의 Buffer내 Dirty Page를 Disk로 flush 하기전에 Redo log buffer에서 Redo Log File로 먼저 기록 되게 되고
그후에 체크포인트가 발생되면 dirty page를 disk로 flush 하게 됩니다.
그래서 Mysql 인스턴스가 crash가 발생하였을때 재기동을 하면서 Instance Recovery 시 Redo 와 Undo정보를 토대로 Roll-back과 Roll-forward가 수행됩니다




<Mysql Async Replication>


다시 돌아와서 Async Replication 방식은 Master 서버에서 Binary log dump thread 가 Slave를 위해 가동되며 Slave 의 I/O Thread 와 Master Thread가 연결되어 Slave DB의 I/O Thread 요청에 의해 Master 의 Dump Thread가 binlog을 읽어서 slave에 전달하게 됩니다.

Slave 측 I/O Thread는 Master DB로 부터 전달 받은 로그를 자신의(slave) Relay Log에 복제를 합니다 
그리고 Slave의 SQL Thread는 Relay Log 을 읽어서 다시 Slave에 실행(반영)하여 데이터를 복제 하게 됩니다.

추가적으로 slave에서 log_slave_updates 파라미터가 활성화(ON) 하게 되면 자신의 Binlog 에도 기록 하게 됩니다.
이렇게 되면 A->B->C 형태로 중간의 B 인 Slave 서버가 C의 Master 역할도 수행할 수 있게 됩니다.

이렇게 replication 되는 과정에서 async 방식으로 동작하기 때문에 Master 에서는 Slave의 복제 여부 등을 확인 하지 않고 Master 서버 중인 트랜잭션을 종료 및 결과 반환 등을 하게 됩니다.

그래서 변경량이나 Slave의 부하 정도, 시스템 사용률 , 네트워크 속도 등 여러가지 이유로 Slave에 replication 이 늦어질수도 있고 그에 따라 조회시점에 데이터가 차이가 발생될 수도 있습니다.

Master DB의 문제로 인하여 복제가 완료되지 않은 트랜잭션은 손실이 될수도 있긴 합니다.
slave 의 DB는 문제 발생 이후 제가동 되면서 복제가 중지된 Log Pos 이후 부터 따라가면서 다시 복제가

수행되기 때문에 Slave DB의 장애는 큰 영향을 주지는 않습니다.

Mysq Replication에서는 Master / Slave 간의 Gap을 줄이는게 중요하고 여담으로 AWS의 Aurora Cluster가 일반적인 Replication 방식이 아닌 자체 구현한 방식을 통해 사용하는데 이 방식을 사용하면 일반적인 Replication에 비해 더 빠르게 적용 된다고 합니다




두번째로 Semi-sync Replication
Mysql 5.5 버전에서 도입된 Semi-sync Replication 방식은 Master DB에서 Slave 로 전달된 Relay log의 기록이 완료 되었다는 메세지(신호)를 받고나서 처리중인 transaction의 결과를 요청한 application(client)에 결과를 반환해주는 방식 입니다.



<Mysql Async Replication>

Async 방식에 비하면 성능이 조금 저하되긴 하지만 완전한 sync(slave에서 relay log 내용까지 적용되는) 방식보다는 성능 저하가 덜 하고
Slave 측까지는 일단 변경이력이 전달 되었기 때문에 Master와 slave 사이의 데이터에 대한 동기화 나 안전성 측면에서 async 방식에 비해 더욱 보장해줄 수 있습니다.

Semi-sync Replication 은 전달 시기에 따라서 after_commit(ver 5.5) 과 after_sync(ver 5.7) 방식으로 나뉘게 됩니다.

Semi-sync Replication은 다음 포스트에서 다시 기재 하도록 하겠습니다.



binlog 방식


Binary log는 DDL 과 DML 같이 데이터베이스 내에서 발생하는 변경 내역들이 저장되는 로그 파일 입니다.

이런 binlog 파일에 대해서 format을 설정 할 수 있습니다.

binlog_format = row | mixed | statement
3 종류가 있습니다


statement : 전통적으로 사용하던 방식으로 실행된 쿼리 구문 그대로 Binlog에 남겨지는 방식 입니다.


row : 생성/변경된 데이터의 Before/After row image가 binlog에 저장하여, 사이즈가 statement보다 크게 생성 됩니다.

*5.1 버전에서 도입 되었으며  5.7.7 버전부터 default value가 되었습니다.

mixed : row와 statement 중간 형태로 날짜와 같이 determine이 필요한 경우 row형태로 저장되는 형식 입니다.


binlog_format 을 row 로 사용하는 경우 연계되어 사용할수 있는 파라미터로 binlog_row_image 이 있습니다.

row 방식으로 binlog 를 기록 할 때 로깅할 컬럼 set을 설정 할 수 있습니다.
binlog_row_image = FULL | MINIMAL | NOBLOB

full : 변경 전/후 이미지 전체를 binlog에 기록 (Default)
minimal : 최소한의 값만 로깅,변경된 행을 식별하는 데 필요한 이전 이미지의 열만 기록
noblob : Blob,text와 같이 사이즈가 큰 값을 제외하고 기록(로깅)


현재 테스트 환경은 mysql 5.7.31(Source Compile) 이기 때문에 binlog_format=row , binlog_row_image=full 이 default 로 사용되게 됩니다




Master DB 설정 변경 및 replication 유저 생성


# /etc/my.cnf 파일에 아래 와 같이 내용을 추가/변경 합니다.

[root]# vi /etc/my.cnf


[mysqld]
server-id=1
     -> server-id는 master와 slave가 달라야 합니다
### Replication
log-bin=/usr/local/mysql/logs/binlog
     -> Binlog의 파일명을 기재 합니다.
sync_binlog=1
binlog_cache_size=2M
max_binlog_size=512M
expire_logs_days=7
log-bin-trust-function-creators=1

파일을 저장한 후 mysql을 재기동하여 binlog 를 활성화 합니다
[root]# systemic restart mysqld


* 상황에 따라 파라미터는 추가/변경 하여 사용 하시면 됩니다.


Mysql 기동 후 binlog 활성화 여부는 show variables 로 확인 가능 합니다.
show variables like '%log_bin%';

show variables 로 확인되는 log_bin 값과 my.cnf 에 설정한 log_bin 은 다른 내용이 입니다.
show variables 의 log_bin 은 현재 binlog의 활성화 유무만 보여주는 변수이고
my.cnf 에 기술되는 log_bin은 binlog를 활성화 시키면서 경로까지 지정해주는 파라미터 입니다.



# replication 계정 생성

[root]# mysql --login-path=dba

--login-path 관련해서는 아래 내용을 참고하시면 됩니다.


mysql> create user 'repl_user'@'%' identified by '패스워드';
mysql> grant replication slave on *.* to 'repl_user'@'%';



slave 파라미터 설정


slave 서버의 my.cnf 파일을 아래와 같이 추가/수정 합니다.
[root]# vi /etc/my.cnf

[mysqld]
server-id=2
   -> master 서버에서의 id 와 달라야 합니다.
#Slave Replication Option
report-host=acs2
   -> master 에서 status 조회시 사용
relay-log=/usr/local/mysql/logs/relay_log
relay_log_purge=true
expire_logs_days=7
log_slave_updates=ON

read_only


"report-host=호스트명" 은 master 서버에서 show slave hosts 명령어 수행시 host 정보를 확인 할 수 있게 해주는 파라미터 입니다.

= 파라미터 미설정시 
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 2 | [공란] | 3306 | 1 | 8687edf5-c2b7-11ea-bc27-080027a227aa |
+-----------+------+------+-----------+--------------------------------------+

= 파라미터 설정시
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 2 | acs2 | 3306 | 1 | 8687edf5-c2b7-11ea-bc27-080027a227aa |
+-----------+------+------+-----------+--------------------------------------+

log_slave_updates 는 slave에도 binlog를 기록할지를 결정 하는 파라미터로 default는 비활성화 입니다(0)
활성화 해서 사용하시려면 1로 지정하고 시작 하시면 됩니다.



master 데이터 추출 및 적재


# mysqldump 데이터 추출 (Master)
[root]# mysqldump --login-path=dba --opt --single-transaction \
--hex-blob --master-data=2 --routines --triggers \
--all-databases | gzip > master_data.sql.gz

추출 된 master_data.sql.gz 파일을 slave 서버로 전송 합니다.


# 데이터를 입력 합니다(slave)
[root]# gunzip master_data.sql.gz
[root]# mysql --login-path=dba < master_data.sql



replication 설정 및 시작


SQL 파일 상단에서 binlog 파일명과 log position을 확인 합니다.


[root]# more master_data.sql

파일에서 아래부분을 참조
CHANGE MASTER TO MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=154


# master 서버 정보 입력 (slave 에서 실행)
[root] mysql --login-path=dba

mysql> change master to
master_host='acs',
   -> Master 서버의 호스트명이나 ip

master_port=3306,
   -> Master 서버의 포트번호

master_user='repl_user',
   -> replication 계정명

master_password='패스워드',
     -> replication 계정 비밀번호

master_log_file='binlog.000001',
    -> 위에서 확인한 binlog 파일명

master_log_pos=154;
   -> 위에서 확인한 log position 번호




# replication 시작
mysql> start slave;


# slave 상태 조회 
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: acs
Master_User: repl_user
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: binlog.000001
Read_Master_Log_Pos: 154
Relay_Log_File: relay_log.000002
Relay_Log_Pos: 317
Relay_Master_Log_File: binlog.000001
Slave_IO_Running: Yes  <-- Slave에서 기동되는 Thread가 정상 기동중임
Slave_SQL_Running: Yes <-- Slave에서 기동되는 Thread가 정상 기동중임
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 154
Relay_Log_Space: 518
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0  <-- Master 와의 Gap 정보
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 12416d15-0bfa-11eb-ad17-080027d4f8ed
Master_Info_File: /usr/local/mysql/data/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates  
      <-- 동기화가 완료되어 추가 변경 event를 기다리는 중

Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)



# replication 중지(stop)

mysql> stop slave;
를 통해서 replication 을 중지 할 수 있습니다
start slave 하면 다시 재개 됩니다.

stop 후 show slave status\G 로 조회해보면 2개의 thread 가 No 로 확인 됩니다
Slave_IO_Running: No 
Slave_SQL_Running: No 



# replication 마스터 정보 삭제
mysql> stop slave;
mysq> reset slave all;





replication master 정보


Note (Code 1759): Sending passwords in plain text without SSL/TLS is extremely insecure.
Note (Code 1760): Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended.
Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.

테스트 환경에서는 change master 수행시 2가지 warning 이 발생되는데 SSL 미사용에 따른 메세지와 replication 유저의 정보가 평문으로 저장됨으로 주의하고, start slave 명령어를 이용하라는 메세지 입니다.
ssl은 제외 하고 두번째 메세지에 대해서 더 확인 해보면


Master 정보가 포함된 파일을 열어보면 아래와 같이 평문으로 내용이 확인 되고 그에 따라 계정정보 또한 확인이 되게 됩니다.

[root]# cat /usr/local/mysql/data/master.info
25
binlog.000001
154
acs
repl_user  <-- ID
repl_user  <-- Password
3306
60
0

이와 같이 사용하는 것은 보편적인 방법이고 이렇게 평문등으로 남기 때문에 replication 권한만 부여 된 유저를 생성하여 사용 하는 것이기도 합니다.

warning 메세지에 나온 내용대로 start slave 명령어 를 활용 할 수도 있습니다.

start slave 으로 사용하려면 change master 명령어시 ID/PW 정보는 입력하지 않습니다.
mysql> change master to
master_host='acs',
master_port=3306,
master_log_file='binlog.000001',
master_log_pos=154;


= start slave 시 계정정보를 입력 합니다.
mysql> START SLAVE user='repl_user' password='repl_user';

이렇게 수행 후 다시 master.info 파일을 살펴보면 아래와 같이 계정정보는 제외되고 저장된 것을 확인 할 수 있습니다.

[root]# cat /usr/local/mysql/data/master.info
25
binlog.000001
154
acs


3306
60
0

0
30.000

0
12416d15-0bfa-11eb-ad17-080027d4f8ed
86400


0


 

slave restart


slave 는 재시작시 자동으로 replication이 시작 됩니다.
관련해서는 skip-slave-start 파라미터가 있으며 Mysql 기동 시 slave replication 이 자동으로 시작되는 것을 막기 위한 설정입니다
파라미터가 설정되어 있으면 mysql 기동 후 명시적으로 start slave; 를 해야 합니다.


위에서 설명한 START SLAVE 구문에 계정정보를 입력하여 replication 사용시, Slave DB가 재가동 되었을때 default 설정으로 replication이 가동되지만 master.info 파일에 계정 정보가 없어서 replication 이 즉시 수행되지 못한다는 단점이 있습니다.


Last_IO_Error: Fatal error: Invalid (empty) username when attempting to connect to the master server. Connection attempt terminated.

show slave status\G 로 조회시 위와 같은 상태 메세지가 확인 되며 사용자가 명시적으로 "start slave 계정정보" 명령어를 수행해야 replication 이 진행됩니다.
START SLAVE user='repl_user' password='repl_user';

즉 slave db 재가동시 사용자가 start slave 를 챙겨줘야 하는 단점 있습니다.
이런 부분도 확인이나 고려가 되어야 할 것 입니다.
 

 

상태,정보 확인 및 모니터 명령어


# mastser
mysql> show master status;
mysql> show slave hosts;


# slave 
mysql> show slave status\G



Master DB 에서 데이터 추가나 변경 등을 발생시켜서 데이터 동기화가 정상적으로 이루어지는지 추가로 테스트를 진행 하시면 되겠습니다.



이어지는 글 :  Mysql Replication 설정 - Semi Async - after_sync - after_commit

 

답글 남기기