當前位置:編程學習大全網 - 源碼下載 - mysql中如何從binlog文件中提取第壹個事務的gtid

mysql中如何從binlog文件中提取第壹個事務的gtid

MySQL 5.6全局事務ID(GTID)實現原理(三)這是MySQL 5.6全局事務ID(GTID)系列的第三篇博客。

前面兩篇博客,第壹篇?本文介紹了全局事務ID的定義和數據結構。第二條?本文介紹了MySQL 5.6中新的全局事務狀態(Gtid_state)。

這裏要介紹的是全局事務ID是如何參與MySQL的主次復制過程的。

MySQL 5.6中引入全局事務ID的首要目的是保證Slave在復制時不會重復相同的事務操作;其次,用全局事務id代替由文件名和物理偏移量組成的復制站點,定位從站需要復制的binlog內容。

因此,MySQL在編寫binlog時必須記錄每個事務的全局GTID,以保證主/從可以根據這些GTID忽略或執行相應的事務。在實現中,MySQL沒有修改舊的binlog事件,而是添加了兩種類型的事件:

+ - +.函數|+ - +|+ - +.|+ - + - +Gtid_log_event

在MySQL 5.6的binlog文件中,每個事務的開始不是“begin”,而是壹個Gtid_log_event事件:

(來源:MySQL _ innovation _ day _ replication _ ha.pdf?)它只包含壹個GTID,記錄結構如下:

Gtid _ log _ event: = (commit _ flag,sid,gno)//commit _ flag目前始終為true,其中sid是生成事務的server_uuid,gno是按順序編號的transaction_id。

在事務開始時記錄Gtid是為了MySQL過濾binlog:當不需要Gtid時,可以直接忽略整個後續事務。

MySQL 5.6保證同時寫Gtid_log_event和global logged_gtids狀態:

首先,在將第壹個binlog寫入binlog_cache_data之前,MySQL會在緩存的緩沖區中寫入壹個空的Gtid_log_event占位符。

第二步:當binlog_cache_data的內容被刷入binlog文件時,MySQL會將緩存緩沖區中Gtid_log_event的內容替換為實際的Gtid,並在緩存中重寫。

最後,MySQL調用Gtid_state的update_on_flush()將Gtid寫入logged_gtids,然後調用sync_binlog_file()確保內容更新到磁盤。

在主從復制中,從不會像主壹樣自動生成GTID,而是直接復制Gtid_log_event中包含的GTID。這個特性是這樣實現的:MySQL 5.6維護壹個會話級變量gtid_next,類型為Gtid_specification:

Gtid _ specification:=(enum _ GROUP _ type,Gtid)enum _ GROUP _ type:= enum(AUTOMATIC_GROUP,GTid_GROUP,ANONYMOUS_GROUP,INVALID_GROUP,UNDEFINED_GROUP)當Master執行壹個事務時,gtid_next的類型默認為AUTOMATIC _ GROUP,也就是說要調用generate_automatic_gno()來自動生成全局事務ID。

從機執行事務時,首先用Gtid_log_event中的Gtid覆蓋Gtid _ next,使其類型為GTID_GROUP。在這種情況下,MySQL將使用gtid_next中設置的Gtid值作為下壹個全局事務id。

Previous_gtids_log_event

在MySQL 5.6中,該事件出現在每個binlog文件的開頭。

MySQL創建壹個新的binlog文件後,先寫壹個Format_description_log_event的描述,再寫壹個Previous_GTIDs_log_event的描述,這是創建這個binlog文件前執行的全局事務GTIDs。

事件的格式很簡單,就是壹個字符串編碼的Gdit_set:(編碼格式請參考本文第壹篇?)previous _ gtids _ log _ event:= gtid _ set的緩沖區(例如:3e 11fa 47-711e 1-9e 33-c80a 9429562)。當主設備和備用設備復制時,從設備將忽略binlog中的Previous_gtids_log_event事件。

Binlog和持久全局事務狀態

上壹篇文章裏?沒有談到MySQL 5.6如何持久化全局事務狀態logged _ GTIDs和lost_gtids狀態存儲了這個數據庫曾經執行過的所有gtid(包括刪除binlog中的gtid)——如果數據庫在停止或者崩潰之前沒有持久化,那麽事後肯定會丟失信息。

