Mysql 5.7 Gtid內部學習(四) mysql.gtid_executed表Previous gtid Event的改變

gaopengtttt發表於2017-12-18

簡書地址:
http://www.jianshu.com/p/1f4f9c07ce0b

之所以把mysql.gtid_executed表的作用和Previous gtid Event的改變放到一起進行描述是因為它們後面文章探討的基礎。這部分使用到了我自己使用C語言寫的原生binlog解析工具infobin。
百度雲盤下載如下:
http://pan.baidu.com/s/1jHIWUN0

一、Gtid event

為什麼要先描述什麼是Gtid event呢?因為後面會用到,實際上在中其核心元素就是一個形如:

31704d8a-da74-11e7-b6bf-52540a7d243:100009 

的一個Gtid處於整個事物event中的開始,用於描述這個事物的Gtid是多少,當然在5.7中為了支援MTS其中還封裝了last_commit/sequence_number。那麼使用infobin工具檢視一個insert單條語句完整事物的event包括如下:

>Gtid Event:Pos:234(0Xea) N_pos:299(0X12b) Time:1513135186 Event_size:65(bytes) 
Gtid:31704d8a-da74-11e7-b6bf-52540a7d243:100009 last_committed=0  sequence_number=1
-->Query Event:Pos:299(0X12b) N_Pos:371(0X173) Time:1513135186 Event_size:72(bytes) 
Exe_time:0  Use_db:test Statment(35b-trun):BEGIN /*!Trx begin!*/ Gno:100009
---->Map Event:Pos371(0X173) N_pos:415(0X19f) Time:1513135186 Event_size:44(bytes) 
TABLE_ID:108 DB_NAME:test TABLE_NAME:a Gno:100009
------>Insert Event:Pos:415(0X19f) N_pos:455(0X1c7) Time:1513135186 Event_size:40(bytes) 
Dml on table: test.a  table_id:108 Gno:100009 
>Xid Event:Pos:455(0X1c7) N_Pos:486(0X1e6) Time:1513135186 Event_size:31(bytes) 
COMMIT; /*!Trx end*/ Gno:100009 

當然也可以使用mysqlbinlog進行分析,只是格式稍微不那麼友好。

二、gtid_executed表的作用

這一部分是重點中的重點,也是我以前一直疑惑的,請大家細細品讀。
官方文件這樣描述gtid_executed表

Beginning with MySQL 5.7.5, GTIDs are stored in a table named gtid_executed, in the mysql
database. A row in this table contains, for each GTID or set of GTIDs that it represents, the UUID of the
originating server, and the starting and ending transaction IDs of the set; for a row referencing only a
single GTID, these last two values are the same. 

也就是說gtid_executed表是Gtid持久化的一個工具,如前文所描述Gtid_state中的get_executed_gtids/get_lost_gtids/get_gtids_only_in_table/get_previous_gtids_logged這些資料都是儲存在記憶體中的,那麼在資料庫重啟後需要進行初始化,那麼這需要讀取Gtid持久化的介質,我們可以發現gtid_executed是一個innodb表建表語句如下,並且我們可以手動更改它,但是千萬不要這麼幹:

 Table: gtid_executed
