[MySQL][Replication] Semi Sync 기능과 설정방법

세미싱크 소개

일반적으로 MySQL에서 복제라 얘기하면 Master - Slave(Replica)구조의 복제방식입니다. 그리고 복제방식은 특별한 설정을 하지 않는다면 비동기 방식입니다.

동기 방식은 크게 반동기(세미싱크) 방식과 비동기 방식 2가지가 있습니다. 이걸 구분하는 방법은 슬레이브 바이너리 로그에 DML 적용되었는지 여부를 판단하느냐 않하느야에 달려 있습니다.

먼저 비동기 방식에 대해 알아보겠습니다.

비동기 방식은 마스터에서 DML 발생하면 바이너리 로그에 DML 작성하고 바이너리 로그를 슬레이브로 보냅니다. 이때 비동기 방식은 바이너리 로그가 슬레이브 로그에 적용되었는지 여부에 관련없이 무조건 자신의 DML 수행합니다. 방식은 마스터에서의 수행 여부만 판단하기 때문에 속도가 빠릅니다. 대신 슬레이브에 지연이 발생할 있으며 지연이 발생하는 만큼 슬레이브에 데이터를 조회하게 되면 마스터와 데이터와 맞지 않게 됩니다. 여기에서 알수 있듯이 비동기 방식은 내부적으로 문제가 있습니다. 보통 Master - Slave(Replica)구조로 되어 있을때 Master 장애가 발생한다면 슬레이브의 서버를 마스터로 Role Change 진행하게 됩니다. 이때 마스터에만 적용되어 있는 로그가 슬레이브로 전달되지 않은채 마스터 서버가 죽어버린다면 이는 데이터 일관성에 심각한 문제를 초래하게 됩니다. 그렇다고 마스터 서버를 복구 시도를 하게 되면 그만큼 서비스 중단이 되게 됩니다. 속도가 빠르다는 장점과 장애시 데이터 유실이 크게 있는 단점을 가지게 됩니다.

문제를 보완하고자 만든것이 세미 싱크입니다. 세미싱크 복제는 마스터 서버가 슬레이브 서버에 기록되는 릴레이 로그에 로그 기록이 완료되었다는 응답을 받으면 다음 트랜잭션을 수행하는 방법입니다. 마스터 혼자 수행되는게 아니라 슬레이브의 적용여부까지 확인하는 방법입니다. 비동기 복제 방식에 비해 성능저하가 발생하지만 마스터 - 슬레이브 복제 동기화가 그만큼 많이 이루어진다는 뜻이기도 합니다. 그리고 장애 발생시 동기화가 많이 이루어져 있기 때문에 복구에도 좀더 쉽게 복구가 가능하다는 장점이 있습니다.

 

세미싱크 아키텍쳐

마스터와와 슬레이브 간의 세미싱크 복제는 다음과 같이 작동합니다.

- 슬레이브는 마스터에 연결할 세미싱크 가능 여부를 확인합니다.

- 마스터에서 세미싱크 복제가 활성화되고 세미싱크 복제본이 하나 이상 있는 경우, 마스터에서 트랜잭션 커밋을 수행하는 스레드가 차단되고 최소한 하나의 세미싱크 복제본이 트랜잭션에 대한 모든 이벤트를 수신했음을 확인할 때까지 대기합니다. 이때 일정시간이 지나면 타임아웃이 발생합니다.

- 슬레이브는 이벤트가 릴레이 로그에 기록되고 디스크에 플러시된 후에만 트랜잭션 이벤트 수신을 확인합니다.

- 트랜잭션을 승인한 복제본 없이 시간 초과가 발생하면 소스는 비동기식 복제로 되돌아갑니다. 하나 이상의 세미싱크 복제본이 따라잡으면 마스터가 세미싱크 복제로 돌아갑니다.

- 세미싱크 복제는 마스터 슬레이브 모두에서 활성화되어야 합니다. 마스터에서 세미싱크 복제가 비활성화되었거나 마스터에서 활성화되었지만 슬레이브가 없는 경우 마스터는 비동기식 복제를 사용합니다.

 

세미싱크는 크게 2가지 방식이 있습니다. AFTER_SYNC AFTER_COMMIT방식입니다. 2가지 차이점에 대해 알아보겠습니다.

 

▶︎ AFTER_COMMIT

AFTER_COMMIT 5.5버전부터 도입된 기능입니다.

AFTER_COMMIT 방식은 다음과 같습니다.

트랜잭션 Commit -> 바이너리 로그에 Flush/Commit -> 스토리지 엔진 Commit -> 바이너리 로그 덤프 ACK요청 이벤트를 전송 -> 슬레이브의 릴레이 로그에 작성-> 마스터에 응답 전송 -> 사용자에게 커밋 응답 전송

엔진 커밋 이후 테이블 바이너리 로그를 작성한 로그를 슬레이브로 보냅니다. 그리고 바이너리 로그를 전송하게 되면 릴레이 로그에 적용 바로 마스터에 응답을 보냅니다.

 

트랜잭션을 실행하는 클라이언트는 서버가 스토리지 엔진에 커밋하고 복제본 승인을 받은 후에만 반환 상태를 얻습니다. 커밋 복제본 승인 이전에 다른 클라이언트는 커밋 클라이언트 이전에 커밋된 트랜잭션을 있습니다.

복제본이 트랜잭션을 처리하지 않는 문제가 발생하면 예기치 않은 소스 종료 복제본으로의 장애 조치가 발생하는 경우 이러한 클라이언트가 소스에서 것과 관련된 데이터 손실을 있습니다.

 

▶︎ AFTER_SYNC

 

AFTER_SYNC MySQL 5.7.2 부터 도입된 기능입니다.

트랜잭션 Commit -> 바이너리 로그 Flush/Commit -> 바이너리 로그 덤프 ACK요청 이벤트를 전송 -> 슬레이브 릴레이 로그에 기록 -> 마스터에 응답 전송 -> 스토리지 엔진 커밋 ->  사용자에게 커밋 응답 전송

엔진 커밋 이후 바로 바이너리 로그를 전송합니다. 그리고 릴레이 로그에 적용 바로 마스터에 응답을 보냅니다.

 

모든 클라이언트가 커밋된 트랜잭션을 동시에 있습니다. 이는 복제본에 의해 승인되고 소스의 스토리지 엔진에 커밋된 후입니다. 따라서 모든 클라이언트는 소스에서 동일한 데이터를 봅니다.

소스 오류가 발생하면 소스에서 커밋된 모든 트랜잭션이 복제본으로 복제됩니다(릴레이 로그에 저장됨). 복제본이 최신 상태이므로 소스의 예기치 않은 종료 복제본으로의 장애 조치는 무손실입니다. 위에서 언급했듯이 소스는 장애 조치 후에 재사용해서는 됩니다.

 

 

AFTER_COMMIT AFTER_SYNC와의 가장 차이는 차이는 바이너리 로그를 엔진 커밋 이후 전송 것인지, 바이너리 로그를 플러시/커밋 이후에 전송할 것인지에 대한 차이입니다.

 

 

 

세미싱크에 대한 전략적 사용

▶︎ 일반 복제에서 슬레이브를 2 이상 사용

일반적인 마스터 슬레이브 복제에서 마스터 슬레이브 1:1 구성시 한가지 문제가 있습니다. 바로 슬레이브의 응답 속도입니다. 만약 슬레이브에서 응답이 느리다면 마스터또한 슬레브의 응답을 기다려야 하기 때문에 속도가 느려지게 됩니다. 그런데 슬레이브의 응답이 느린 이유가 여러가지 이유가 있습니다. 네트워크 문제일수도 있고 스토리지 문제일수도 있고 OS문제일수도 있고 MySQL자체의 문제일수도 있습니다.

이럴때 슬레이브를 2대에서 3대이상 사용하면 문제를 회피할 수도 있습니다. 2대이상의 슬레이브에서 한대라도 빠르게 슬레이브에서 응답해 주면 마스터는 모든 슬레이브의 응답을 기다리지 않고 하나의 응답만으로 마스터의 다음 트랜잭션을 처리하게 됩니다. 만약 세미싱크에 의한 복제지연이 자주 일어난다면 슬레이브를 늘려보는것도 하나의 방법입니다.

 

▶︎ MHA(MySQL High Available) 유리

MHA 마스터에 장애가 발생할 MHA Agent에서 마스터의 로그가 가장 많이 적용되어 있는 슬레이브를 이용해서 마스터로 승격 후보로 정하게 됩니다.

그리고 에이전트가 가지고 있는 마스터 로그를 마스터 후보 슬레이브를 확인해서 차이가 나는 구간을 적용 마스터로 승격시키게 됩니다. 그래서 마스터를 승격시키는데 만약 적용해야 로그가 많다면 Failover 하는데 시간이 걸리게 됩니다. 이때 세미싱크가 적용되어 있다면 상당한 효과를 발휘하게 됩니다. 세미싱크는 마스터와 슬레이브의 로그가 대부분 일치하기 때문에 Failover시에도 거의 실시간으로 된다는 장점이 있습니다. 그래서 2개의 조합은 최상의 결과를 얻게 됩니다.

 

 

설정방법

▶︎ 마스터 슬레이브 복제 구성

다음 포스팅을 참고해 마스터 슬레이브 복제 환경을 구성합니다.

일반 마스터 슬레이브 : https://myinfrabox.tistory.com/22

GTID 슬레이브 : https://myinfrabox.tistory.com/30

 

▶︎ 플러그인 설치

세미 싱크는 플러그인 설치를 통해 사용할 있습니다. 마스터와 슬레이브에 모두 관련 플러그인을 설치합니다. 먼저 플러그인 존재 여부를 확인해 봅니다.

mysql> select PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_TYPE, PLUGIN_DESCRIPTION 
    -> from information_schema.plugins
    -> where PLUGIN_NAME LIKE '%semi%';
Empty set (0.00 sec)

 

다음과 같은 명령어를 이용해 플러그인을 설치합니다.

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.05 sec)

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)

 

플러그인 설치 여부를 확인합니다.

mysql> select PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_TYPE, PLUGIN_DESCRIPTION 
    -> from information_schema.plugins
    -> where PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+-------------+-------------------------------------+
| PLUGIN_NAME          | PLUGIN_STATUS | PLUGIN_TYPE | PLUGIN_DESCRIPTION                  |
+----------------------+---------------+-------------+-------------------------------------+
| rpl_semi_sync_master | ACTIVE        | REPLICATION | Semi-synchronous replication master |
| rpl_semi_sync_slave  | ACTIVE        | REPLICATION | Semi-synchronous replication slave  |
+----------------------+---------------+-------------+-------------------------------------+
2 rows in set (0.00 sec)

 

 

▶︎ 세미싱크 활성

다음과 같은 명령을 실행합니다. 명령어를 통해서 세미싱크가 활성화 됩니다.

 

마스터에서 수행

mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)

 

슬레이브에서 수행

mysql> SET GLOBAL rpl_semi_sync_slave_enabled=1;
Query OK, 0 rows affected (0.00 sec)

 

 

▶︎ my.cnf 설정

마스터 설정

[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000

rpl_semi_sync_master_timeout 단위값은 ms입니다. 위의 값은 10초가 됩니다.

 

 

슬레이브 설정

참고로 슬레이브가 여러대 있다면 모두 설정합니다.

[mysqld]
rpl_semi_sync_slave_enabled=1

 

위에서 설치 적용을 해두었지만 만약을 위해 my.cnf에도 설정해 둡니다.

 

 

세미싱크 적용확인 모니터링

▶︎ MySQL 변수 확인

마스터

mysql> SHOW VARIABLES LIKE '%semi%';
+-------------------------------------------+------------+
| 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_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
| rpl_semi_sync_slave_enabled               | OFF        |
| rpl_semi_sync_slave_trace_level           | 32         |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)

 

 

슬레이브

mysql> SHOW VARIABLES LIKE '%semi%';
mysql> SHOW VARIABLES LIKE '%semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.00 sec)

 

▶︎ MySQL 상태 확인

마스터

mysql> show status like '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 0     |
| Rpl_semi_sync_master_no_times              | 0     |
| Rpl_semi_sync_master_no_tx                 | 0     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
| Rpl_semi_sync_slave_status                 | OFF   |
+--------------------------------------------+-------+
15 rows in set (0.00 sec)

 

슬레이브

mysql> show status like '%semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

 

중요 파라미터 설명

▶︎ rpl_semi_sync_master_wait_point

세미싱크 복제에서 마스터가 트랜잭션을 커밋한 클라이언트에 상태를 반환하기 전에 트랜잭션 수신의 슬레이브 적용 확인을 기다리는 지점을 제어합니다. 다음 값이 허용됩니다.

- AFTER_COMMIT: 마스터는 트랜잭션을 바이너리 로그와 슬레이브에 쓰고 바이너리 로그를 동기화하고 트랜잭션을 스토리지 엔진에 커밋합니다. 마스터는 커밋 트랜잭션 수신의 슬레이브 적용 확인을 기다립니다. 적용확인이 되면 마스터는 클라이언트에 결과를 반환하고 계속 진행할 있습니다.

 

- AFTER_SYNC(기본값): 마스터는 트랜잭션을 바이너리 로그와 복제본에 쓰고 바이너리 로그를 디스크에 동기화합니다. 마스터는 동기화 슬레이브에 트랜잭션 적용 여부를 기다립니다. 적용 확인을 받으면 마스터는 트랜잭션을 스토리지 엔진에 커밋하고 결과를 클라이언트에 반환하면 계속 진행할 있습니다.

 

▶︎ rpl_semi_sync_master_timeout

semi sync 사용중에 slave 응답을 기다리는 최대 시간으로 default 10000 ms(10) 입니다. 단위는 ms입니다. 설정시간이 초과되면 세미 싱크 모드에서 비동기 방식으로 바뀌게 됩니다.

 

 

참고사이트

https://dev.mysql.com/doc/refman/5.7/en/replication-semisync-installation.html

 

MySQL :: MySQL 5.7 Reference Manual :: 16.3.9.2 Semisynchronous Replication Installation and Configuration

16.3.9.2 Semisynchronous Replication Installation and Configuration Semisynchronous replication is implemented using plugins, so the plugins must be installed into the server to make them available. After a plugin has been installed, you control it by mea

dev.mysql.com

https://ssup2.github.io/theory_analysis/MySQL_Replication/

https://gywn.net/2017/06/mysql-slave-addition-effect/

 

[MySQL] 슬레이브 하나 더 추가했을 뿐인데.. :-) – gywndi's database

Overview MySQL의 꽃중의 꽃은 역시 비동기 방식의 데이터 복제라고 볼 수 있는데요. 지극히 개인적인 생각이기는 하지만, 슬레이브 노드를 데이터 일관성이 반드시 필요한 상황에서의 READ 스케일아

gywn.net

https://hoing.io/archives/3111

 

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

포스팅은 MySQL에서의 Async Replication(복제)에 대한 내용과 복제 구성에 대한 내용이 기술되어 있습니다.

hoing.io

 

Designed by JB FACTORY