MySQL 使用GTID進行復制


1. GTID的格式和存儲

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

1.1 GTID 集

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

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按字母順序排列,數值間隔按升序合並。

1.2 mysql.gtid_executed 表

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

當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,因為在主服務器上,必須啟用二進制日志記錄才能進行復制。

  • 如果啟用了二進制日志記錄(log_bin為ON),則無論何時輪詢二進制日志或關閉服務器,服務器都會將寫入先前二進制日志的所有事務的GTID寫入mysql.gtid_executed表。 這種情況適用於復制主服務器或啟用了二進制日志記錄的復制從服務器。

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

    啟用二進制日志記錄時,mysql.gtid_executed表不會為所有已執行的事務提供GTID的完整記錄。 該信息由gtid_executed系統變量的全局值提供。

命令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選項)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM