溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Mysql 5.7中Gtid相關(guān)內(nèi)部數(shù)據(jù)結(jié)構(gòu)有哪些

發(fā)布時(shí)間:2021-11-12 14:42:25 來(lái)源:億速云 閱讀:128 作者:iii 欄目:MySQL數(shù)據(jù)庫(kù)

本篇內(nèi)容介紹了“Mysql 5.7中Gtid相關(guān)內(nèi)部數(shù)據(jù)結(jié)構(gòu)有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

1、 Gtid基本格式

  • 單個(gè)Gtid:

 e859a28b-b66d-11e7-8371-000c291f347d:1

前一部分是server_uuid,后面一部分是執(zhí)行事物的唯一標(biāo)志,通常是自增的。內(nèi)部使用Gtid這種數(shù)據(jù)結(jié)構(gòu)表示,后面會(huì)描述。

  • 區(qū)間Gtid:

e859a28b-b66d-11e7-8371-000c291f347d:1-5

前一部分是server_uuid,后面一部分是執(zhí)行事物的唯一標(biāo)志集合,在內(nèi)部使用Gtid_set中某個(gè)Sidno對(duì)應(yīng)的Interval節(jié)點(diǎn)表示,后面會(huì)描述。

2、server_uuid的生成

既然說(shuō)到了server_uuid這里就開(kāi)始討論server_uuid的生成。server_uuid實(shí)際上是一個(gè)32字節(jié)+1字節(jié)(/0)的字符串。Mysql啟動(dòng)的時(shí)候會(huì)調(diào)用init_server_auto_options() 讀取auto.cnf文件。如果沒(méi)有讀取到則調(diào)用generate_server_uuid()調(diào)用生成一個(gè)server_id。
實(shí)際上在這個(gè)函數(shù)里面會(huì)看到server_uuid至少和下面部分有關(guān):

  • 1、mysql啟動(dòng)時(shí)間

  • 2、線程Lwp有關(guān)

  • 3、一個(gè)隨機(jī)的內(nèi)存地址有關(guān)

請(qǐng)看代碼片段:

 const time_t save_server_start_time= server_start_time; //獲取Mysql 啟動(dòng)時(shí)間
  server_start_time+= ((ulonglong)current_pid << 48) + current_pid;//加入Lwp號(hào)運(yùn)算
  thd->status_var.bytes_sent= (ulonglong)thd;//這是一個(gè)內(nèi)存指針

  lex_start(thd);
  func_uuid= new (thd->mem_root) Item_func_uuid();
  func_uuid->fixed= 1;
  func_uuid->val_str(&uuid);     //這個(gè)函數(shù)里面有具體的運(yùn)算過(guò)程

獲得這些信息后會(huì)進(jìn)入Item_func_uuid::val_str做運(yùn)算返回,有興趣的朋友可以深入看一下,最終會(huì)生成一個(gè)server_uuid并且拷貝到實(shí)際的server_uuid中如下:

strncpy(server_uuid, uuid.c_ptr(), UUID_LENGTH);

調(diào)用棧幀:

#0  init_server_auto_options () at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:3810
#1  0x0000000000ec625e in mysqld_main (argc=97, argv=0x2e9af08) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:4962
#2  0x0000000000ebd604 in main (argc=10, argv=0x7fffffffe458) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25

3、server_uuid的內(nèi)部表示binary_log::Uuid

binary_log::Uuid是server_uuid的內(nèi)部表示實(shí)際上核心就是一個(gè)16字節(jié)的內(nèi)存空間,如下:

 /** The number of bytes in the data of a Uuid. */
  static const size_t BYTE_LENGTH= 16;
  /** The data for this Uuid. */
  unsigned char bytes[BYTE_LENGTH];

server_uuid和binary_log::Uuid之間可以互相轉(zhuǎn)換,在Sid_map中binary_log::Uuid表示的server_uuid實(shí)際上就是其sid。

4、類結(jié)構(gòu)Gtid

本結(jié)構(gòu)是單個(gè)Gtid的內(nèi)部表示其核心元素包括:

 /// SIDNO of this Gtid.
  rpl_sidno sidno;
  /// GNO of this Gtid.
  rpl_gno gno;

其中g(shù)no就是我們說(shuō)的事物唯一標(biāo)志,而sidno其實(shí)是server_uuid的內(nèi)部表示binary_log::Uuid (sid)通過(guò)hash算法得出的一個(gè)查找表中的值。參考函數(shù)Sid_map::add_sid本函數(shù)則根據(jù)binary_log::Uuid (sid)返回一個(gè)sidno。

5、類結(jié)構(gòu)Sid_map

