MySQL 使用GTID進行復制

1. GTID的格式和存儲

GTID即全局事務ID(global transaction identifier),GTID其實是由server_uuid:transaction_id組成的。其中server_uuid是一個MySQL實例的惟一標識,存放在數據目錄的auto.cnf文件下,transaction_id表明了該實例上已經提交的事務數量,而且隨着事務提交單調遞增,因此GTID可以保證每一個MySQL實例事務的執行(不會重複執行同一個事務,而且會補全沒有執行的事務)。html

1.1 GTID 集

GTID集是一組全局事務標識符,以下所示:mysql

gtid_set:
    uuid_set [, uuid_set] ...
    | ''

uuid_set:
    uuid:interval[:interval]...

uuid:
    hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh

h:
    [0-9|A-F]

interval:
    n[-n]

    (n >= 1)

GTID集在MySQL服務器中以多種方式使用。 例如,gtid_executedgtid_purged系統變量存儲的值表示爲GTID集。 此外,函數GTID_SUBSET()GTID_SUBTRACT()須要GTID集做爲輸入。 當從服務器變量返回GTID集時,UUID按字母順序排列,數值間隔按升序合併。web

1.2 mysql.gtid_executed 表

GTID存儲在mysql數據庫中名爲gtid_executed的表中。 對於它表示的每一個GTID或GTID集合,該表中的一行包含原始服務器的UUID,以及該集合的起始和結束事務ID; 對於僅引用單個GTID的行,這兩個最後兩個值是相同的。sql

當slave禁用binlog時,mysql.gtid_executed表使slave可以使用GTID,而且它能夠在二進制日誌丟失時保留GTID歷史記錄。數據庫

當gtid_mode爲ON或ON_PERMISSIVE時,GTID僅存儲在mysql.gtid_executed表中,存儲GTID的位置取決因而啓用仍是禁用binlog:安全

  • 若是禁用二進制日誌記錄(log_bin爲OFF),或者若是禁用log_slave_updates,則服務器將屬於每一個事務的GTID與表中的事務一塊兒存儲。 此外,該表能夠按期壓縮; 此狀況僅不適用於複製中的master,由於在主服務器上,必須啓用二進制日誌記錄才能進行復制。bash

  • 若是啓用了二進制日誌記錄(log_bin爲ON),則不管什麼時候輪詢二進制日誌或關閉服務器,服務器都會將寫入先前二進制日誌的全部事務的GTID寫入mysql.gtid_executed表。 這種狀況適用於複製主服務器或啓用了二進制日誌記錄的複製從服務器。服務器

    若是服務器意外中止,則當前二進制日誌中的GTID集不會保存在mysql.gtid_executed表中。 在這種狀況下,這些GTID會在恢復期間添加到表和gtid_executed系統變量中的GTID集合中。session

    啓用二進制日誌記錄時,mysql.gtid_executed表不會爲全部已執行的事務提供GTID的完整記錄。 該信息由gtid_executed系統變量的全局值提供。app

命令RESET MASTER將重置mysql.gtid_executed表。

1.3 mysql.gtid_executed 表壓縮

啓用GTID時,服務器會按期在mysql.gtid_executed表上執行此類壓縮。 經過設置gtid_executed_compression_period系統變量,您能夠控制壓縮表以前容許的事務數,從而控制壓縮率。 該變量的默認值爲1000; 這意味着,默認狀況下,在每1000次事務以後執行表的壓縮。 將gtid_executed_compression_period設置爲0能夠防止執行壓縮; 可是,若是執行此操做,您應該爲gtid_executed表可能須要的磁盤空間量的大幅增長作好準備。

【注意】:
啓用binlog時,且不使用gtid_executed_compression_period的值,會在每一個binlog輪換時壓縮mysql.gtid_executed表。

壓縮前:

mysql> SELECT * FROM mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid                          | interval_start | interval_end |
|--------------------------------------+----------------+--------------|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37             | 37           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38             | 38           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39             | 39           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40             | 40           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41             | 41           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42             | 42           |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43             | 43           |
...

壓縮後:

+--------------------------------------+----------------+--------------+
| source_uuid                          | interval_start | interval_end |
|--------------------------------------+----------------+--------------|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37             | 43           |
...

mysql.gtid_executed表的壓縮由名爲thread/sql/compress_gtid_table的專用前臺線程執行。 該線程未在SHOW PROCESSLIST的輸出中列出,但能夠將其視爲performance_schema.threads表中的一行,以下所示:

mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
*************************** 1. row ***************************
          THREAD_ID: 26
               NAME: thread/sql/compress_gtid_table
               TYPE: FOREGROUND
     PROCESSLIST_ID: 1
   PROCESSLIST_USER: NULL
   PROCESSLIST_HOST: NULL
     PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
   PROCESSLIST_TIME: 1509
  PROCESSLIST_STATE: Suspending
   PROCESSLIST_INFO: NULL
   PARENT_THREAD_ID: 1
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: NULL
       THREAD_OS_ID: 18677

