Database

[MariaDB] Replication 적용기 - 3 (반동기 복제: semi-sync)

KAispread 2024. 1. 15. 21:21
728x90
반응형

개요

이전 실습을 통해 Replication을 적용해 보았다. 이를 통해 읽기 작업과 쓰기 작업의 부하를 분산할 수 있었고 추가적으로 데이터 분산, 분석 및 백업에 이점이 있다는 사실을 알 수 있었다. 하지만 Replication을 통해 읽기/쓰기 부하를 분산하는 방식에는 치명적인 단점이 있다. 바로 데이터의 정합성 문제가 발생할 수 있다는 점이다.

Master 서버의 변경 사항이 Replica 서버 스토리지 엔진을 통해 동기화되기 전에 Replica 서버에 읽기 작업이 발생한다면, 복제되기 이전의 데이터 셋을 참조하여 정합성 문제가 발생할 수 있다. MariaDB의 경우 기본적으로 비동기 복제 방식을 사용하는데 이 방식은 Replica 서버에 이벤트가 전달되었음을 전혀 신경쓰지 않는 방식이기 때문에 이러한 문제 발생 가능성이 더 크다.

이에 대한 대안으로 반동기 복제(semi-synchronous)를 적용하는 방법이 있다. 반동기 복제는 비동기 복제와 다르게 Master 서버의 트랜잭션 처리 중, 최소 한 대 이상의 Replica 서버에서 이벤트가 적재되었음을 알리는 응답을 'ACK' 받고 커밋을 수행한다. 따라서, 비동기 복제 방식보다 정합성 측면에서는 유리하지만 쓰기 성능에선 불리하다.

MariaDB 10.3 이하 버전에서는 반동기 복제를 적용하기 위해 별도의 플러그인 설치가 필요했는데, MairaDB 10.3.3 버전부터는 MariaDB 서버에 반동기 복제가 내장되기 때문에 별도의 플러그인 설치 없이도 반동기 복제를 적용할 수 있다.

 

MariaDB 공식문서에 반동기 복제 적용 방법에 대해 매우 잘 나와있으니 이해가 안되는 부분이 있다면 확인해 보자.

 

Semisynchronous Replication

Semisynchronous replication.

mariadb.com

 

 

비동기 복제

비동기 복제 (Async Replication)

비동기 복제는 다음과 같이 동작한다.

  1. [Master 서버] 스토리지 엔진에서 트랜잭션 준비
  2. [Master 서버] 트랜잭션을 Binary Log에 동기화
  3. [Replica 서버] I/O receiver thread 가 Master 서버의 Binary Log Dump Thread 에 Binary Log 파일 요청
  4. [Master 서버] Binary Log Dump Thread 에서 비동기로 Replica 서버의 I/O receiver Thread에 Binary Log 전송
  5. [Replica 서버] I/O Thread 가 Relay Log를 기록하고 SQL applier Thread 는 변경 내용을 적용함

비동기 복제 방식에서 중요한 점은, Master 서버에서 Replica 서버의 이벤트 적용 성공/실패 여부를 신경 쓰지 않는다는 점이다. Binary Log Dump Thread는 Replica 서버에 이벤트를 전송하고 별도의 응답을 기다리지 않는다. 따라서 Replica 서버 입장에서는 COMMIT 직후 Master 서버에 장애가 발생하더라도 이를 알지 못하게 된다.

Replication 여부와 관계없이 작업을 처리하기 때문에 빠른 성능을 보장하지만 변경된 이벤트가 Replica 서버의 Relay Log에 기록되지 않을 수 있기 때문에 상대적으로 데이터 정합성 측면에서 불리한 방식이다.

 

 

반동기 복제

반동기 복제 (Semi-sync Replication)

반동기 복제는 복제 이벤트가 Replica 서버의 Relay Log에 쓰인 이후 응답을 반환하는 방식이다. Relay Log에 이벤트가 쓰여졌다는 것을 보장하는 것이지 동기화가 완료되었다는 뜻은 아니다.

  1. [Master 서버] 스토리지 엔진에서 트랜잭션 준비
  2. [Master 서버] 트랜잭션을 Binary Log에 동기화
  3. [Master 서버] Binary Log Dump Thread  Replica 서버의 I/O receiver Thread에 Binary Log 전송
  4. [Replica 서버]  I/O receiver Thread 가 Binary Log를 읽고 Relay Log에 변경 이벤트를 기록함.
  5. [Replica 서버] Relay Log에 이벤트를 작성했다는 의미의 ACK 응답을 보냄
  6. [Master 서버] Master 서버는 ACK을 수신한 뒤 Engine Commit 수행
  7. [Replica 서버] I/O Thread 가 Relay Log를 기록하고 SQL applier Thread 는 변경 내용을 적용함

