一、全局事物標識:global transaction identifieds。mysql
二、GTID事物是全局惟一性的,且一個事務對應一個GTID。git
三、一個GTID在一個服務器上只執行一次,避免重複執行致使數據混亂或者主從不一致。sql
四、GTID用來代替classic的複製方法,不在使用binlog+pos開啓複製。而是使用master_auto_postion=1的方式自動匹配GTID斷點進行復制。數據庫
五、MySQL-5.6.5開始支持的,MySQL-5.6.10後開始完善。安全
六、在傳統的slave端,binlog是不用開啓的,可是在GTID中,slave端的binlog是必須開啓的,目的是記錄執行過的GTID(強制)。服務器
前面是server_uuid:後面是一個序列號session
例如:server_uuid:sequence number多線程
7800a22c-95ae-11e4-983d-080027de205a:10併發
UUID:每一個mysql實例的惟一ID,因爲會傳遞到slave,因此也能夠理解爲源ID。app
Sequence number:在每臺MySQL服務器上都是從1開始自增加的序列,一個數值對應一個事務。
一、更簡單的實現failover,不用之前那樣在須要找log_file和log_Pos。
二、更簡單的搭建主從複製。
三、比傳統複製更加安全。
四、GTID是連續沒有空洞的,所以主從庫出現數據衝突時,能夠用添加空事物的方式進行跳過。
一、master更新數據時,會在事務前產生GTID,一同記錄到binlog日誌中。
二、slave端的i/o 線程將變動的binlog,寫入到本地的relay log中。
三、sql線程從relay log中獲取GTID,而後對比slave端的binlog是否有記錄。
四、若是有記錄,說明該GTID的事務已經執行,slave會忽略。
五、若是沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
六、在解析過程當中會判斷是否有主鍵,若是沒有就用二級索引,若是沒有就用所有掃描。
一、slave在接受master的binlog時,會校驗master的GTID是否已經執行過(一個服務器只能執行一次)。
二、爲了保證主從數據的一致性,多線程只能同時執行一個GTID。
[mysqld] #GTID: gtid_mode=on enforce_gtid_consistency=on server_id=2003306 #天天實例的server_id都要不同 #binlog log-bin=mysqlbin log-slave-updates=1 #容許下端接入slave binlog_format=row #強烈建議,其餘格式可能形成數據不一致 #relay log skip_slave_start=1 注意:建議使用mysql-5.6.5以上的最新版本。
一、若是是在已經跑的服務器,你須要重啓一下mysql server。
二、啓動以前,必定要先關閉master的寫入,保證全部slave端都已經和master端數據保持同步。
三、全部slave須要加上skip_slave_start=1的配置參數,避免啓動後仍是使用老的複製協議。
一、若是是新搭建的服務器,直接啓動就好了。
一、啓動之後最好不要當即執行事務,而是先change master上。
二、而後在執行事務,固然知不是必須的。
三、使用下面的sql切換slave到新的master。
stop slave; CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='repl', master_auto_position = 1;
有兩種方法:
一、若是你的master全部的binlog還在。能夠選擇相似於上面的方法,安裝slave,直接change master to到master端。
二、原理是直接獲取master全部的GTID並執行。
三、優勢:簡單方便。
四、缺點:若是binlog太多,數據徹底同步須要時間較長,而且master一開始就啓用了GTUD。
一、經過master或者其餘slave的備份搭建新的slave。(看第三部分)
二、原理:獲取master的數據和這些數據對應的GTID範圍,而後經過slave設置@@global.gtid_purged跳過備份包含的gtid。
三、優勢:是能夠避免第一種方法的不足。
四、缺點:相對來講有點複雜。
兩種方法:
一、在備份的時候指定--master-data=2(來保存binlog的文件號和位置的命令)。 二、使用mysqldump的命令在dump文件裏能夠看到下面兩個信息: SET @@SESSION.SQL_LOG_BIN=0; SET @@GLOBAL.GTID_PURGED='7800a22c-95ae-11e4-983d-080027de205a:1-8'; 三、將備份還原到slave後,使用change master to命令掛載master端。
注意:在mysql5.6.9之後的命令才支持這個功能。
一、Xtrabackup_binlog_info文件中,包含global.gtid_purged='XXXXXX:XXXX'的信息。 二、而後到slave去手工的 SET @@GLOBAL.GTID_PURGED='XXXXXX:XXXX'。 三、恢復備份,開啓change master to 命令。
注意:若是系統運行了好久,沒法找到GTID的編號了,能夠經過上面的方式進行查找。
一、這個功能主要跳過事務,代替原來的set global sql_slave_skip_counter = 1。
二、因爲在這個GTID必須是連續的,正常狀況同一個服務器產生的GTID是不會存在空缺的。因此不能簡單的skip掉一個事務,只能經過注入空事物的方法替換掉一個實際操做事務。
三、注入空事物的方法:
stop slave; set gtid_next='xxxxxxx:N'; begin;commit; set gtid_next='AUTOMATIC'; start slave;
四、這裏的xxxxx:N 也就是你的slave sql thread報錯的GTID,或者說是你想要跳過的GTID。
[master]>show global variables like '%gtid%';
一、enforce_gtid_consistency:開啓gtid的一些安全限制(介意開啓)。 二、gtid_executed:全局和seeeion級別均可以用。用來保存已經執行過的GTIDs。 貼士:show master status\G;輸出結果中的Executed_Gtid_Set和gitd_executed一致。reset master時,此值會被清空。 三、gtid_owned:全局和session級別均可用,全局表示全部服務器擁有GTIDs,session級別表示當前client擁有全部GTIDs。(此功能用的少) 四、gtid_mode:是否開啓GTID功能。 五、gtid_purged:全局參數,設置在binlog中,已經purged的GTIDs,而且purged掉的GTIDs會包含到gtid_executed中。
貼士:從而致使slave不會再去master請求這些GTIDs,而且Executed_Gtid_Set爲空時,才能夠設置此值。
六、gtid_next:這個時session級別的參數: [master]>show session variables like '%gtid_next%';
一、Case重現:
master:對一個innodb表作一個多sql更新的事物,效果是產生一個GTID。
slave:對應的表是MYISAM引擎,執行這個GTID的第一個語句後就會報錯,由於非事務引擎一個sql就是一個事務。
二、錯誤編號:
last_Errno:1756
三、異常恢復方案:
(1)、簡單的stop slave; start slave;就可以忽略錯誤。可是這個時候主從的一致性已經出現問題。須要手工的把slave差的數據補上。
(2)、首先將引擎調整爲同樣的,slave也改成事務引擎。
一、case重現:
master:直接執行一個create table select * from table;的sql
二、報錯:
error 1786
三、原理:
因爲create table ...select語句會生成兩個sql,一個是DDL建立表SQL,一個是insert into 插入數據的sql。因爲DDL會致使自動提交,因此這個sql至少須要兩個GTID,可是GTID模式下,只能給這個sql生成一個GTID,若是強制執行會致使和上面更新非事務引擎同樣的結果。
case重現:t1表是innodb,t2表是myisam
一、update t1,t2 set t1.id=1000,t2.id=1000 where t1.id=t2.id;
二、報錯:1785
三、原理和第二個相同。
一、case重現:
將一個未開啓gtid的slave經過原始的binlog和pos方式鏈接到開啓GTID的master。
二、報錯:
The slave IO thread stops because the master has @@GLOBAL.GTID_MODE ON and this server has @@GLOBAL.GTID_MODE OFF。
一、case重現:
將一個開啓gtid的slave經過原始的binlog和pos方式鏈接到開啓GTID的master。
二、報錯:
ERROR 1776(HY000):Parameters MASTER_LOG_FILE,MASTER_LOG_POS,RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active。
須要重啓才能生效,官方暫時不支持平滑的從classic replication切換到GTID replication。
貼士:
因爲GTID開啓須要重啓系統,一個複製組中全部的實例必須統一開啓或者關閉GTID,開啓GTID之後不能在使用classic複製。
問題:
也就是說在線業務必須統一關閉,而後再啓動,會致使服務中斷。
解決方案:
一、針對這種狀況,社區有兩種對應的平滑升級的方案:
一種是booking.com出品,這兩個差異在淘寶9月份數據庫月報裏有說明,加了一個橋接的服務器,既能夠運行GTID模式下,也能夠運行classic模式下。
另一種是facebook.com出品。全部的slave能夠在開啓GTID模式的狀況下,能夠鏈接到沒有開啓GTID模式的master。
二、能夠關閉一個部分,中止寫操做,可是讀不用,將另外一部分改爲GTID模式。
一、create temporary table和drop temporary table語句同樣在GTID環境下不支持。
若是--enforce_gtid_consistency參數開啓,而且autocommit=1,那麼可使用。
一、Errant transaction:所謂的errant transaction也就是沒有規範的從master執行,而是直接從slave執行的事務。
二、因爲GTID協議的緣由,最開始已經提過(參見GTID architecture)。
三、若是slave有errant transaction產生,因爲GTID協議中的規則,很容易致使failover失敗。主要有兩種狀況:
a、在slave上作了無用的或者臨時的errant transaction操做,若是該slave升級成爲master的話,鏈接到它的全部數據庫都會獲取到這個事務。若是同樣就會產生衝突。 b、因爲作了這個errant transaction這個事務之後,其餘的slave尚未獲取這個errant transaction的GTID,須要從master上發同步給其餘的slave,可是主的binlog又被刪掉了,這時將會報錯。
四、總之:儘可能避免產生errant transaction。能夠經過:set sql_log_bin=off的方式在slave執行sql,可是也要考慮到數據一致性。
··············跳過錯誤
從庫已經執行過的事務是'e10c75be-5c1b-11e6-ab7c-000c296078ae:1-5',執行出錯的事務是'e10c75be-5c1b-11e6-ab7c-000c296078ae:6',當前主備的數據實際上是一致的,能夠經過設置gtid_next跳過這個出錯的事務。
在從庫上執行如下SQL:
mysql> set gtid_next='e10c75be-5c1b-11e6-ab7c-000c296078ae:6'; Query OK, 0 rows affected (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> set gtid_next='AUTOMATIC'; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.02 sec)
設置gtid_next的方法一次只能跳過一個事務,要批量的跳過事務能夠經過設置gtid_purged完成。
crash safe slave是MySQL 5.6提供的功能,意思是說在slave crash後,把slave從新拉起來能夠繼續從Master進行復制,不會出現複製錯誤也不會出現數據不一致。
在基於binlog文件位置的複製下,要保證crash safe slave,配置下面的參數便可。
relay_log_info_repository = TABLE
relay_log_recovery = ON
這樣可行的緣由是,relay_log_info_repository = TABLE時,apply event和更新relay_log_info表的操做被包含在同一個事務裏,innodb要麼讓它們同時生效,要麼同時不生效,保證位點信息和已經應用的事務精確匹配。同時relay_log_recovery = ON時,會拋棄master_log_info中記錄的複製位點,根據relay_log_info的執行位置從新從Master獲取binlog,這就回避了因爲未同步刷盤致使的binlog文件接受位置和實際不一致以及relay log文件被截斷的問題。
在同時使用MTS(multi-threaded slave)時,爲保證crash safe slave基於binlog文件位置的複製還須要設置sync_relay_log=1,由於MySQL在Crash恢復時必須先經過讀取relay log補齊MTS致使的事務空洞。
上面的設置並不適用於基於GTID的複製。在基於GTID的複製下,crash的Slave重啓後,從binlog中解析的gtid_executed決定了要apply哪些binlog記錄,因此binlog必須和innodb存儲引擎的數據保持一致。要作到這一點,須要把sync_binlog和innodb_flush_log_at_trx_commit都設置爲1,即所謂的"雙1"。
另外MySQL啓動時,會從relay log文件中獲取已接收的GTIDs並更新Retrieved_Gtid_Set。因爲relay log文件可能不完整,因此須要拋棄已接收的relay log文件。所以relay_log_recovery = ON也是必須的。
這樣,對於基於GTID的複製,保證crash safe slave的設置就是下面這樣。
sync_binlog = 1 innodb_flush_log_at_trx_commit = 1 relay_log_recovery = ON
關於如何設置以確保crash safe slave,官方文檔有明確記載,見 17.3.2 Handling an Unexpected Halt of a Replication Slave。
可是其中關於GTID的記載中存在筆誤,將relay_log_recovery=1寫成了relay_log_recovery=0 (#83711)。同時也沒有提到必須設置"雙1",可是"雙1"是必要的,不然crash的Slave重啓後,可能會重複應用binlog event也可能會遺漏應用binlog event(#70659)。其中遺漏應用binlog event的狀況更可怕,由於Slave在不觸發SQL錯誤的狀況下就默默的和Master不一致了。
出於安全考慮,強烈推薦設置"雙1"。"雙1"會增大每一個事務的RT,但得益於MySQL的組提交機制,高併發下"雙1"對系統總體tps的影響在可接受範圍內。
sysbench oltp.lua 10張表每張表100w記錄(qps/併發數)
對更新同一行這樣沒法有效並行的場景,"雙1"對性能的影響很是大。
sysbench update_non_index.lua 1張表1條記錄(qps/併發數)
對不能有效並行的Slave replay,存在一樣的問題。
經過指定tx-rate執行sysbench的update_non_index.lua腳本壓測30秒,完成後檢查主備延遲。
能夠發如今Slave被配置爲"雙1"的狀況下,延遲很是嚴重,1000以上的QPS就會出現延遲,非"雙1"下QPS到5000以上纔會出現延遲(主庫配置爲"雙1")。
sysbench update_non_index.lua 1張表100w條記錄 128併發(延遲/qps)
以上測試環境是Percona Server 5.6運行在配置HDD的8 core虛機,因爲測試結果和系統IO能力有很大關係,僅供參考。
若是是MySQL 5.7能夠關閉log_slave_updates,這樣MySQL會將已執行的GTIDs實時記錄到系統表mysql.gtid_executed中,mysql.gtid_executed是和用戶事務一塊兒提交的,所以能夠保證和實際的數據一致。
log_slave_updates = OFF relay_log_recovery = ON
若是是MySQL 5.6能夠採用以下變通的方式。
按照基於binlog文件複製時crash safe slave的要求設置
relay_log_info_repository = TABLE relay_log_info_repository = TABLE relay_log_recovery = ON
在Slave crash後,根據relay_log_info_repository設置相應的gitd_purged再開啓複製,
步驟以下:
1.啓動MySQL,但不開啓複製 mysqld --skip-slave-start 2.在Slave上修改成基於binlog文件位置的複製 change master to MASTER_AUTO_POSITION = 0 3.啓動slave IO線程 start slave io_thread 這裏不能啓動SQL線程,若是接受到的GTID已經在Slave的gtid_executed裏了,會被Slave skip掉。 4.檢查binlog傳輸的開始位置(即Retrieved_Gtid_Set的值) show slave status\G 假設輸出的Retrieved_Gtid_Set值爲e10c75be-5c1b-11e6-ab7c-000c296078ae:7-10 5.在Master上檢查gtid_executed show master status 假設輸出的Executed_Gtid_Set值爲e10c75be-5c1b-11e6-ab7c-000c296078ae:1-10 6.在Slave上設置gitd_purged爲binlog傳輸位置的前面的GTID的集合 reset master; set global gitd_purged='e10c75be-5c1b-11e6-ab7c-000c296078ae:1-6'; 7.修改回auto position的複製 change master to MASTER_AUTO_POSITION = 1 8.啓動slave SQL線程 start slave sql_thread
可是,這種變通的方法不適合多線程複製。由於多線程複製可能產生gtid gap和Gap-free low-watermark position,這會致使Salve上重複apply已經apply過的event。後果就是數據不一致或者複製中斷,除非設置binlog格式爲row模式而且slave_exec_mode=IDEMPOTENT,slave_exec_mode=IDEMPOTENT容許Slave回放binlog時忽略重複鍵和找不到鍵的錯誤,使得binlog回放具備冪等性,但這也意味着若是真的出現了主備數據不一致也會被它忽略。
在同時使用MTS(slave_parallel_workers > 1)時,即便按上面crash safe slave的要求設置了基於GTID的複製,Slave crash後再重啓仍是會致使複製中斷。
經過強制殺掉MySQL所在虛機的方式模擬Slave宕機,而後再啓動MySQL,MySQL日誌中有以下錯誤消息:
啓動slave時也會報錯
mysql> start slave; ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
出現這種現象的緣由在於,relay_log_recovery=1 且 slave_parallel_workers>1的狀況下,mysql啓動時會進入MTS Group恢復流程,即讀取relay log,嘗試填補因爲多線程複製致使的gap。而後relay log文件因爲不是實時刷新的,在relay log文件中找不到gap對應的relay log記錄(覆蓋了gap的relay log起始和結束位置分別被稱爲低水位和高水位,低水位點即slave_relay_log_info.Relay_log_pos的值)就會報這個錯。
實際上,在GTID模式下,slave在apply event的時候能夠跳太重複事件,因此能夠安全的從低水位點應用日誌,不必解析relay log文件。 這看上去是一個bug,因而提交了一個bug報告#83713,目前尚未收到回覆。
做爲迴避方法,能夠經過清除relay log文件,跳過這個錯誤。執行步驟以下:
reset slave; change master to MASTER_AUTO_POSITION = 1 start slave;
在這裏,單純的調reset slave不能把狀態清理乾淨,內部的Relay_log_info.inited標誌位仍然處於未被初始化狀態,此時調用start slave仍然會失敗。所以須要補一刀change master。
前面一直在講crash safe slave,Master的crash safe一樣重要。 要想Master保持crash safe須要按下面的參數進行設置,不然不只會丟失事務,gtid_executed還可能和實際的innodb存儲引擎中的數據不一致。
sync_binlog = 1 innodb_flush_log_at_trx_commit = 1
在Master配置爲"雙1"的狀況下,Master crash後,若是沒有發生failover,能夠繼續做爲Master。 若是發生了failover,能夠檢查舊Master和新Master上由舊Master執行的事務集合是否一致。
show master status
若是一致,能夠按MASTER_AUTO_POSITION = 1的方式將舊Master做爲Slave和新Master創建複製關係。不然,考慮作事務補償或重新Master上拉取備份進行恢復。
在Master配置不是"雙1"的狀況下,在Master crash後因爲難以準確知道舊Master上究竟執行了哪些事務,安全的作法是實施主備切換,並重新Master上拉取備份,把舊Master做爲新Master的Slave進行恢復。