MySQL GTID簡介
GTID( Global Transaction Identifier)全局事務(wù)標識篙耗,由主庫上生成的與事務(wù)綁定的唯一標識迫筑,這個標識不僅在主庫上是唯一的,在MySQL集群內(nèi)也是唯一的宗弯。GTID是 MySQL 5.6 版本引入的一個有關(guān)于主從復(fù)制的重大改進脯燃,相對于之前版本基于Binlog文件+Position的主從復(fù)制,基于GTID的主從復(fù)制蒙保,數(shù)據(jù)一致性更高辕棚,主從數(shù)據(jù)復(fù)制更健壯东臀,主從切換赛蔫、故障切換不易出錯,很少需要人為介入處理炉菲。
MySQL GTID特點
事務(wù)提交產(chǎn)生GTID详恼,GTID與事務(wù)及事務(wù)提交所在的節(jié)點綁定补君,GTID與事務(wù)一起寫入Binlog,但是從庫應(yīng)用Binlog并不會生成新的GTID单雾。集群中的任何一個節(jié)點赚哗,根據(jù)其GTID值就可以知道哪些事務(wù)已經(jīng)執(zhí)行,哪些事務(wù)沒有執(zhí)行硅堆,如果發(fā)現(xiàn)某個GTID已執(zhí)行屿储,重復(fù)執(zhí)行該GTID,將會被忽略渐逃,即同一個GTID只能被應(yīng)用一次够掠。當(dāng)一個連接執(zhí)行一個特定GTID的事務(wù),但是還沒有提交茄菊,此時有另外一個連接也要執(zhí)行相同GTID的事務(wù)疯潭,那么第二個連接的執(zhí)行將會被阻塞,直到第一個事務(wù)提交或者回滾面殖。如果第一個事務(wù)成功提交竖哩,第二個事務(wù)將會被忽略。如果第一個事務(wù)回滾脊僚,第二個事務(wù)正常執(zhí)行相叁。如何開啟GTID
gtid_mode=ON
enforce_gtid_consistency=ON
GTID長啥樣
GTID = server_uuid:transaction_id
示例:3E11FA47-71CA-11E1-9E33-C80AA9429562:1
server_uuid標識了該事務(wù)執(zhí)行的源節(jié)點,存儲在數(shù)據(jù)目錄中的auto.cnf文件中,transaction_id 是在該主庫上生成的事務(wù)序列號增淹,從1開始椿访,示例中 3E11FA47-71CA-11E1-9E33-C80AA9429562 是這個節(jié)點的server_uuid,1為這個節(jié)點上提交的第1個事務(wù)的事務(wù)號虑润,如果提交了10個事務(wù)成玫,GTID會是這樣: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-10
GTID可以是一段連續(xù)或者不連續(xù)的幾段事務(wù)序列集合,下面是可能出現(xiàn)的GTID模樣:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:12:47-49
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19(多個節(jié)點提交事務(wù)拳喻,通常發(fā)生了主從切換)
GTID存儲在什么地方哭当?
GTID與事務(wù)綁定在一起,隨著事務(wù)的提交舞蔽,GTID隨事務(wù)信息一起寫入Binlog荣病,通過主從復(fù)制码撰,傳遞到從庫渗柿。對于已經(jīng)執(zhí)行了的事務(wù),其GTID通常會記錄在MySQL的系統(tǒng)變量@@GLOBAL.gtid_executed 以及系統(tǒng)表mysql.gtid_executed中脖岛,系統(tǒng)變量@@GLOBAL.gtid_executed 在內(nèi)存中朵栖,屬于非持久化存儲,而系統(tǒng)表mysql.gtid_executed屬于持久化存儲柴梆。
mysql.gtid_executed 表的更新陨溅。與Binlog有沒有打開有關(guān)。
如果開啟了Binlog绍在,只有在 Binlog輪轉(zhuǎn)或者MySQL關(guān)閉的時候门扇,才會把Binlog中的GTID與入到mysql.gtid_executed表中。
如果沒有開啟Binlog偿渡,那么將通過 gtid_executed_compression_period 這個參數(shù)控制mysql.gtid_executed表的更新臼寄。默認值為1000,即每1000個事務(wù)溜宽,將mysql.gtid_executed表中的數(shù)據(jù)進行合并吉拳。 gtid_executed_compression_period設(shè)置為0,將不會進行合并适揉,mysql.gtid_executed 表會變得越來越大留攒,直到把磁盤用完。如果開啟了Binlog嫉嘀,gtid_executed_compression_period這個參數(shù)將不再起作用炼邀。mysql.gtid_executed表的數(shù)據(jù)合并壓縮由線程函數(shù)compress_gtid_table來執(zhí)行,位于源碼sql/rpl_gtid_persist.cc
extern "C" void *compress_gtid_table(void *p_thd);
該線程不在show processlist中展示剪侮,但是可以在 performance_schema.threads 表中看到拭宁。
SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
如果MySQL異常崩潰,GTID沒來得及寫入mysql.gtid_executed表中,那么在MySQL重新啟動后红淡,會從Binlog中搜索GTID不狮,并將這一部分沒有寫入到mysql.gtid_executed表的GTID寫入到表中。如果想查詢最新的GTID提交情況在旱,建議查詢MySQL全局變量 @@GLOBAL.gtid_executed摇零,而不是查詢表 mysql.gtid_executed。
開始GTID后桶蝎,Binlog存儲事務(wù)和GTID信息驻仅,可以通過mysqlbinlog工具來解析,具體用法如下:
mysqlbinlog --start-datetime="2017-03-21 10:20:00" --start-datetime="2017-03-21 12:20:00" mysql-bin.000001 --base64-output=decode-rows -vvv > binlog.txt
GTID生命周期:
當(dāng)一個事務(wù)在一個主庫上被執(zhí)行和提交登渣,那么這個事務(wù)就會被分配一個和該主庫uuid相關(guān)聯(lián)的gtid噪服,這個gtid被寫入到主庫的binlog文件中。當(dāng)這個binlog文件達到最大值發(fā)生輪轉(zhuǎn)胜茧,或者MySQL Server關(guān)閉時粘优,上一個binlog文件中的事務(wù)GTID將會被寫入到mysql.gtid_executed表中。事務(wù)提交時呻顽,該事務(wù)的gtid會很快的添加到系統(tǒng)變量 @@GLOBAL.gtid_executed雹顺,但是系統(tǒng)表 mysql.gtid_executed 則不會,因為有部分gtid還在binlog中廊遍,需要等到binlog輪轉(zhuǎn)或者MySQL Server關(guān)閉時才會寫入到mysql.gtid_executed表中嬉愧。主庫上的binlog通過主從復(fù)制協(xié)議傳送到從庫,并寫入到從庫的relay log喉前,從庫讀取relay log中的gtid和對應(yīng)的事務(wù)信息没酣,把gtid_next設(shè)置為該gtid值,使得從庫使用該gtid值應(yīng)用其對應(yīng)的事務(wù)卵迂。如果多個線程并發(fā)地應(yīng)用同一個事物裕便,比如多個線程設(shè)置gtid_next為同一個值,MySQL Server只允許其中一個線程執(zhí)行狭握,gtid_owned系統(tǒng)變量記錄著誰擁有該GTID闪金。GTID Auto-Position:
GTID之前的主從復(fù)制是基于文件+偏移的方式,建立主從復(fù)制论颅,必須先知道主庫的binlog文件和偏移位置( MASTER_LOG_FILE 和 MASTER_LOG_POS)哎垦。而使用基于GTID的主從復(fù)制,設(shè)置 MASTER_AUTO_POSITION =1恃疯,從庫發(fā)送自身已經(jīng)接收到的gtid給主庫漏设,主庫將從庫缺失的gtid及其對應(yīng)的binlog文件發(fā)送給從庫,也就是主庫只發(fā)送從庫沒有接收到的事務(wù)今妄。所有的信息由MySQL集群自動獲取完成郑口,不需要人為干預(yù)鸳碧,大大簡化了復(fù)制搭建過程。
如果主庫要發(fā)送給從庫的GTID所在的binlog已經(jīng)被清除了犬性,或者這些gtid已經(jīng)被添加到gtid_purged瞻离,那么主庫將發(fā)送錯誤信息給從庫,復(fù)制將會中斷乒裆。通常發(fā)生這種情況時套利,從庫可以更換復(fù)制源,或者使用最新的備份來重建復(fù)制鹤耍。也可以考慮修改增加主庫binlog文件的過期時間來減少這種情況的發(fā)生肉迫。
如果從庫已經(jīng)接收到的gtid 比主庫的gtid要多,那么主庫也將發(fā)送錯誤信息給從庫稿黄,同時復(fù)制中斷喊衫。這種情況一般是主庫沒有設(shè)置 sync_binlog=1 ,此時主庫發(fā)生斷電杆怕、宕機等故障族购,導(dǎo)致主庫的binlog沒有刷到磁盤,而從庫已經(jīng)接收到了主庫的binlog财著。這種情況一般需要人工介入解決联四,所以推薦更安全的sync_binlog=1 撑碴。
基于GTID的復(fù)制搭建:
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3306,MASTER_USER='repl', MASTER_PASSWORD='123456',MASTER_AUTO_POSITION=1;
基于Binlog+Position的復(fù)制搭建:
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=524;
GTID相關(guān)函數(shù):
GTID_SUBSET(set1,set2)
如果set1是set2的子集撑教,返回true,否則返回false
GTID_SUBTRACT(set1,set2)
返回set1與set2的差集醉拓,即GTID在set1中伟姐,不在set2中。
WAIT_FOR_EXECUTED_GTID_SET(gtid_set[,?timeout])
等待GTID執(zhí)行到某一個位置亿卤,如果指定timeout參數(shù)愤兵,在timeout時間之內(nèi),gtid沒有執(zhí)行到該位置 排吴,則報錯返回秆乳。
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(gtid_set[,?timeout][,channel])
等待復(fù)制線程(SQL_Thread)執(zhí)行GTID到某一個位置,同樣可以指定超時時間timeout钻哩。