1. MySQL GTID 시작하기
2017.01.14 MySQL PG 세미나
전세웅 (SK Telecom)
『돌고래사육사』 http://seuis398.blog.me
2. MySQL GTID 시작하기
MySQL GTID 개요
1 / 15
mysql-bin.102
mysql-bin.1019d850d65-219f-11e6-b752-08002702c825:1-30
9d850d65-219f-11e6-b752-08002702c825:31-81
DB1 (MASTER)
DB2 (SLAVE) DB3 (SLAVE)
mysql-bin.207
mysql-bin.206
Replication
9d850d65-219f-11e6-b752-08002702c825:1-50
9d850d65-219f-11e6-b752-08002702c825:51-81
Replication
현재 복제 포지션
DB1 mysql-bin.102 , 20352
= 9d850d65-219f-11e6-b752-08002702c825:81
DB2의 복제 포지션으로 전환
9d850d65-219f-11e6-b752-08002702c825:81
= DB2 mysql-bin.207 , 2974
서로 다른 노드의 Binary Log / Position을
mapping 시킬 수 있는 기반 정보를 제공
File Offset = 20352
File Offset = 2974
3. GTID를 이해하기 위한 기본 개념(I)
GTID
• Server UUID + Transaction 순차번호로 구성 (예: 9d850d65-219f-11e6-b752-08002702c825:33)
• Server UUID 값은 SHOW VARIABLES LIKE ‘server_uuid‘로 확인 가능
GTID SET
• GTID의 집합 (예: 9d850d65-219f-11e6-b752-08002702c825:1-33:38-42)
EXECUTED GTID ★
• 초기화 이후 실행된 GTID SET을 의미하며, gtid_executed 시스템 변수에서 확인 가능
• Binary Log를 남기는 Master 입장에서는 자신의 GTID 발급 현황을,
Slave 입장에서는 Master의 트랜잭션이 어디까지 반영되었는지를 의미하기도 함
PURGED GTID
• 실행 후 Binary Log Purge까지 완료된 GTID SET을 의미하며, gtid_purged 시스템 변수에서 확인 가능
• Slave가 gtid_purged 범위의 GTID를 요청하면 해당 요청은 처리 불가
※ gtid_executed, gtid_purged 시스템 변수 값은 DB 재기동 시점에 계산되어 초기화
MySQL GTID 시작하기 2 / 15
4. GTID를 이해하기 위한 기본 개념(I)
mysql-bin.002
mysql-bin.003
mysql-bin.004
mysql-bin.001
Binary Log Purge
9d850d65-219f-11e6-b752-08002702c825:1-30
9d850d65-219f-11e6-b752-08002702c825:31-81
9d850d65-219f-11e6-b752-08002702c825:82-102
9d850d65-219f-11e6-b752-08002702c825:103-114
Purged Gtid
9d850d65-219f-11e6-b752-08002702c825:1-81
Executed Gtid
9d850d65-219f-11e6-b752-08002702c825:1-114
Slave 전파
복제되어 처리되는 트랜잭션에 의해 Slave DB에서도 동일한
Executed GTID 값을 가지게 됨
MySQL GTID 시작하기 3 / 15
5. 주제1. IO Thread와 SQL Thread에게 GTID란?
(1) IO Thread에게 GTID란?
• IO Thread가 초기화(change master) 될 때 Master에서 어떤 Log를 받아와야 될지 판단하는 기준
• “Master의 Executed GTID – 자신의 Executed GTID 영역”을 받아와서 Relay Log에 저장
• Master의 Executed GTID : 9d850d65-219f-11e6-b752-08002702c825:1-102
• 자신의 Executed GTID : 9d850d65-219f-11e6-b752-08002702c825:1-90:96-100
• Relay Log로 가져오게 되는 트랜잭션은 9d850d65-219f-11e6-b752-08002702c825:91-95:101-102
• IO Thread 초기화 이후에는 non-GTID 모드와 동일하게 Binary Log File / Position 기반으로 동작
(2) SQL Thread에게 GTID란?
• SQL Thread는 non-GTID 모드와 동일하게 Relay Log에 저장된 트랜잭션을 순차 처리함
• 다만, GTID 모드에서는 SQL Thread가 실행하는 GTID 트랜잭션의 기록만 추가로 남김 (gtid_executed)
※ GTID는 IO Thread가 초기화 될 때 Master의 Binary Log File/Position을 찾기 위해 사용됨
그리고 필요할 때 쓰기 위해 SQL Thread가 동작할 때 실행된 GTID에 대한 기록을 남김
이외의 기본적인 Replication 동작은 GTID나 non-GTID나 동일함
MySQL GTID 시작하기 4 / 15
6. 주제2. log-bin / log-slave-updates 옵션의 사용
(1) 5.6 버전과 5.7 버전의 요구사항이 다르다.
• 5.6 버전까지 GTID를 사용하기 위해서는 복제 그룹의 모든 DB가 log-bin / log-slave-updates 옵션을 사용해야 함
• 누구나 Master가 될 수 있다는 기본적인 GTID 컨셉을 충족하기 위함
• 복제된 트랜잭션이 어디까지 수행되었는지 기록을 해야 하기 때문
• DB 재기동 시점에 Local에 저장된 첫번째, 마지막 Binary Log를 읽어 gtid_purged, gtid_executed 값을 계산
• 5.7 버전부터는 log-bin / log-slave-updates 옵션의 사용은 필수가 아님
• log-bin / log-slave-updates 옵션을 사용하지 않으면 mysql.gtid_executed 테이블에 필요한 정보를 저장
• 단, Master 역할을 부여받을 가능성이 있는 DB는 반드시 log-bin / log-slave-updates 옵션을 켜 두어야 함
MySQL GTID 시작하기 5 / 15
7. 주제2. log-bin / log-slave-updates 옵션의 사용
(2) log-bin / log-slave-updates 옵션 사용시 유의할 점은?
• MySQL 데몬이 재기동 되는 경우 gtid_executed 값은 아래의 정보를 참조하여 초기화 됨
• mysql.gtid_executed 테이블에 저장된 GTID 값 ”binary log switch 시점에 1회 업데이트”
• Local에 남겨진 마지막 binary log의 GTID 값
• Binary Log 저장 안정성(sync_binlog) 확보 실패 혹은 임의 삭제 시 gtid_executed 변수의 잘못된 초기화를 유발
<사례> Slave MySQL 데몬 crash 후 binary log를 유실한 상황
mysql-bin.003
mysql-bin.004
9d850d65-219f-11e6-b752-08002702c825:82-102
9d850d65-219f-11e6-b752-08002702c825:103-114
mysql.gtid_executed 테이블
9d850d65-219f-11e6-b752-08002702c825:1-102
9d850d65-219f-11e6-b752-08002702c825:113-114
트랜잭션의 Binary Log flush 실패(유실)
slave> show global variables like 'gtid_executed';
+---------------+----------------------------------------------------+
| Variable_name | Value |
+---------------+----------------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-112:115-240 |
+---------------+----------------------------------------------------+
master> show global variables like 'gtid_executed';
+---------------+--------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-240 |
+---------------+--------------------------------------------+
???
MySQL GTID 시작하기 6 / 15
8. 주제2. log-bin / log-slave-updates 옵션의 사용
7 / 15
(2) log-bin / log-slave-updates 옵션 사용시 유의할 점은?
• Slave DB의 gtid_executed 값에 빈 구간(113-114)이 발생
• 하지만 복제는 여전히 잘 되고, 데이터 정합성에도 전혀 문제가 없음
• 당장 문제가 없는 것은 GTID 복제 역시 Log File / Position 기반으로 동작하기 때문 ”mysql.slave_relay_log_info”
• IO Thread가 초기화 되는 시점에 “Master의 Executed GTID – Slave의 Executed GTID 영역”을 받아와서 Relay Log
에 저장하게 되며 문제는 여기서 발생하게 됨
Case 1) GTID 113-114 트랜잭션이 이미 Master에서 Purge 되고 남아있지 않은 경우 복제 연결 불가
Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO
MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.‘
Case 2) GTID 113-114 트랜잭션이 Master에 남아있는 경우 중복 실행 (데이터 정합성 문제 혹은 복제 에러 발생)
slave> show global variables like 'gtid_executed';
+---------------+----------------------------------------------------+
| Variable_name | Value |
+---------------+----------------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-112:115-240 |
+---------------+----------------------------------------------------+
master> show global variables like 'gtid_executed';
+---------------+--------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-240 |
+---------------+--------------------------------------------+
???
MySQL GTID 시작하기
???
9. 주제2. log-bin / log-slave-updates 옵션의 사용
8 / 15
(2) log-bin / log-slave-updates 옵션 사용시 유의할 점은?
• 문제가 생기기 전에 보정 필요
• 방안1) 누락된 트랜잭션을 Empty 트랜잭션으로 Skip 처리
• 방안2) Slave의 gtid_executed 값을 적절히 변경
slave> show global variables like 'gtid_executed';
+---------------+----------------------------------------------------+
| Variable_name | Value |
+---------------+----------------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-112,115-240 |
+---------------+----------------------------------------------------+
???
slave> STOP SLAVE SQL_THREAD;
slave> SET GTID_NEXT='9d850d65-219f-11e6-b752-08002702c825:113';
slave> BEGIN; COMMIT;
slave> SET GTID_NEXT='AUTOMATIC';
slave> START SLAVE SQL_THREAD;
slave> STOP SLAVE SQL_THREAD;
slave> show global variables like ‘gtid_executed’;
… '9d850d65-219f-11e6-b752-08002702c825:285’ …
slave> RESET MASTER;
slave> SET GLOBAL GTID_PURGED='9d850d65-219f-11e6-b752-08002702c825:1-285';
slave> START SLAVE SQL_THREAD ;
MySQL GTID 시작하기
10. 주제2. log-bin / log-slave-updates 옵션의 사용
9 / 15
(3) log-bin / log-slave-updates 옵션을 사용하지 않은 경우 유의할 점은?
• 트랜잭션 당 1건의 Record가 mysql.gtid_executed 테이블에 Insert
• N 건(기본 1000)의 Record가 쌓이면 N건을 Delete 하고 1건의 Record를 Insert (gtid_executed table compression)
• mysql.gtid_executed 테이블은 InnoDB 테이블이므로, ACID transaction 처리가 가능하므로 유실은 발생하지 않음
• MySQL 데몬이 재기동 되는 경우 gtid_executed 값은 mysql.gtid_executed 테이블의 값을 참조하여 초기화 됨
9d850d65-219f-11e6-b752-08002702c825 1000 1000
9d850d65-219f-11e6-b752-08002702c825 1001 1001
…
9d850d65-219f-11e6-b752-08002702c825 2000 2000 복제된 트랜잭션 1건당 1 Record 생성
9d850d65-219f-11e6-b752-08002702c825 1 1000
9d850d65-219f-11e6-b752-08002702c825 1001 1001
…
9d850d65-219f-11e6-b752-08002702c825 2000 2000
9d850d65-219f-11e6-b752-08002702c825 1 2000 압축된 결과 저장
삭제
MySQL GTID 시작하기
11. 주제2. log-bin / log-slave-updates 옵션의 사용
10 / 15
(3) log-bin / log-slave-updates 옵션을 사용하지 않은 경우 유의할 점은?
• 여기서 잠깐!!! InnoDB에 대량의 Insert, Delete 작업이 복제 트랜잭션 건수만큼 추가
• InnoDB 테이블의 기본적인 IO 메커니즘을 따르므로, 대량의 insert / delete에 따른 부하가 추가됨
• Master의 변경량이 많아진다면?
※ mysql.gtid_executed 테이블의 압축에 대한 로직은 MySQL Reference Manual에 잘못 설명이 되어 있음
Manual : log-bin 설정에 따라 다른 동작 실제 : log-bin / log-slave-updates 설정 따라 다른 동작
gtid_executed
INSERT 1 Row
redo undo
Compression
DELETE N Rows
INSERT 1 Row
Purge
Old Trx
---TRANSACTION 14349675830, ACTIVE 4787 sec fetching rows
mysql tables in use 1, locked 1
1766093 lock struct(s), heap size 189702352, 23552816 row
lock(s), undo log entries 23552812
MySQL thread id 2, OS thread handle 140153037256448, query
id 0 Compressing gtid_executed table
------------
TRANSACTIONS
------------
Trx id counter 19540270802
Purge done for trx's n:o < 17490950910 undo n:o < 0 state:
History list length 1024727771
MySQL GTID 시작하기
12. 주제3. 백업 데이터로 복구
11 / 15
Nothing Special !!
• IO Thread가 적절하게 Binary Log를 가져올 수 있도록 gtid_executed 값을 설정해 주면 됨
• mysqldump, xtrabackup 등의 도구에서 남겨준 gtid_executed 값을 참조하거나, 운영자가 직접 확인
• 신규 서버에 데이터 복구가 완료된 후
• GTID_EXECUTED 시스템 변수는 READ ONLY !!!
RESET MASTER로 GTID 초기화 후 GTID_PURGED 값을 설정 (GTID_EXECUTED 값은 자동으로 설정)
• 만약 Multi Source Replication을 사용하는 Slave라서 Master DB가 여러 대라면?
mysql> SET GLOBAL GTID_EXECUTED='9d850d65-219f-11e6-b752-08002702c825:1-2000';
ERROR 1238 (HY000): Variable 'gtid_executed' is a read only variable
???
mysql> RESET MASTER;
mysql> SET GLOBAL GTID_PURGED='9d850d65-219f-11e6-b752-08002702c825:1-2000';
mysql> RESET MASTER;
mysql> SET GLOBAL GTID_PURGED='9d850d65-219f-11e6-b752-08002702c825:1-2000,
a17a1326-219f-11e6-88f7-080027ee5436:1-520’;
MySQL GTID 시작하기
13. 주제4. Reset Master의 역습
12 / 15
• Non-GTID 복제에서 Slave DB에서 수행하는 Reset Master는 복제에 아무런 영향을 주지 않음
• Reset Master 커맨드는 gtid_executed 시스템 변수를 초기화 시키기 때문에, GTID 복제에서 문제를 일으킴
• IO Thread가 초기화 될 때 문제가 발생하므로, 앞서 다뤘던 방법을 참고하여 보정 작업 필요
slave> reset master;
…
slave> show global variables like 'gtid_executed';
+---------------+----------------------------------------------+
| Variable_name | Value |
+---------------+----------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:225-240 |
+---------------+----------------------------------------------+
master> show global variables like 'gtid_executed';
+---------------+--------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------+
| gtid_executed | 9d850d65-219f-11e6-b752-08002702c825:1-240 |
+---------------+--------------------------------------------+
???
MySQL GTID 시작하기
14. GTID를 이해하기 위한 기본 개념(II)
13 / 15
GTID_MODE
• GTID 발급 여부와 GTID를 부여받지 않은 트랜잭션(Anonymous Transaction)의 허용 여부를 결정
• 5.6 버전 기준으로 ON / OFF 2가지 모드가 존재
• 5.7 버전 기준으로 OFF ↔ OFF_PERMISSIVE ↔ ON_PERMISSIVE ↔ ON 4가지 모드가 존재, 단계별 변경만 가능
<GTID MODE 호환표>
Master
Slave
OFF OFF_PERMISSIVE ON_PERMISSIVE ON
OFF Y Y N N
OFF_PERMISSIVE Y Y Y Y
ON_PERMISSIVE Y Y Y Y
ON N N Y Y
MySQL GTID 시작하기
ON
OFF
(empty)
PERMISSIVE
Master 입장에서의 동작
ON : GTID 부여
OFF : GTID 부여하지 않음
Slave 입장에서의 동작
PERMISSIVE : GTID/Anonymous 혼재 허용
15. 주제5. GTID MODE 온라인 변경
14 / 15
5.7 버전에서 지원
https://dev.mysql.com/doc/refman/5.7/en/replication-mode-change-online-enable-gtids.html
1. 복제 그룹 내 모든 서버의 ENFORCE_GTID_CONSISTENCY 값을 ON 으로 변경한다.
GTID 환경에서 지원되지 않는 SQL을 사전에 검출하기 위함
원칙적으로는 해당 변수 값을 WARN으로 먼저 변경하여 문제가 발생하는 경우 Warning을 발생시키도록 함
장기간 모니터링 후 문제가 없다는 것을 확인하고, ON으로 변경해야 함
2. 복제 그룹 내 모든 서버의 GTID_MODE 값을 OFF_PERMISSIVE로 변경한다.
GTID가 부여된 트랜잭션이 넘어와도 처리할 수 있도록 하기 위함
3. 복제 그룹 내 모든 서버의 GTID_MODE 값을 ON_PERMISSIVE로 변경한다.
Master DB는 GTID가 부여하기 시작하고, Slave DB는 GTID 발급 여부와 관계없이 트랜잭션을 처리한다.
4. 잔여 Anonymous 트랜잭션 확인
모든 DB 노드에서 SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT‘ 결과 값을 확인
결과 값이 0인 상태가 한번이라도 보이면 OK
5. 복제 그룹 내 모든 서버의 GTID_MODE 값을 ON으로 변경한다.
더 이상 GTID가 발급되지 않은 트랜잭션은 존재하지 않음
6. Binary Log File / Position 기반으로 동작하던 복제를 Auto Position 모드로 변경한다.
STOP SLAVE; CHANGE MASTER TO MASTER_AUTO_POSITION=1; START SLAVE;
MySQL GTID 시작하기
16. 주제5. GTID MODE의 혼용
15 / 15
5.7 버전에서만 가능
MySQL GTID 시작하기
Group 1 (GTID)
분석/통계 작업용 DB (DW) - Multi Source Replication 구성
GTID_MODE = OFF_PERMISSIVE
Slave가 OFF_PERMISSIVE인 경우 GTID_MODE=ON/OFF인 DB를 모두
Master로 인식할 수 있다.
Group 2 (GTID)
channel 1 channel 2
Group 3 (non-GTID)
channel 3