Create Table: CREATE TABLE `gtid_executed` (
  `source_uuid` char(36) NOT NULL COMMENT 'uuid of the source where the transaction was originally executed.',
  `interval_start` bigint(20) NOT NULL COMMENT 'First number of interval.',
  `interval_end` bigint(20) NOT NULL COMMENT 'Last number of interval.',
  PRIMARY KEY (`source_uuid`,`interval_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 

那麼在5.7.5以前沒有gtid_executed表不是也沒有問題嗎?其實除了gtid_executed表以外我們還有一個Gtid持久化的介質那就是binlog中的Gtid event。所以總結一下Gtid持久化介質:

  • gtid_executed表
  • binlog中的gtid event

那麼既然有了binlog的gtid event進行持久化那麼為什麼還需要gtid_executed表呢?這實際上就是5.7.5過後的一個優化,我們可以反過來思考在5.6中如果使用了Gtid做從庫,從庫如果不開啟binlog並且同時設定log_slave_updates=ture那麼從庫的執行過的Gtid事物是沒有辦法持久化的。我們來一段5.6官方文件對於搭建Gtid從庫的其中一步:

Step 3: Restart both servers with GTIDs enabled. To enable binary logging with global
transaction identifiers, each server must be started with GTID mode, binary logging, slave update
logging enabled, and with statements that are unsafe for GTID-based replication disabled. In addition,
you should prevent unwanted or accidental updates from being performed on either server by starting
both in read-only mode. This means that both servers must be started with (at least) the options shown
in the following invocation of mysqld_safe:
shell> mysqld_safe --gtid_mode=ON --log-bin --log-slave-updates --enforce-gtid-consistency & 

開啟binlog同時設定設定log_slave_updates=ture必然造成一個問題,實際上從庫很多時候我們是不需要做級聯slave,設定log_slave_updates=ture會造成需要額外的空間和效能開銷。自然這種情況下我們需要另外的一種Gtid持久化介質,而並不是binlog中的Gtid event。為了解決這個問題,5.7中gtid_executed表應運而生了。然而gtid_executed表是否需要實時更新呢?顯然在slave端不開啟binlog或者開啟binlog不設定log_slave_updates=ture的情況下它需要實時更新,因為I/O thread執行過得Gtid是必須持久化的,而在主庫上因為有binlog的Gtid event的存在他是不需要實時更新的,這樣不同的對待方式也能夠減輕負擔提高效能。
同時在官方文件上也有相關描述它分為是否開始binlog進行描述,但是其描述並不是最詳細的。所以這部分在後面我會進行詳細描述。

三、Previous gtid Event的改變

Previous gtid Event是包含在每一個binlog的開頭用於描述所有以前binlog所包含的全部Gtid的一個集合(包括已經刪除的binlog)如:

da267088-9c22-11e7-ab56-5254008768e3:1-32 

在5.6中如果不開啟Gtid,那麼binlog是不會包含這個Previous gtid Event的,但是在5.7中不開啟Gtid也會包含這個Previous gtid Event,實際這一點的改變其意義也是非常巨大,簡單的說他為快速掃描binlog(binlog_gtid_simple_recovery=ture)獲得正確Gtid集合提供了基礎,否則將會掃描大量的binlog,從而浪費I/O效能,這是5.6中一個非常嚴重的問題,在5.7的官方文件這樣描述:

When binlog_gtid_simple_recovery=TRUE, which is the default in MySQL 5.7.7 and
later, the server iterates only the oldest and the newest binary log files and the values of
gtid_purged and gtid_executed are computed based only on Previous_gtids_log_event
or Gtid_log_event found in these files. This ensures only two binary log files are iterated during
server restart or when binary logs are being purged 

當然這部分也會在後面進行詳細的描述,這裡只是簡單提一下。那麼我們通過mysqlbinlog 和infobin工具分別確認這一點。

  • 5.6. 26 不開啟Gtid

mysqlbinlog:

*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#171211 16:20:10 server id 20155  end_log_pos 120 CRC32 0x12617db7      Start: binlog v 4, server v 5.6.26-74.0-log created 171211 16:20:10
# Warning: this binlog is either in use or was not closed properly.
# at 120
#171211 16:20:14 server id 20155  end_log_pos 192 CRC32 0x696752cb      Query   thread_id=30 

infobin:

------------Detail now--------------
>Format description log Event:Pos:4(0X4) N_pos:120(0X78) Time:1512980410 Event_size:116(bytes) 
-->Query Event:Pos:120(0X78) N_Pos:192(0Xc0) Time:1512980414 Event_size:72(bytes) 
Exe_time:0  Use_db:test Statment(35b-trun):BEGIN /*!Trx begin!*/ Gno:0
---->Map Event:Pos192(0Xc0) N_pos:241(0Xf1) Time:1512980414 Event_size:49(bytes) 
TABLE_ID:91 DB_NAME:test TABLE_NAME:testpo Gno:0
------>Insert Event:Pos:241(0Xf1) N_pos:281(0X119) Time:1512980414 Event_size:40(bytes) 
Dml on table: test.testpo  table_id:91 Gno:0 
>Xid Event:Pos:281(0X119) N_Pos:312(0X138) Time:1512980414 Event_size:31(bytes) 
COMMIT; /*!Trx end*/ Gno:0 

我們並沒有發現Previous gtid Event,也就是5.6如果不開啟Gtid則不包含Previous gtid Event。

  • 5.7.14

mysqlbinlog:

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#171211 16:26:49 server id 1  end_log_pos 123 CRC32 0xf9a36298  Start: binlog v 4, server v 5.7.14-7-debug-log created 171211 16:26:49
# Warning: this binlog is either in use or was not closed properly.
# at 123
#171211 16:26:49 server id 1  end_log_pos 194 CRC32 0x5865633f  **Previous-GTIDs**
# da267088-9c22-11e7-ab56-5254008768e3:1-32
# at 194 

infobin:

------------Detail now--------------
>Format description log Event:Pos:4(0X4) N_pos:123(0X7b) Time:1512980809 Event_size:119(bytes) 
>Previous gtid Event:Pos:123(0X7b) N_pos:194(0Xc2) Time:1512980809 Event_size:71(bytes) 
>Anonymous gtid Event:Pos:194(0Xc2) N_pos:259(0X103) Time:1512980814 Event_size:65(bytes) 
Gtid:Anonymous(Gno=0) last_committed=0  sequence_number=1
-->Query Event:Pos:259(0X103) N_Pos:331(0X14b) Time:1512980814 Event_size:72(bytes) 
Exe_time:0  Use_db:test Statment(35b-trun):BEGIN /*!Trx begin!*/ Gno:0
---->Map Event:Pos331(0X14b) N_pos:380(0X17c) Time:1512980814 Event_size:49(bytes) 
TABLE_ID:154 DB_NAME:test TABLE_NAME:testpo Gno:0
------>Insert Event:Pos:380(0X17c) N_pos:420(0X1a4) Time:1512980814 Event_size:40(bytes) 
Dml on table: test.testpo  table_id:154 Gno:0 
>Xid Event:Pos:420(0X1a4) N_Pos:451(0X1c3) Time:1512980814 Event_size:31(bytes) 
COMMIT; /*!Trx end*/ Gno:0 

我們清晰的看到這裡包含了Previous gtid Event,當然我們還發現了Anonymous gtid Event這也是5.7中變化,5.7中即使不開始Gtid每個事物也包含也一個Anonymous gtid Event,雖然沒有Gtid但是它任然包含了 last_committed/sequence_number。

四、本節小結

學習完本節至少能夠學習到:

  • 1、什麼是Gtid event。包含什麼重要元素。
  • 2、為什麼需要gtid_executed表及其作用。
  • 3、5.7中Previous gtid Event發生了哪些改變。
  • 4、簡單瞭解Previous gtid Event的改變意味著什麼。

作者微信:


微信.jpg

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2148837/,如需轉載,請註明出處,否則將追究法律責任。

相關文章