thread/sql/compress_gtid_table線程一般會休眠,直到執行了gtid_executed_compression_period事務,而後喚醒以執行mysql.gtid_executed表的壓縮,如前所述。 而後它休眠直到另外一個gtid_executed_compression_period事務發生,而後喚醒再次執行壓縮,無限期地重複此循環。 禁用二進制日誌記錄時將此值設置爲0意味着線程始終處於休眠狀態且從不喚醒。

2. GTID 生命週期

GTID的生命週期包括如下步驟:

  1. Master產生GTID:在Master端產生一個GTID的信息,並保存到binlog中。
  2. 發送Binlog信息到從庫上,將binlog信息發送到SLAVE所在的服務器上。將SLAVE中的gtid_next的值設置爲GTID的值。
  3. SLAVE執行GTID。SLAVE首先驗證是否在本身的二進制日誌中使用了這個GTID號
  4. SLAVE不生成GTID。因爲GTID不爲空,SLAVE不會嘗試爲該事務生成新的GTID,而是從gtid_next 中讀取GTID值,寫入二進制日誌中,來標識一個事務的GTID的值。

gtid_purged
gtid_purged系統變量(@@global.gtid_purged)中的GTID集包含已在服務器上提交但在服務器上的任何二進制日誌文件中不存在的全部事務的GTID。 如下類別的GTID在此集合中:

  • 在slave上禁用binlog提交的複製事務的GTID
  • 已寫入已清除的binlog的事務的GTID
  • 由語句SET @@global.gtid_purged明確添加到集合中的GTID

服務器啓動時,將初始化gtid_purged系統變量中的GTID集。 每一個二進制日誌文件都以事件Previous_gtids_log_event開頭,該事件包含全部先前二進制日誌文件中的GTID集(由前一個文件的Previous_gtids_log_event中的GTID和文件自己中每一個Gtid_log_event的GTID組成)。 最舊的二進制日誌文件中的Previous_gtids_log_event的內容用於在服務器啓動時初始化gtid_purged集,並在清除二進制日誌文件時維護該集。

3. 使用GTID搭建主從

GTID使用master_auto_position=1代替了基於binlog和position號的主從複製搭建方式,更便於主從複製的搭建。

3.1 環境準備

類型 ip prot server-id 是否開啓binlog binlog格式 log_slave_updates參數
master 192.168.56.100 3307 1003307 log-bin = /data/mysql/mysql3307/logs/my3307_binlog binlog_format = row log_slave_updates=1
slave 192.168.56.200 3307 2003307 log-bin = /data/mysql/mysql3307/logs/my3307_binlog binlog_format = row log_slave_updates=1

3.2 配置GTID主從的參數

  • server_id: 設置MySQL實例的server_id,每一個server_id不能同樣
  • gtid_mode=ON: MySQL實例開啓GTID模式
  • enforce_gtid_consitency=ON:使用GTID模式複製時,須要開啓參數,用來保證數據的一致性。
  • log-bin: MySQL必需要開啓binlog
  • log-slave-updates=1:決定SLAVE從Master接收到更新且執行是否記錄到SLAVE的binlog中
  • binlog_format=ROW: binlog格式爲row
  • skip-slave-start=1(可選): 當SLAVE數據庫啓動的時候,SLAVE不會啓動複製

3.3 在master上操做

1) 建立複製帳號

create user 'repl'@'%' identified by 'wanbin'; grant replication slave on *.* to 'repl'@'%';

2) master數據庫利用xtrabackup備份至slave上

innobackupex --defaults-file=/etc/my3307.cnf -uroot -pmysql --stream=tar ./ |ssh root@mysqldb2 "cat - > /data/backup/dbback`date +%Y%m%d_%H%M%S`.tar"

3.4 在slave上操做

  1. 解壓備份
mkdir dbback20181012_151213

tar -xvf dbback20181012_151213.tar -C dbback20181012_151213
  1. prepare備份
innobackupex --apply-log /data/backup/dbback20181012_151213/
  1. 恢復備份
innobackupex --defaults-file=/etc/my3307.cnf --copy-back /data/backup/dbback20181012_151213/

chown -R mysql:mysql /data/mysql/mysql3307/data

mysqld --defaults-file=/etc/my3307.cnf &
  1. 過濾掉已執行過的gtid
1)查看xtrabackup_info文件中的gtid信息
cat xtrabackup_info|grep binlog_pos
binlog_pos = filename 'my3307_binlog.000002', position '2401', GTID of the last change '3a068bf8-cdeb-11e8-8176-080027b0b461:1-10'

2)查看slave已執行的gtid是否爲空,若是不爲空,須要執行reset MASTER進行清理,不然沒法設置gtid。
root@localhost [(none)] 15:50:41>show master status \G;
*************************** 1. row ***************************
             File: my3307_binlog.000002
         Position: 234
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 3a068bf8-cdeb-11e8-8176-080027b0b461:1-10,
ffe86a27-cdef-11e8-bb92-0800275b8a9a:1-2
1 row in set (0.00 sec)

3)執行reset master
root@localhost [(none)] 15:50:52>reset master;
Query OK, 0 rows affected (0.04 sec)

root@localhost [(none)] 15:53:18>show master status\G
*************************** 1. row ***************************
             File: my3307_binlog.000001
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)

4)執行GTID_PURGED
root@localhost [(none)] 15:56:32>set session sql_log_bin = 0;
root@localhost [(none)] 15:56:53>set global gtid_purged='3a068bf8-cdeb-11e8-8176-080027b0b461:1-10';
root@localhost [(none)] 15:57:58>set session sql_log_bin = 1;
  1. 配置主從
執行help change master to 能夠獲取change master to命令

CHANGE MASTER TO
  MASTER_HOST='192.168.56.100',
  MASTER_USER='repl',
  MASTER_PASSWORD='wanbin',
  MASTER_PORT=3307,
  master_auto_position=1;
  1. 開始主從複製
start slave;


#若是想分別指定啓動線程,可使用以下命令
START SLAVE IO_THREAD;
START SLAVE SQL_THREAD;

#一樣關閉命令:
STOP SLAVE;

#分別關閉命令:
STOP SLAVE IO_THREAD;
STOP SLAVE SQL_THREAD;

4. 使用gtid進行復制的限制

因爲基於GTID的複製依賴於事務,所以在使用時不支持MySQL中可用的某些功能。本節提供有關使用GTID進行復制的限制和限制的信息。

4.1 非事務性存儲引擎的更新

使用GTID時,使用非事務性存儲引擎(如MyISAM)對錶的更新不能在與使用事務性存儲引擎(如InnoDB)的表的更新相同的語句或事務中進行。

此限制是因爲對使用非事務性存儲引擎的表的更新與對同一事務中使用事務存儲引擎的表的更新混合可能致使將多個GTID分配給同一事務。

當master和slave使用不一樣的存儲引擎用於同一個表的相應版本時,也會發生這樣的問題,其中一個存儲引擎是事務性的而另外一個不是。 還要注意,定義爲在非事務性表上運行的觸發器多是致使這些問題的緣由。

在剛剛提到的任何一種狀況下,事務和GTID之間的一對一對應關係被破壞,結果是基於GTID的複製沒法正常運行。

4.2 CREATE TABLE … SELECT 語句

CREATE TABLE … SELECT對於基於語句的複製是不安全的。 使用基於行的複製時,此語句實際上記錄爲兩個單獨的事件 - 一個用於建立表,另外一個用於將源表中的行插入剛剛建立的新表中。 當在事務中執行此語句時,在某些狀況下,這兩個事件可能會接收相同的事務標識符,這意味着slave將跳過包含插入的事務。 所以,使用基於GTID的複製時不支持CREATE TABLE … SELECT。

4.3 臨時表

使用GTID時(即,enforce_gtid_consistency系統變量設置爲ON時),事務,過程,函數和觸發器內不支持CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE語句。 能夠在啓用GTID的狀況下使用這些語句,但僅限於任何事務以外,而且僅使用autocommit = 1。

4.4 防止執行不受支持的語句

要防止執行會致使基於GTID的複製失敗的語句,必須在啓用GTID時使用–enforce-gtid-consistency選項啓動全部服務器。

4.5 跳過事務

使用GTID時不支持sql_slave_skip_counter。 若是您須要跳過事務,請使用master的gtid_executed變量的值; 有關詳細信息,請參考
https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-failover.html#replication-gtids-failover-empty

4.6 Ignoring servers

使用GTID時,不推薦使用CHANGE MASTER TO語句的IGNORE_SERVER_IDS選項,由於已經應用的事務會自動被忽略。 在啓動基於GTID的複製以前,請檢查並清除以前在相關服務器上設置的全部忽略的服務器ID列表。 能夠爲各個通道發出的SHOW_SLAVE_STATUS語句顯示已忽略的服務器ID列表(若是有)。 若是沒有列表,則Replicate_Ignore_Server_Ids字段爲空。

4.7 GTID mode and mysqldump

若是目標服務器的二進制日誌中沒有GTID,則能夠將使用mysqldump建立的轉儲導入到啓用了GTID模式的MySQL服務器中。

4.8 GTID mode and mysql_upgrade

當服務器在啓用全局事務標識符(GTID)的狀況下運行時(gtid_mode = ON),請不要經過mysql_upgrade啓用二進制日誌記錄(–write-binlog選項)。

相關文章
相關標籤/搜索