MySQL的解決方案很簡單,啟動時掃描剩余的binlog文件,用文件中存儲的Previous_gtids_log_event和Gtid_log_event的內容恢復全局logged_gtids和lost_gtids狀態。

具體代碼如下:(源代碼:mysql-5.6.9-rc\sql\binlog.cc,第2558行)第壹步,找到最後壹個binlog文件,讀取Previous_gtids_log_event記錄;然後遍歷binlog文件中的所有GTID _ log _ events,將找到的GTID記錄合並放入global logged _ GTIDs記錄中,作為這個數據庫歷史上執行過的所有GTID;第二步,找到第壹個binlog文件,將全局lost_gtids的內容替換為其Previous_gtids_log_event信息。因為這是第壹個沒有被刪除的binlog文件,所以之前被刪除的binlog文件中包含的所有GTIDs都被記錄在這裏。

由於MySQL在事務提交結束時寫入真實的Gtid_log_event信息,所以從binlog中恢復信息可以保證讀取的Gtid與成功執行的事務壹致。

將母版更改為...

MySQL 5.6主備復制的壹個變化是增加了COM_binlog_DUMP_GTID協議,支持從切換到新的主時,用Master _ AUTO _ POSITION = 1(AUTO _ POSITION模式)替換原來的binlog文件名和物理偏移量。

COM_BINLOG_DUMP_GTID協議並不復雜,請求格式如下:

Request = {服務器標識,二進制日誌名稱,二進制日誌偏移量,全局標識號已執行}

如果主機通過auto_position連接,那麽從機發送的binlog_name和binlog_offset都是空的,主機只使用gtids_executed定位要在從機上執行的binlog。

實現邏輯如下:主從第壹個文件讀取binlog,逐個檢查從發送的gtids_executed集合中是否包含Gdit_log_event事件的全局事務ID。如果發現該GTID已經包含在gtids_executed集合中,則整個後續事務將被忽略,binlog內容將不會發送到從機。

其實這個過程並不是很優化,因為如果正常的話,主需要遍歷好幾個g binlogs才能找到Slave需要復制的binlog內容——這應該是壹個進步。

全局事務ID和並發復制

MySQL 5.6主備復制的另壹個變化是多線程並行復制的實現。此功能必須由全局事務ID支持,因為:

1)在並行復制模式下,某些操作不會按照binlog中記錄的順序執行。這樣,如果復制站點是以文件名+物理偏移量的方式記錄的,那麽在主副復制停止/恢復時,可能會重復壹些操作。

2)我們知道,即使對於混合/行模式記錄的binlog,仍然有壹些語句編碼的DDL操作,這些DDL操作在Slave中是不能重復的(因為它們不是冪等的)。壹旦從機操作出錯,結果就是復制中斷。

因此,從服務器必須依賴binlog中的全局事務ID,並在停止/恢復主備復制時準確記錄哪些事務在從服務器中執行,哪些事務沒有執行。

現在,MySQL 5.6可以使用COM_binlog_DUMP_GTID來確保這壹點:當主復制和輔助復制恢復時,Slave會將其執行的所有GTID(logged _ GTID)發送給Master。上壹次主備復制中斷時,已經執行的binlog被主設備直接過濾,不會傳輸到從設備。

摘要

MySQL 5.6為活動和備用復制添加了三個新特性:

1)使用Gtid作為主復制和輔助復制的站點,並在寫入binlog時用Gtid_log_event標記事務。

2)支持主備切換的auto_position模式。在新添加的協議中,GTIDs用作復制站點,從主庫請求binlog信息。

3)多線程並發復制,使用GTIDs防止事務重復執行。

全局事務ID(GTID)可以很好地支持這些功能。而且GTIDs的使用避免了傳輸binlog時對文件名和物理偏移量的邏輯依賴,可以更好地支持自動容災切換。

但個人認為,全局事務ID還有壹些問題需要解決:

1)GTID是本地訂購,無法記錄交易的全球訂單。所以在雙寫/快速主備切換場景下,更新沖突的問題無法按照GTID順序解決。

2)切換容災時,MASTER_AUTO_POSITION只能解決記錄站點的問題。為了保證壹致性,仍然需要停止寫入並等待主備用趕上,這通常是服務無法快速恢復的主要原因。

  • 上一篇:中外期貨公司前二十名各自排名
  • 下一篇:什麽樣的面相有福氣,女人非富即貴?
  • copyright 2024編程學習大全網