深入理解MySQL 5.7 GTID系列(二):GTID相關內部資料結構
作者:高鵬(重慶八怪)
原文地址:
https://www.jianshu.com/p/5649644fdc13
深入理解MySQL 5.7 GTID系列文章共十篇,本文為第二篇,
該系列文章將陸續不定期更新~
一、 GTID基本格式
單個 GTID:
前一部分是SERVER_UUID,後面一部分是執行事務的唯一標誌,通常是自增的。內部使用 GTID這種資料結構表示,後面會描述。
區間 GTID:
前一部分是SERVER_UUID,後面一部分是執行事務的唯一標誌集合,在內部使用GTID_SET中某個SIDNO對應的INTERVAL節點表示,後面會描述。
二、SERVER_UUID的生成
既然說到了SERVER_UUID這裡就開始討論SERVER_UUID的生成。
SERVER_UUID實際上是一個32位元組+1位元組(/0)的字串。MySQL啟動的時候會呼叫INIT_SERVER_AUTO_OPTIONS()讀取AUTO.CNF檔案。如果沒有讀取到則呼叫GENERATE_SERVER_UUID()呼叫生成一個SERVER_ID。
實際上在這個函式裡面會看到SERVER_UUID至少和下面部分有關:
MySQL啟動時間
執行緒LWP有關
一個隨機的記憶體地址有關
請看程式碼片段:
獲得這些資訊後會進入Item_func_uuid::val_str做運算返回,有興趣的朋友可以深入看一下,最終會生成一個SERVER_UUID並且拷貝到實際的SERVER_UUID中如下:
呼叫棧幀:
三、SERVER_UUID的內部表示BINARY_LOG::UUID
BINARY_LOG::UUID是SERVER_UUID的內部表示實際上核心就是一個16位元組的記憶體空間,如下:
SERVER_UUID和BINARY_LOG::UUID之間可以互相轉換,在SID_MAP中BINARY_LOG::UUID表示的SERVER_UUID實際上就是其SID。
四、類結構GTID
本結構是單個GTID的內部表示其核心元素包括:
其中gno就是我們說的事務唯一標誌,而SIDNO其實是SERVER_UUID的內部表示BINARY_LOG::UUID(SID)通過HASH演算法得出的一個查詢表中的值。參考函式SID_MAP::ADD_SID本函式則根據BINARY_LOG::UUID(SID)返回一個SIDNO。
五、類結構SID_MAP
既然說到了HASH演算法那麼需要一個內部結構來儲存這種整個hash查詢表,在MySQL中使用SID_MAP來作為這樣一個結構,其中包含一個可變陣列和一個HASH查詢表其作用用來已經在註釋裡面給出。全域性只有一個SID_MAP。會在GTID模組初始化的時候分配記憶體。SID_MAP核心元素如下:
這裡在看一下可變陣列中的指標元素NODE的型別:
其實他就是一個SIDNO和SID的對應。
六、類結構GTID_SET
本結構是一個關於某種型別GTID總的集合,比如我們熟知的有EXECUTE_GTID集合,PURGE_GTID集合。我們知道在一個EXECUTE_GTID集合中可能包含多個數據庫的GTID也就是多個SIDNO同時存在的情況,並且可能存在某個資料庫的GTID出現區間的情況如下:
這裡3558703b-de63-11e7-91c3-5254008768e3的GNO出現了多個區間:
1-6
20-30
那麼這種情況下內部表示應該是陣列加區間連結串列的方式,當然MySQL內部正是這樣實現的。我們來看核心元素:
7、GTID_SET的關聯類結構INTERVAL
它正是前面說到的表示GTID區間如下:
da267088-9c22-11e7-ab56-5254008768e3:1-34
他的內部類就是INTERVAL類結構我們看一下核心元素就懂了:
非常簡單起始GNO加一個NEXT指標,標示了一個區間。
8、類結構GTID_STATE
本結構也是在資料庫啟動的時候和SID_MAP一起進行初始化,也是一個全域性的變數。
我們熟知的引數幾個引數如下:
GTID_EXECUTED
GTID_OWNED
GTID_PURGED
都來自於次,當然除了以上的我們常見的還包含了其他一些核心元素我們來具體看看:
9、類結構 OWNED_GTIDS
這個結構包含當前執行緒所包含的所有正在持有的GTID集合,為事務分配GTID會先將這個GTID和執行緒號加入到給OWNED_GTIDS然後將執行緒的THD->OWNED_GTID指向這個GTID。
參考函式GTID_STATE::ACQUIRE_OWNERSHIP,在COMMIT的最後階段會將這個GTID從OWNED_GTIDS中移除參考函式OWNED_GTIDS::REMOVE_GTID並且將他加入到GTID_STATE::EXECUTED_GTIDS中。
這個過程會在後面進行描述。其核心元素包括:
這樣一個每個SIDNO都會有HASH結構其HASH的內容則是:
這樣一個結構體,我們看到其中包含了GNO和執行緒ID。
十、類結構GTID_TABLE_PERSISTOR
本結構主要是包含一些操作MySQL.GTID_EXECUTED表的函式介面
主要包含:
Insert the gtid into table.int save(THD *thd, const Gtid *gtid);
Insert the gtid set into table.int save(const Gtid_set *gtid_set);
Delete all rows from the table.int reset(THD *thd);
Fetch gtids from gtid_executed table and store them into
gtid_executed set.int fetch_gtids(Gtid_set *gtid_set);
Compress the gtid_executed table completely by employing one or more transactions.int compress(THD *thd);
Write a gtid interval into the gtid_executed table.
int write_row(TABLE *table, const char *sid,rpl_gno gno_start, rpl_gno gno_end);Update a gtid interval in the gtid_executed table.
int update_row(TABLE *table, const char *sid,rpl_gno gno_start, rpl_gno new_gno_end);Delete all rows in the gtid_executed table.int delete_all(TABLE *table);
這些方法也是確定什麼時候讀/寫MySQL.GTID.EXECUTED的斷點。
十一、內部結構圖示
為了能夠用圖的方式解釋這些類結構之間的關係,我修改MySQL.GTID_EXECUTED表和AUTO.CNF構造出了這種有區間的GTID案例,同時在原始碼處增加列印程式碼將啟動完成後的get_executed_gtids/get_lost_gtids/get_gtids_only_in_table/get_previous_gtids_logged輸出到了日誌。但是在線上情況下很難見到這種有區間的GTID。
假設某一時刻我們資料庫啟動後各種GTID如下():
2017-12-12T04:10:42.768153Z 0 [Note] gtid_state->get_executed_gtids:
Gtid have:3558703b-de63-11e7-91c3-5254008768e3:1-35,
da267088-9c22-11e7-ab56-5254008768e3:1-342017-12-12T04:10:42.768191Z 0 [Note] gtid_state->get_lost_gtids:
Gtid have:3558703b-de63-11e7-91c3-5254008768e3:1-6:20-30,
da267088-9c22-11e7-ab56-5254008768e3:1-342017-12-12T04:10:42.768226Z 0 [Note] gtid_state->get_gtids_only_in_table:
Gtid have:3558703b-de63-11e7-91c3-5254008768e3:1-6:20-30,
da267088-9c22-11e7-ab56-5254008768e3:1-342017-12-12T04:10:42.768260Z 0 [Note] gtid_state->get_previous_gtids_logged:Gtid have:3558703b-de63-11e7-91c3-5254008768e3:7-19:31-35
啟動後我們馬上執行了一個事務,這個事務正處於ORDERED_COMMIT的FLUSH階段由GTID_STATE::ACQUIRE_OWNERSHIP獲得了一個GTID那麼它正在OWNED_GTIDS中,所以這個時候的圖如下:
十二、本文小結
學習完本節至少能夠學習到:
1、SERVER_UUID是什麼,如何生成,按照什麼規則生成
2、GTID內部是如何表示
3、SERVER_UUID和GTID內部表示之間的聯絡
4、 GTID_EXECUTED/GTID_OWNED/GTID_PURGED表示了什麼具體對應哪個記憶體結構,當然這些將在後面的文章中多次提到,也會加深對它的瞭解。
如果有原始碼閱讀能力的朋友可以按照這個框架繼續深入學習。
對本文有任何疑問可掃碼新增原文作者微信
知數堂
葉金榮與吳炳錫聯合打造
領跑IT精英培訓
行業資深專家強強聯合,傾心定製
MySQL實戰/MySQL優化 / Python/ SQL優化
數門精品課程
緊隨技術發展趨勢,定期優化培訓教案
融入大量生產案例,貼合企業一線需求
社群陪伴學習,一次報名,可學3期
DBA、開發工程師必修課
上千位學員已華麗轉身,薪資翻番,職位提升
改變已悄然發生,你還在等什麼?
掃碼下載知數堂精品課程試聽視訊
(MySQL 實戰/優化、Python開發,及SQL優化等課程)
密碼:hg3h