반동기 복제 방식에서는 비동기 복제 방식과 다르게 Binary Log가 Replica 서버에 전송되고 Relay Log에 쓰여진 이후 Engine Commit을 수행한다. Replica 서버 Relay Log에 변경 이벤트 동기화를 보장하지만 실제 Storage Engine으로부터 Data File이 동기화된 것은 아니다. 따라서, 데이터 정합성 문제가 발생할 가능성은 있지만 그 확률이 비동기 복제 방식보다는 낮다.

Semi-sync 방식에서는 2가지 모드를 지원하는데, AFTER_COMMIT 모드는 Engine Commit 이 발생한 이후 Binary Log 를 Replica 서버에 보낸다. 앞서 설명한 방식은 AFTER_SYNC 방식이다.

 

 

실습 환경

  • Ubuntu 22.04
  • MariaDB 10.6.12

 

 

[🚀 Master 서버] 반동기 복제 활성화

SET GLOBAL 명령을 통해 반동기 복제를 활성화할 수 있다.

SET GLOBAL rpl_semi_sync_master_enabled=ON;

 

다만 SET GLOBAL 명령은 서버를 재부팅하면 다시 설정해주어야 하므로 다음과 같이 설정 파일에 값을 추가하자.

# MariaDB 설정 파일 열기
sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf

# 파일에 다음과 같이 설정 값 추가
[mariadb]
...
rpl_semi_sync_master_enabled=ON

 

 

다음의 명령으로 설정 값이 잘 적용되었는지 확인할 수 있다.

rpl_semi_sync_master_enabledON이면 반동기 복제가 활성화된 것이다.

SHOW VARIABLES LIKE '%semi_sync_master%';

+------------------------------------+--------------+
| Variable_name                      | Value        |
+------------------------------------+--------------+
| rpl_semi_sync_master_enabled       | ON           |
| rpl_semi_sync_master_timeout       | 10000        |
| rpl_semi_sync_master_trace_level   | 32           |
| rpl_semi_sync_master_wait_no_slave | ON           |
| rpl_semi_sync_master_wait_point    | AFTER_COMMIT |
+------------------------------------+--------------+
5 rows in set (0.001 sec)

 

 

 

[🚀 Replica 서버] 반동기 복제 활성화

Replica 서버도 설정 방법은 동일하다. 중간에 master 단어가 slave로 바뀐 것에 유의하자.

SET GLOBAL rpl_semi_sync_slave_enabled=ON;

 

# MariaDB 설정 파일 열기
sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf

# 파일에 다음과 같이 설정 값 추가
[mariadb]
...
rpl_semi_sync_slave_enabled=ON

 

Replica 서버에서 반동기 - 비동기 전환 시 I/O Thread가 이미 동작하고 있는 상태라면 I/O Thread를 재시작해주어야 한다. 그렇지 않으면 이전 세팅으로 복제가 수행된다.

STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;

 

 

⏱️ Timeout 설정

반동기 복제 방식에서는 이벤트를 Relay Log에 기록하고 Flush 한 이후에 Replica 서버가 Master 서버로 ACK 응답을 반환한다. 만약, Replica 서버가 ACK 응답을 지정된 시간 안에 주지 않으면 Timeout이 발생하고 Master 서버의 복제 방식은 비동기로 자동 전환된다.

이러한 변경 내역은 Master 서버의 Error Log에 다음과 같이 쓰인다.

[Warning] Timeout waiting for reply of binlog (file: mariadb-1-bin.000002, pos: 538), semi-sync up to file , position 0.
[Note] Semi-sync replication switched OFF.

이후, 하나 이상의 Replica 서버에서 반동기 복제가 완료되면 Master 서버에서 반동기 복제가 다시 활성화된다.

 

Master서버의 반동기 복제 Timeout 시간은 다음과 같이 변경할 수 있다.

SET GLOBAL rpl_semi_sync_master_timeout=20000;
# MariaDB 설정 파일 열기
sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf

# 파일에 다음과 같이 설정 값 추가
[mariadb]
...
rpl_semi_sync_master_timeout=20000

 

실습을 통해 확인해 보자

Timeout을 통해 자동으로 비동기 - 반동기로 전환되는지 확인해 보기 위해 Error Log를 활성화해 보았다.

# mariadb 설정 파일을 연다.
vi /etc/mysql/mariadb.conf.d/50-server.cnf

# 아래의 값이 없거나 주석 되어있으면 1로 설정한다.(ON)
[mysqld]
....
general_log = 1
log_error = /var/log/mysql/error.log

# error log 파일 생성
touch /var/log/mysql/error.log

# mysql에게 소유권을 부여한다.
chown mysql:mysql /var/log/mysql/error.log

# mariadb 서버를 재시작 한다.
systemctl restart mariadb

 

Master 서버의 time out 시간을 1로 설정하고 Master 서버에서 간단한 INSERT 쿼리를 날려보았다. 

SET GLOBAL rpl_semi_sync_master_timeout=1;

 

공식문서에 의하면 timeout 시간이 1이기 때문에 Binary Log를 전달한 이후 Timeout 이 발생하고 Master 서버의 복제 방식이 전환되었을 것이다. 이를 확인하기 위해 Error Log를 확인해 보았다.

# error log를 확인하자.
cat /var/log/mysql/error.log

 

로그 파일을 확인해 보니 Timeout이 발생했고 Semi-sync replicationSwitch-OFF 된 것을 볼 수 있다. Replica 서버에서 이벤트가 Relay Log에 기록된 이후 다시 Semi-sync replicationSwitch-ON 된 것까지 확인할 수 있었다.

 

 

⌛️ Wait Point 설정

반동기 복제 방식에서 Master 서버가 Replica 서버의 ACK 응답을 기다리는 2가지 방법이 있다. 

  • AFTER_SYNC
  • AFTER_COMMIT

이 두 가지 방법은 각각 장단점이 존재한다. 이 옵션을 지정하는 방법은 다음과 같다.

# AFTER_SYNC 적용
SET GLOBAL rpl_semi_sync_master_wait_point='AFTER_SYNC';

# 확인
SHOW VARIABLES LIKE '%semi_sync_master_wait_point%';
+---------------------------------+------------+
| Variable_name                   | Value      |
+---------------------------------+------------+
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+---------------------------------+------------+
1 row in set (0.001 sec)
# MariaDB 설정 파일 열기
sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf

# 파일에 다음과 같이 설정 값 추가
[mariadb]
...
rpl_semi_sync_master_wait_point=AFTER_SYNC

 

Wait Point를 변경하는 방법은 위와 같이 간단하다. Wait Point 설정에 따라 반동기 복제 동작 방식이 약간씩 변경된다. 우선 AFTER_SYNC로 설정했을 때 어떻게 동작하는지 살펴보자.

[AFTER_SYNC]

  1. Master 서버 스토리지 엔진에서 트랜잭션을 준비합니다.
  2. 트랜잭션을 Binary Log에 동기화합니다.
  3. Replica 서버의 확인을 기다립니다.
  4. Replica 서버의 Relay Log에 이벤트가 기록되고 ACK 응답을 수신합니다.
  5. Master 서버 스토리지 엔진에 트랜잭션을 커밋합니다.
  6. 클라이언트에게 응답을 반환합니다.

AFTER_SYNC는 Replica 서버로부터 ACK 응답이 올 때까지 대기한 이후 트랜잭션을 커밋한다.

AFTER_SYNC를 적용할 경우, Replica 서버에 이벤트가 쓰이고 트랜잭션이 커밋되기때문에 모든 클라이언트는 같은 시간에 동일한 데이터를 볼 수 있다. 하지만, 이 방식은 Master 서버에 장애 발생시 failover 시 데이터 손실이 발생하면 안된다. 모든 트랜잭션은 Replica 서버에 이벤트가 쓰여지고 커밋되기 때문이다.

 

[AFTER_COMMIT]

  1. Master 서버 스토리지 엔진에서 트랜잭션을 준비합니다.
  2. 트랜잭션을 Binary Log에 동기화합니다.
  3. Master 서버 스토리지 엔진에 트랜잭션을 커밋합니다.
  4. Replica 서버의 확인을 기다립니다.
  5. Replica 서버의 Relay Log에 이벤트가 기록되고 ACK 응답을 수신합니다.
  6. 클라이언트에게 응답을 반환합니다.

AFTER_COMMIT은 트랜잭션 커밋 이후 ACK 응답이 올 때까지 대기하는 방식이다.

AFTER_COMMIT을 적용할 경우, 다른 클라이언트들은 트랜잭션을 커밋하고 있는 클라이언트보다 먼저 커밋된 트랜잭션을 볼 수 있다. 또한, failover시 데이터 손실이 발생할 수 있는데 트랜잭션이 먼저 커밋되기 때문에 Replica에 이벤트가 쓰이지 않은 상태일 수 있기 때문이다.

 

728x90
반응형