MySQL數(shù)據(jù)庫(kù)主從技術(shù)GTID大揭秘
一、概述
1.1 GTID的概念
GTID(全局事務(wù)標(biāo)識(shí)符)是mysql MySQL-5.6.5開(kāi)始支持的新特性之一,全局事務(wù)標(biāo)識(shí)符不僅在源(主)服務(wù)器上是唯一的,而且在給定復(fù)制設(shè)置中的所有服務(wù)器都是唯一的。正因?yàn)檫@樣一個(gè)特性使得mysql的主從復(fù)制變得更加簡(jiǎn)單且一致性更高。它與源(主)服務(wù)器上提交的每個(gè)事務(wù)相關(guān)聯(lián),由服務(wù)器ID+事務(wù)ID組合而成。
GTID = source_id:transaction_id,中間由“:”分隔,source_id用于標(biāo)識(shí)原服務(wù)器,通常指server_uuid,由于GTID會(huì)傳遞到slave,所以也可以理解為源ID。transaction_id為當(dāng)前服務(wù)器上已提交事務(wù)的一個(gè)序列號(hào),通常從1開(kāi)始自增長(zhǎng)的序列,一個(gè)數(shù)值對(duì)應(yīng)一個(gè)事務(wù)。
查看本機(jī)的server_uuid方法如下:
- mysql> show variables like '%uuid%';
- +---------------+--------------------------------------+
- | Variable_name | Value |
- +---------------+--------------------------------------+
- | server_uuid | f3d0a8b5-a657-11eb-a6e5-000c29dbd935 |
- +---------------+--------------------------------------+
- 1 row in set (0.01 sec)
1.2 GTID的工作原理
1、當(dāng)一個(gè)事務(wù)在主庫(kù)端執(zhí)行并提交時(shí),會(huì)產(chǎn)生一個(gè)GTID并記錄到binlog日志中。
2、binlog傳輸?shù)絪lave,并存儲(chǔ)到slave的relaylog后,讀取這個(gè)GTID的這個(gè)值設(shè)置gtid_next變量,即告訴Slave,下一個(gè)要執(zhí)行的GTID值。
3、sql線程從relay log中獲取GTID,然后對(duì)比slave端的binlog是否有該GTID,如果有說(shuō)明該GTID的事務(wù)已經(jīng)執(zhí)行,slave會(huì)忽略。如果沒(méi)有記錄,slave會(huì)執(zhí)行該GTID的事務(wù),在執(zhí)行前會(huì)檢查其他session持有該GTID,確保該GTID的事務(wù)不會(huì)被重復(fù)執(zhí)行,并記錄該GTID到自身的binlog。
4、在解析過(guò)程中會(huì)判斷是否有主鍵,如果沒(méi)有就用二級(jí)索引,再?zèng)]有就走全表掃描。
1.3 mysql.gtid_exected表
GTID存儲(chǔ)在mysql的 gtid_executed的表中。該表供mysql服務(wù)器內(nèi)部使用,該表中的一行代表的每個(gè)GTID或GTID集合,以及該集合的開(kāi)始和結(jié)束事務(wù)ID;對(duì)于僅引用單個(gè)GTID的行,最后兩個(gè)值相同。
在mysql.gtid_executed安裝或升級(jí)MySQL Server時(shí),使用create table 類似于以下所示的語(yǔ)句創(chuàng)建該表(如果尚不存在):
- CREATE TABLE gtid_executed (
- source_uuid CHAR(36) NOT NULL,
- interval_start BIGINT(20) NOT NULL,
- interval_end BIGINT(20) NOT NULL,
- PRIMARY KEY (source_uuid, interval_start)
- )
注意:與其他MySQL系統(tǒng)表一樣,請(qǐng)勿嘗試自己創(chuàng)建或修改該表。
GTID僅當(dāng)gtid_mode is ON or ON_PERMISSIVE時(shí),GTID才會(huì)存儲(chǔ)在gtid_executed的表中,GTID的存儲(chǔ)與mysql是否啟用二進(jìn)制日志緊密相關(guān)。
- 如果禁用了二進(jìn)制日志記錄(log_binis OFF),或者如果 log_slave_updates禁用了二進(jìn)制日志記錄,則服務(wù)器將屬于每個(gè)事務(wù)的GTID與該事務(wù)一起存儲(chǔ)在表中。此外,該表會(huì)以用戶可配置的速率定期壓縮。這種情況僅適用于禁用了二進(jìn)制日志記錄或副本更新日志記錄的副本。它不適用于復(fù)制源服務(wù)器,因?yàn)楸仨氃谠瓷蠁⒂枚M(jìn)制日志記錄才能進(jìn)行復(fù)制。
- 如果啟用了二進(jìn)制日志記錄(log_bin是 ON),則每當(dāng)旋轉(zhuǎn)二進(jìn)制日志或關(guān)閉服務(wù)器時(shí),服務(wù)器都會(huì)將寫(xiě)入前一個(gè)二進(jìn)制日志的所有事務(wù)的GTID寫(xiě)入mysql.gtid_executed表中。這種情況適用于復(fù)制源服務(wù)器或啟用了二進(jìn)制日志記錄的副本。
- 如果服務(wù)器意外停止,則當(dāng)前二進(jìn)制日志文件中的GTID集不會(huì)保存在 mysql.gtid_executed表中?;謴?fù)期間,這些GTID從二進(jìn)制日志文件添加到表中。例外的是重新啟動(dòng)服務(wù)器時(shí)未啟用二進(jìn)制日志記錄。在這種情況下,服務(wù)器無(wú)法訪問(wèn)二進(jìn)制日志文件以恢復(fù)GTID,因此無(wú)法啟動(dòng)復(fù)制。
啟用二進(jìn)制日志記錄后,該 mysql.gtid_executed表將不保存所有已執(zhí)行事務(wù)的GTID的完整記錄。該信息由gtid_executed系統(tǒng)變量的全局值提供 。始終使用 @@GLOBAL.gtid_executed,它在每次提交后都會(huì)更新,以表示MySQL服務(wù)器的GTID狀態(tài),而不查詢 mysql.gtid_executed表。
1.4 mysql.gtid_executed表壓縮
隨著時(shí)間的流逝, mysql.gtid_executed表中可能會(huì)出現(xiàn)很多行,表會(huì)越來(lái)越大,為了節(jié)省空間,MySQL服務(wù)器mysql.gtid_executed通過(guò)用橫跨事務(wù)標(biāo)識(shí)符整個(gè)間隔的一行替換每行這樣的行來(lái)定期壓縮 表,如下所示:
- +--------------------------------------+----------------+--------------+
- | source_uuid | interval_start | interval_end |
- |--------------------------------------+----------------+--------------|
- | 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 |
- ...
您可以通過(guò)設(shè)置
gtid_executed_compression_period 系統(tǒng)變量來(lái)控制壓縮速率,此變量的默認(rèn)值為1000,這意味著默認(rèn)情況下,每1000個(gè)事務(wù)處理后將對(duì)表進(jìn)行壓縮。設(shè)置 gtid_executed_compression_period 為0根本無(wú)法執(zhí)行壓縮,gtid_executed如果您這樣做,應(yīng)該準(zhǔn)備增加表可能需要的磁盤(pán)空間量 。
該mysql.gtid_executed表的壓縮由名為的專用前臺(tái)線程執(zhí)行
thread/sql/compress_gtid_table。該線程未在的輸出中列出SHOW PROCESSLIST,但可以在threads表中的一行中查看 ,如下所示:
- mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
- RESOURCE_GROUP: SYS_default
- *************************** 2. row ***************************
- THREAD_ID: 45
- NAME: thread/sql/compress_gtid_table
- TYPE: FOREGROUND
- PROCESSLIST_ID: 6
- PROCESSLIST_USER: NULL
- PROCESSLIST_HOST: NULL
- PROCESSLIST_DB: NULL
- PROCESSLIST_COMMAND: Daemon
- PROCESSLIST_TIME: 8757
- PROCESSLIST_STATE: Suspending
- PROCESSLIST_INFO: NULL
- PARENT_THREAD_ID: 1
- ROLE: NULL
- INSTRUMENTED: YES
- HISTORY: YES
- CONNECTION_TYPE: NULL
- THREAD_OS_ID: 7602
- RESOURCE_GROUP: SYS_default
- 2 rows in set (0.01 sec)
二、GTID復(fù)制的優(yōu)缺點(diǎn)
2.1 GTID優(yōu)勢(shì)
1、更簡(jiǎn)單的實(shí)現(xiàn)failover,不用以前那樣在需要找log_file和log_pos。 2、更簡(jiǎn)單的搭建主從復(fù)制。 3、比傳統(tǒng)的復(fù)制更加安全。 4、GTID是連續(xù)的沒(méi)有空洞的,保證數(shù)據(jù)的一致性,零丟失。
2.2 GTID的限制
1、不允許在同一個(gè)事務(wù)內(nèi)對(duì)事務(wù)表和非事務(wù)進(jìn)行DML操作,例如在同一個(gè)事務(wù)內(nèi)先update innodb表,然后update myisam表。因?yàn)镚TID強(qiáng)制每一個(gè)GTID對(duì)應(yīng)一個(gè)事務(wù),而在同一個(gè)事務(wù)內(nèi)既操作innodb表又操作myisam,就會(huì)產(chǎn)生兩個(gè)GTID; 2、不允許CREATE TABLE … SELECT語(yǔ)句,首先這種語(yǔ)句對(duì)于statement格式的binlog是不安全的;而對(duì)于row格式的binlog,這種語(yǔ)句在binlog實(shí)際是分成兩個(gè)event進(jìn)行記錄的,一個(gè)記錄create創(chuàng)建操作,一個(gè)記錄insert操作,那么就有可能這兩個(gè)操作是對(duì)應(yīng)到同一個(gè)GTID上,而當(dāng)將這兩個(gè)擁有相同GTID的event傳到從庫(kù)時(shí),從庫(kù)就會(huì)忽略擁有相同GTID的insert操作,造成數(shù)據(jù)丟失; 3、CREATE TEMPORARY TABLE和DROP TEMPORARY TABLE不允許在事務(wù)內(nèi)執(zhí)行,只有在事務(wù)以外并且autocommit=1才能正常執(zhí)行; 4、不支持sql_slave_skip_counter,如果需要跳過(guò)事務(wù),可以用以下方法:
- set @@session.gtid_next='需要跳過(guò)的事務(wù)gtid'
- begin;commit;
- set session gtid_next=automatic;
【編輯推薦】