概念
GTID 全局事務唯一標識(? global transaction identifier)
格式
單個GTID由兩部分組成 ,用冒號分割;前面一部分為server_uuid,后面一部分transaction_id
是由事務在源上提交的順序確定的序列號
GTID = server_uuid:transaction_id
?舉例:
03775d13-0fe8-11e9-b537-38bc01691bfc:1?
該GTID是在UUID 為775d13-0fe8-11e9-b537-38bc01691bfc 的服務器上提交的第一個事務
GTID集合?
GTID集合 可以包括一個或多個的GTID集合。
GTID 集在 MySQL 服務器中以多種方式使用,
1 系統變量 gitd_executed和 gtid_purged存儲的就是GTID集合 ,后面會詳細介紹這兩個參數
mysql> select @@GLOBAL.gtid_executed;
+-------------------------------------------------+
| @@GLOBAL.gtid_executed |
+-------------------------------------------------+
| 03775d13-0fe8-11e9-b537-38bc01691bfc:1-55063960 |
+-------------------------------------------------+
1 row in set (0.00 sec)mysql>
mysql>
mysql> select @@GLOBAL.gtid_purged;
+-------------------------------------------------+
| @@GLOBAL.gtid_purged |
+-------------------------------------------------+
| 03775d13-0fe8-11e9-b537-38bc01691bfc:1-54852116 |
+-------------------------------------------------+
1 row in set (0.00 sec)
2 START SLAVE 中的子句 UNTIL SQL_BEFORE_GTIDS 和?UNTIL SQL_AFTER_GTIDS 可以用來使副本僅處理 GTID 集中的第一個 GTID 之前的事務,或在 GTID 集中的最后一個 GTID 之后停止
3 內建函數??GTID_SUBSET()?and?GTID_SUBTRACT()? 需要一個GTID集合作為參數傳入
存儲
GTID 存儲在 mysql.
gtid_executed
中 名為 的表中。
CREATE TABLE `gtid_executed` (`source_uuid` char(36) NOT NULL COMMENT 'uuid of the source where the transaction was originally executed.',`interval_start` bigint(20) NOT NULL COMMENT 'First number of interval.',`interval_end` bigint(20) NOT NULL COMMENT 'Last number of interval.',PRIMARY KEY (`source_uuid`,`interval_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
mysql.gtid_execulated 表壓縮
gtid_executed_compression_period?該變量的默認值為 1000,這意味著默認情況下,每 1000 個事務后就會執行一次表壓縮。為 0 事會完全阻止執行壓縮,會導致該表的磁盤空間量大幅增加。
經過壓縮之后查看該表
mysql> select * from gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| 03775d13-0fe8-11e9-b537-38bc01691bfc | 1 | 55033090 |
+--------------------------------------+----------------+--------------+
1 row in set (0.00 sec)
GTID 生命周期
GTID的生命周期由以下步驟組成:
-
事務在復制源服務器上執行并提交。該客戶端事務被分配一個由源的 UUID 和該服務器上尚未使用的最小非零事務序列號組成的 GTID。GTID 被寫入源的二進制日志(緊鄰日志中事務本身之前)。如果客戶端事務沒有寫入二進制日志(例如,因為事務被過濾掉,或者事務是只讀的),則不會為其分配 GTID。
-
如果為事務分配了 GTID,則 GTID 會在提交時通過在事務開始時將其寫入二進制日志(作為?
Gtid_log_event
)以原子方式持久保存。每當二進制日志輪換或服務器關閉時,服務器都會將前一個二進制日志文件的所有事務的 GTID 寫入表中?mysql.gtid_executed
。 -
如果為事務分配了 GTID,則通過將 GTID 添加到系統變量gtid_executed (
@@GLOBAL.gtid_executed
)?中的 GTID 集合,以非原子方式(事務提交后不久)將 GTID 外部化。該 GTID 集包含所有已提交 GTID 事務集的表示,并且在復制中用作表示服務器狀態的令牌。啟用二進制日志記錄(根據源的要求)后,系統變量gtid_executed中的 GTID 集是所應用事務的完整記錄,但表?mysql.gtid_executed
不是,因為最新的歷史記錄仍在當前二進制日志文件中。 -
在二進制日志數據傳輸到副本并存儲在副本的中繼日志中之后,副本讀取 GTID 并設置其系統變量gtid_next的值為此 GTID。這告訴副本必須使用此 GTID 記錄下一個事務。需要注意的是,副本集位于
gtid_next
會話上下文中。 -
副本會驗證是否還沒有線程取得 GTID 的所有權gtid_next才能處理事務。通過在處理事務本身之前首先讀取并檢查復制事務的 GTID,副本不僅可以保證之前沒有具有此 GTID 的事務應用于副本,而且還沒有其他會話已經讀取此 GTID 但尚未讀取已提交關聯交易。因此,如果多個客戶端嘗試同時應用同一事務,服務器會通過僅讓其中一個客戶端執行來解決此問題。副本的系統gtid_owned?變量 (?
@@GLOBAL.gtid_owned
) 顯示當前正在使用的每個 GTID 以及擁有它的線程的 ID。如果GTID已經被使用,則不會引發錯誤,并且使用自動跳過功能來忽略該事務。 -
如果尚未使用 GTID,副本將應用復制的事務。由于?gtid_next被設置為源已分配的 GTID,因此副本不會嘗試為此事務生成新的 GTID,而是使用 中存儲的 GTID?gtid_next。
-
如果在副本上啟用了二進制日志記錄,則 GTID 會在提交時通過在事務開始時將其寫入二進制日志(作為?
Gtid_log_event
)以原子方式持久保存。每當二進制日志輪換或服務器關閉時,服務器都會將寫入前一個二進制日志文件的所有事務的 GTID 寫入表中?mysql.gtid_executed
。 -
如果在副本上禁用二進制日志記錄,則通過將 GTID 直接寫入?
mysql.gtid_executed
表中來以原子方式持久保存 GTID。MySQL 在事務中附加一條語句,將 GTID 插入表中。在這種情況下,該?mysql.gtid_executed
表是應用于副本的事務的完整記錄。請注意,在 MySQL 5.7 中,將 GTID 插入表的操作對于 DML 語句來說是原子的,但對于 DDL 語句來說不是,因此如果服務器在涉及 DDL 語句的事務后意外退出,GTID 狀態可能會變得不一致。從 MySQL 8.0 開始,DDL 語句和 DML 語句的操作都是原子的。 -
在副本上提交復制事務后不久,GTID 將通過將其添加到 副本gtid_executed的系統變量 (?
@@GLOBAL.gtid_executed
) 中的 GTID 集合來非原子地外部化。至于源,該 GTID 集包含所有已提交的 GTID 事務集的表示。如果在副本上禁用二進制日志記錄,則該?mysql.gtid_executed
表也是副本上應用的事務的完整記錄。如果在副本上啟用了二進制日志記錄,這意味著某些 GTID 僅記錄在二進制日志中,則系統變量中的 GTID 集gtid_executed是唯一完整的記錄。
參數解讀
enforce_gtid_consistency?
Command-Line Format(命令行格式) | --enforce-gtid-consistency[=value] |
---|---|
System Variable(系統變量) | enforce_gtid_consistency |
Scope(范圍) | Global |
Dynamic(動態的) | Yes |
Type(類型) | Enumeration |
Default Value(默認值) | OFF |
Valid Values(有效值) |
|
根據此變量的值,服務器通過僅允許執行可以使用 GTID 安全記錄的語句來強制執行 GTID 一致性。您?必須在啟用基于 GTID 的復制之前設置此變量 為?ON
。
可以配置的值為 :
-
OFF
:所有事務都允許違反GTID一致性。 -
ON
:任何事務都不允許違反GTID一致性。 -
WARN
:允許所有事務違反 GTID 一致性,但在這種情況下會生成警告。WARN
MySQL 5.7.6 中添加。
?
當設置為 ON?
時,?只能記錄可以使用 GTID 安全語句記錄的語句?,因此此處列出的操作不能與此選項一起使用:
-
CREATE TABLE ... SELECT聲明
-
CREATE TEMPORARY TABLE或?DROP TEMPORARY TABLE交易內的語句
-
更新事務性表和非事務性表的事務或語句。有一個例外,即如果所有非事務性表都是臨時表,則允許在與事務性 DML 相同的事務或同一語句中使用?非事務性DML 。
僅當語句發生二進制日志記錄時才生效。如果服務器上禁用了二進制日志記錄,或者語句由于被過濾器刪除而未寫入二進制日志,則不會對未記錄的語句檢查或強制執行 GTID 一致性。
gtid_executed_compression_period
Command-Line Format | --gtid-executed-compression-period=# |
---|---|
System Variable | gtid_executed_compression_period |
Scope | Global |
Dynamic | Yes |
Type | Integer |
Default Value | 1000 |
Minimum Value | 0 |
Maximum Value | 4294967295 |
每次處理這么多事務時?壓縮表mysql.gtid_executed
。當服務器上啟用二進制日志記錄時,不會使用此壓縮方法,而是?mysql.gtid_executed
在每次二進制日志輪轉時對表進行壓縮。當服務器上禁用二進制日志記錄時,壓縮線程將休眠,直到執行了指定數量的事務,然后喚醒以執行表的壓縮?mysql.gtid_executed
。將此系統變量的值設置為0意味著線程永遠不會喚醒,因此不使用這種顯式壓縮方法。相反,壓縮會根據需要隱式發生。
gtid_mode?
ommand-Line Format | --gtid-mode=MODE |
---|---|
System Variable | gtid_mode |
Scope | Global |
Dynamic | Yes |
Type | Enumeration |
Default Value | OFF |
Valid Values |
|
?控制是否啟用基于 GTID 的日志記錄以及日志可以包含的事務類型。在 MySQL 5.7.6 之前,此變量--gtid-mode是只讀的,并且僅在服務器啟動時使用 。在 MySQL 5.7.5 之前,使用 ??--gtid-mode=ON?啟動服務器要求服務器也使用?--log-bin和?--log-slave-updates選項啟動。從 MySQL 5.7.5 開始,這不再是一個要求。
MySQL 5.7.6 允許動態設置此變量。您必須具有足夠的權限才能設置全局系統變量。
enforce_gtid_consistency必須先設置ON
為 才能設置?gtid_mode=ON。
MySQL 5.7.6 及更高版本中記錄的事務可以是匿名的,也可以使用 GTID。匿名事務依靠二進制日志文件和位置來識別特定事務。GTID 事務有一個唯一的標識符,用于引用事務。OFF_PERMISSIVE
MySQL 5.7.6 中添加的和?模式ON_PERMISSIVE
允許在拓撲中混合這些事務類型。現在不同的模式是:
-
OFF
:新事務和復制事務都必須是匿名的。 -
OFF_PERMISSIVE
:新事務是匿名的。復制事務可以是匿名事務,也可以是 GTID 事務。 -
ON_PERMISSIVE
:新事務是GTID事務。復制事務可以是匿名事務,也可以是 GTID 事務。 -
ON
:新事務和復制事務都必須是GTID事務。
從一個值到另一個值的更改一次只能是一步。例如,如果?gtid_mode當前設置為?OFF_PERMISSIVE
,則可以更改為?OFF
或ON_PERMISSIVE
,但不能更改為ON
。
gtid_next
System Variable | gtid_next |
---|---|
Scope | Session |
Dynamic | Yes |
Type | Enumeration |
Default Value | AUTOMATIC |
Valid Values |
|
該變量用于指定 是否以及如何獲取下一個GTID。
設置此系統變量的會話值是一項受限制的操作。會話用戶必須具有足夠的權限才能設置受限會話變量。請參見?第 5.1.8.1 節“系統變量權限”。
gtid_next
可以采用以下任意值:
-
AUTOMATIC
:使用下一個自動生成的全局事務ID。 -
ANONYMOUS
:事務沒有全局標識符,僅通過文件和位點來標識。 -
全局事務ID:??
UUID:
NUMBER
?。
上述哪個選項準確取決于gtid_mode?的設置,如果是gtid_mode = OFF,?則設置此變量無效。
將此變量設置為?UUID
:NUMBER
并提交或回滾事務后,SET GTID_NEXT
必須在任何其他語句之前再次發出顯式語句。
gtid_owned
System Variable | gtid_owned |
---|---|
Scope | Global, Session |
Dynamic | No |
Type | String |
Unit | set of GTIDs |
?
該只讀變量主要供內部使用。其內容取決于其范圍。
gtid_executed
System Variable | gtid_executed |
---|---|
Scope | Global |
Dynamic | No |
Type | String |
Unit | set of GTIDs |
?此變量包含在服務器上執行的所有事務的集合以及已由語句SET gtid_purged 設置的 GTID集合。
這與SHOW MASTER STATUS?和 SHOW SLAVE STATUS的輸出中的Executed_Gtid_Set列?的值相同?。
該變量的值是 GTID 集,
在任何給定時間可以在二進制日志中找到的事務集等于?GTID_SUBTRACT(@@GLOBAL.gtid_executed, @@GLOBAL.gtid_purged);也就是說,二進制日志中尚未清除的所有事務。
發出RESET MASTER
會導致該變量的全局值(但不是會話值)重置為空字符串。除了由于RESET MASTER
原因而清除該集合時,GTID 不會以其他方式從該集合中刪除?。
在 MySQL 5.7.7 之前,此變量還可以與會話范圍一起使用,其中它包含當前會話中寫入緩存的事務集的表示。MySQL 5.7.7 中已棄用會話范圍。
gtid_purged?
System Variable | gtid_purged |
---|---|
Scope | Global |
Dynamic | Yes |
Type | String |
Unit | set of GTIDs |
系統變量( gtid_purged)?的全局值?@@GLOBAL.gtid_purged
是一個 GTID 集合,由服務器上已提交但不存在于服務器上任何二進制日志文件中的所有事務的 GTID 組成。????????gtid_purged是 gtid_executed的子集?。GTID 的以下類別位于????????gtid_purged:
-
在副本上禁用二進制日志記錄的情況下提交的復制事務的 GTID。
-
寫入二進制日志文件(現已被清除)的事務的 GTID。
-
由語句
SET @@GLOBAL.gtid_purged?
顯式添加到集合中的 GTID .
發出 RESET MASTER 會導致gtid_purged 的值重置為空字符串。
可以手動設置?gtid_purged 的值,以便在服務器上記錄某個 GTID 集中的事務已被應用,盡管它們不存在于服務器上的任何二進制日志中。此操作的一個示例用例是當您正在恢復服務器上一個或多個數據庫的備份,但您沒有包含服務器上事務的相關二進制日志時。
在 MySQL 5.7 中,僅當 gtid_executed?為空字符串時才可以更新 gtid_purged 的值 。因此gtid_purged為空字符串。當復制之前尚未開始,或者復制之前未使用 GTID 時,就會出現這種情況。
SET @@GLOBAL.gtid_purged = 'gtid_set'