既然說(shuō)到了hash算法那么需要一個(gè)內(nèi)部結(jié)構(gòu)來(lái)存儲(chǔ)這種整個(gè)hash查找表,在Mysql中使用Sid_map來(lái)作為這樣一個(gè)結(jié)構(gòu),其中包含一個(gè)可變數(shù)組和一個(gè)hash查找表其作用用來(lái)已經(jīng)在注釋里面給出。全局只有一個(gè)Sid_map。會(huì)在Gtid模塊初始化的時(shí)候分配內(nèi)存。Sid_map核心元素如下:

/// Read-write lock that protects updates to the number of SIDNOs.
  mutable Checkable_rwlock *sid_lock;

  /**
    Array that maps SIDNO to SID; the element at index N points to a
    Node with SIDNO N-1.
  */
  Prealloced_array_sidno_to_sid; //因?yàn)閟idno是一個(gè)連續(xù)的數(shù)值那么更具sidno找到sid只需要簡(jiǎn)單的做
                                                 //數(shù)組查找即可這里將node指針存入
  /**
    Hash that maps SID to SIDNO.  The keys in this array are of type
    rpl_sid.
  */
  HASH _sid_to_sidno;                           //因?yàn)閟id是一個(gè)數(shù)據(jù)結(jié)構(gòu)其核心為bytes關(guān)鍵值存儲(chǔ)了16字節(jié)根據(jù)server_uuid
                                                //轉(zhuǎn)換而來(lái)的無(wú)規(guī)律內(nèi)存空間,需要使用hash查找表快速定位
  /**
    Array that maps numbers in the interval [0, get_max_sidno()-1] to
    SIDNOs, in order of increasing SID.

    @see Sid_map::get_sorted_sidno.
  */
  Prealloced_array _sorted;//額外的一個(gè)關(guān)于sidno的數(shù)組,具體作用未知

這里在看一下可變數(shù)組中的指針元素Node的類型:

 struct Node
  {
    rpl_sidno sidno; //sid hash no
    rpl_sid sid; //sid
  };

其實(shí)他就是一個(gè)sidno和sid的對(duì)應(yīng)。

6、類結(jié)構(gòu)Gtid_set

本結(jié)構(gòu)是一個(gè)關(guān)于某種類型Gtid總的集合,比如我們熟知的有execute_gtid集合,purge_gtid集合。我們知道在一個(gè)execute_gtid集合中可能包含多個(gè)數(shù)據(jù)庫(kù)的Gtid也就是多個(gè)sidno同時(shí)存在的情況,并且可能存在某個(gè)數(shù)據(jù)庫(kù)的Gtid出現(xiàn)區(qū)間的情況如下:

| gtid_executed                    | 
3558703b-de63-11e7-91c3-5254008768e3:1-6:20-30,
da267088-9c22-11e7-ab56-5254008768e3:1-34 |

這里3558703b-de63-11e7-91c3-5254008768e3的Gno出現(xiàn)了多個(gè)區(qū)間:

  • 1-6

  • 20-30

那么這種情況下內(nèi)部表示應(yīng)該是數(shù)組加區(qū)間鏈表的方式,當(dāng)然Mysql內(nèi)部正是這樣實(shí)現(xiàn)的。我們來(lái)看核心元素:

/**
    Array where the N'th element contains the head pointer to the
    intervals of SIDNO N+1.
  */
  Prealloced_array m_intervals;//每個(gè)sidno 包含一個(gè)Interval 單項(xiàng)鏈表,由next指針連接 這就完成了比如分割GTID的問(wèn)題
  /// Linked list of free intervals.
  Interval *free_intervals;  //空閑的interval連接在這個(gè)鏈表上
  /// Linked list of chunks.
  Interval_chunk *chunks; //全局的一個(gè)Interval 鏈表 所有的Interval空間都連接在上面

7、Gtid_set的關(guān)聯(lián)類結(jié)構(gòu)Interval

它正是前面說(shuō)到的表示Gtid區(qū)間如下:

  • da267088-9c22-11e7-ab56-5254008768e3:1-34

他的內(nèi)部類就是Interval類結(jié)構(gòu)我們看一下核心元素就懂了:

 /// The first GNO of this interval.
    rpl_gno start;
    /// The first GNO after this interval.
    rpl_gno end;
    /// Pointer to next interval in list.
    Interval *next;

非常簡(jiǎn)單起始Gno加一個(gè)next指針,標(biāo)示了一個(gè)區(qū)間。

8、類結(jié)構(gòu)Gtid_state

本結(jié)構(gòu)也是在數(shù)據(jù)庫(kù)啟動(dòng)的時(shí)候和Sid_map一起進(jìn)行初始化,也是一個(gè)全局的變量。
我們熟知的參數(shù)幾個(gè)參數(shù)如下:

  • gtid_executed

  • gtid_owned

  • gtid_purged

都來(lái)自于次,當(dāng)然除了以上的我們常見(jiàn)的還包含了其他一些核心元素我們來(lái)具體看看:

/// The Sid_map used by this Gtid_state.
  mutable Sid_map *sid_map; //使用sid_map
  /**
    The set of GTIDs that existed in some previously purged binary log.
    This is always a subset of executed_gtids.
  */
  Gtid_set lost_gtids; //對(duì)應(yīng)gtid_purged參數(shù),這個(gè)參數(shù)一般由Mysql自動(dòng)維護(hù)除非手動(dòng)設(shè)置了gtid_purged參數(shù)
  /*
    The set of GTIDs that has been executed and
    stored into gtid_executed table.
  */
  Gtid_set executed_gtids; //對(duì)應(yīng)gtid_executed參數(shù),這個(gè)參數(shù)一般由Mysql主動(dòng)維護(hù)
  /*
    The set of GTIDs that exists only in gtid_executed table, not in
    binlog files.
  */
  Gtid_set gtids_only_in_table;
//正常來(lái)講對(duì)于主庫(kù)這個(gè)集合始終為空因?yàn)橹鲙?kù)不可能存在只在mysql.gtid_executed表而不再binlog中的gtid,但是從庫(kù)則必須開(kāi)啟log_slave_updates和binlog才會(huì)達(dá)到這個(gè)效果,
//否則binlog不包含relay的Gtid的只能包含在mysql.gtid_executed表中,那么這種情況下Gtid_set gtids_only_in_table是始終存在的。具體后面還會(huì)解釋。
  /* The previous GTIDs in the last binlog. */
  Gtid_set previous_gtids_logged;//包含上一個(gè)binlog已經(jīng)執(zhí)行的所有的在binlog的Gtid
  /// The set of GTIDs that are owned by some thread.
  Owned_gtids owned_gtids;//當(dāng)前所有線程擁有的全部Gtid集合
  /// The SIDNO for this server.
  rpl_sidno server_sidno;//就是服務(wù)器server_uuid對(duì)應(yīng)sid hash出來(lái)的sidno

9、類結(jié)構(gòu) Owned_gtids

這個(gè)結(jié)構(gòu)包含當(dāng)前線程所包含的所有正在持有的Gtid集合,為事物分配Gtid 會(huì)先將這個(gè)Gtid和線程號(hào)加入到給Owned_gtids然后將線程的thd->owned_gtid指向這個(gè)Gtid。
參考函數(shù)Gtid_state::acquire_ownership,在commit的最后階段會(huì)將這個(gè)Gtid從Owned_gtids中移除參考函數(shù)Owned_gtids::remove_gtid 并且將他加入到Gtid_state::executed_gtids中。

這個(gè)過(guò)程會(huì)在后面進(jìn)行描述。其核心元素包括:

 /// Growable array of hashes.
  Prealloced_array sidno_to_hash;

這樣一個(gè)每個(gè)sidno都會(huì)有hash結(jié)構(gòu)其hash的內(nèi)容則是:

 struct Node
  {
    /// GNO of the group.
    rpl_gno gno;
    /// Owner of the group.
    my_thread_id owner;
  };

這樣一個(gè)結(jié)構(gòu)體,我們看到其中包含了gno和線程ID。

10、類結(jié)構(gòu)Gtid_table_persistor

本結(jié)構(gòu)主要是包含一些操作mysql.gtid_executed表的函數(shù)接口
主要包含:

  • 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);
    這些方法也是確定什么時(shí)候讀/寫(xiě)mysql.gtid_executed的斷點(diǎn)。

10、內(nèi)部結(jié)構(gòu)圖示

為了能夠用圖的方式解釋這些類結(jié)構(gòu)之間的關(guān)系,我修改mysql.gtid_executed表和auto.cnf構(gòu)造出了這種有區(qū)間的Gtid案例,同時(shí)在源碼處增加打印代碼將啟動(dòng)完成后的get_executed_gtids/get_lost_gtids/get_gtids_only_in_table/get_previous_gtids_logged輸出到了日志。但是在線上情況下很難見(jiàn)到這種有區(qū)間的Gtid。
假設(shè)某一時(shí)刻我們數(shù)據(jù)庫(kù)啟動(dòng)后各種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-34

  • 2017-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-34

  • 2017-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-34

  • 2017-12-12T04:10:42.768260Z 0 [Note] gtid_state->get_previous_gtids_logged:
    Gtid have:3558703b-de63-11e7-91c3-5254008768e3:7-19:31-35

啟動(dòng)后我們馬上執(zhí)行了一個(gè)事物,這個(gè)事物正處于ordered_commit的flush階段由Gtid_state::acquire_ownership獲得了一個(gè)Gtid那么它正在Owned_gtids中,所以這個(gè)時(shí)候的圖如下:

Mysql 5.7中Gtid相關(guān)內(nèi)部數(shù)據(jù)結(jié)構(gòu)有哪些

“Mysql 5.7中Gtid相關(guān)內(nèi)部數(shù)據(jù)結(jié)構(gòu)有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI