從MySQL 5.6.5 開始新增了一種基於 GTID 的復制方式。通過 GTID 保證了每個在主庫上提交的事務在集群中有一個唯一的ID。這種方式強化了數據庫的主備一致性,故障恢復以及容錯能力。
GTID (Global Transaction ID)是全局事務ID,當在主庫上提交事務或者被從庫應用時,可以定位和追蹤每一個事務,對DBA來說意義就很大了,我們可以適當的解放出來,不用手工去可以找偏移量的值了,而是通過CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION=1的即可方便的搭建從庫,在故障修復中也可以采用MASTER_AUTO_POSITION=‘X’的方式。
可能大多數人第一次聽到GTID的時候會感覺有些突兀,但是從架構設計的角度,GTID是一種很好的分布式ID實踐方式,通常來說,分布式ID有兩個基本要求:
1)全局唯一性
2)趨勢遞增
這個ID因為是全局唯一,所以在分布式環境中很容易識別,因為趨勢遞增,所以ID是具有相應的趨勢規律,在必要的時候方便進行順序提取,行業內適用較多的是基於Twitter的ID生成算法snowflake,所以換一個角度來理解GTID,其實是一種優雅的分布式設計。
1。如何開啟GTID
如何開啟GTID呢,我們先來說下基礎的內容,然后逐步深入,通常來說,需要在my.cnf中配置如下的幾個參數:
①log-bin=mysql-bin
②binlog_format=row
③log_slave_updates=1
④gtid_mode=ON
⑤enforce_gtid_consistency=ON
其中參數log_slave_updates在5.7中不是強制選項,其中最重要的原因在於5.7在mysql庫下引入了新的表gtid_executed。
在開始介紹GTID之前,我們換一種思路,通常我們都會說一種技術和特性能干什么,我們了解一個事物的時候更需要知道邊界,那么GTID有什么限制呢,這些限制有什么解決方案呢,我們來看一下。
2。 GTID的限制和解決方案
如果說GTID在5.6試水,在5.7已經發展完善,但是還是有一些場景是受限的。比如下面的兩個。
一個是create table xxx as select 的模式;另外一個是臨時表相關的,我們就來簡單說說這兩個場景。
1)create 語句限制和解法
create table xxx as select的語句,其實會被拆分為兩部分,create語句和insert語句,但是如果想一次搞定,MySQL會拋出如下的錯誤。
mysql> create table test_new as select *from test;
ERROR 1786 (HY000): Statement violates GTID consistency: CREATE TABLE ... SELECT.
這種語句其實目標明確,復制表結構,復制數據,insert的部分好解決,難點就在於create table的部分,如果一個表的列有100個,那么拼出這么一個語句來就是一個工程了。
除了規規矩矩的拼出建表語句之外,還有一個方法是MySQL特有的用法 like。
create table xxx as select 的方式可以拆分成兩部分,如下。
create table xxxx like data_mgr;
insert into xxxx select *from data_mgr;
2)臨時表的限制和建議
使用GTID復制模式時,不支持create temporary table 和 drop temporary table。但是在autocommit=1的情況下可以創建臨時表,Master端創建臨時表不產生GTID信息,所以不會同步到slave,但是在刪除臨時表的時候會產生GTID會導致,主從中斷.
3。 從三個視角看待GTID
前面聊了不少GTID的內容,我們來看看GTID的一個體系內容,如下是我梳理的一個GTID的概覽信息,分別從變量視圖,表和文件視圖,操作視圖來看待GTID.

我們分別從每個視圖來簡單說下:
1)變量視圖
我們來用下面的表格來闡述下常見的這幾個變量

2)表和文件視圖
先來說下文件層面的關聯,根據MySQL的復制原理,MySQL Server在寫binlog的時候,會先寫一個特殊的Binlog Event,類型為GTID_Event,指定下一個事務的GTID,然后再寫事務的Binlog,主從同步時GTID_Event和事務的Binlog都會傳遞到從庫,在從庫應用Relay Log,從庫在執行的時候也是用同樣的GTID寫binlog.
然后說一下表mysql.gtid_executed,在5.6版本中必須要設置log_slave_updates,因為當slave重啟后,無法得知當前slave已經運行到的GTID位置,因為變量gtid_executed是一個內存值,而這個問題在5.7中通過表mysql.gtid_executed把這個值持久化來得以解決,也就意味着log_slave_updates是一個可選項。
此外,引入該解決方案之后又帶來了新的問題,那就是在gtid_executed里面的數據會越來越多,如何精簡管理呢,MySQL引入了一個新的線程和參數來進行管理。
線程為:thread/sql/compress_gtid_table,可以查詢performance_schema.threads來查看。
參數為 gtid_executed_compression_period ,主要用於控制每執行多少個事務,對表gtid_executed進行壓縮,默認值為:1000 。
3)操作視圖
對於操作,我們列舉了較為簡單常規的操作方式,為了避免歧義,我對一些命令做了取舍。
這些主要是在搭建主從復制關系時所用,基本都是一次開啟,長期生效的方式。
如果是修復主從復制中的異常,如果是在確認錯誤可以跳過的情況下,可以使用如下的方式:
l stop slave;
l set gtid_next='xxxxxxx:N'; --指定下一個事務執行的版本,即想要跳過的GTID
l begin;
l commit; --注入一個空事物
l set gtid_next='AUTOMATIC' --自動的尋找GTID事務。
l start slave; --開始同步