MySQL 5.7基於組提交的並行復制


參考鏈接:

http://mysql.taobao.org/monthly/2016/08/01/

https://www.kancloud.cn/thinkphp/mysql-parallel-applier/45909

 

5.7新版本復制方面的主要優化內容:

運維

  • 在線啟停GTID
  • 在線配置Replication Filter,無需重啟
  • Change Master到另外一個主庫無需停止apply線程
  • Change Master修改一些日志apply屬性(例如master_delay)無需停止IO線程
  • 增加大量Performance Schema表用於監控復制

新特性

  • Loss-less Semi-sync Replication: 允許在事務提交前等待備庫ACK
  • Semisync允許配置成主庫等待N個ACK才繼續提交,增加可用性
  • 存儲GTID信息到系統表中,這樣備庫如果無級聯的話,就可以直接關閉備庫的binlog
  • Multi-source Replication:允許從多個主庫復制數據到一台備庫上
  • Group Replication Plugin,多主結構的集群管理插件

性能

  • 更好的復制性能(logical_clock):在主庫上能夠並發的事務,通過利用Group Commit在日志中被標記為能在備庫並發執行。從而獲得更好的並發apply效率
  • Binlog Dump線程不受Lock_log鎖影響,預分配並重用用於讀取log event的內存
  • 獨立的ACK線程,用於處理semisync打開場景下備庫返還的ack,保證在等待網絡時不阻塞binlog dump線程,提升了整體並發度。

 

 

logical_clock方便的內容:

 

MySQL 5.7才可稱為真正的並行復制,這其中最為主要的原因就是slave服務器的回放與主機是一致的即master服務器上是怎么並行執行的slave上就怎樣進行並行回放。不再有庫的並行復制限制,對於二進制日志格式也無特殊的要求(基於庫的並行復制也沒有要求)。

從MySQL官方來看,其並行復制的原本計划是支持表級的並行復制和行級的並行復制,行級的並行復制通過解析ROW格式的二進制日志的方式來完成,WL#4648。但是最終出現給小伙伴的確是在開發計划中稱為:MTS: Prepared transactions slave parallel applier,可見:WL#6314。該並行復制的思想最早是由MariaDB的Kristain提出,並已在MariaDB 10中出現,相信很多選擇MariaDB的小伙伴最為看重的功能之一就是並行復制。

MySQL 5.7並行復制的思想簡單易懂,一言以蔽之:一個組提交的事務都是可以並行回放,因為這些事務都已進入到事務的prepare階段,則說明事務之間沒有任何沖突(否則就不可能提交)。

為了兼容MySQL 5.6基於庫的並行復制,5.7引入了新的變量slave-parallel-type,其可以配置的值有:

  • DATABASE:默認值,基於庫的並行復制方式
  • LOGICAL_CLOCK:基於組提交的並行復制方式

支持並行復制的GTID

如何知道事務是否在一組中,又是一個問題,因為原版的MySQL並沒有提供這樣的信息。在MySQL 5.7版本中,其設計方式是將組提交的信息存放在GTID中。那么如果用戶沒有開啟GTID功能,即將參數gtid_mode設置為OFF呢?故MySQL 5.7又引入了稱之為Anonymous_Gtid的二進制日志event類型,如:

mysql> SHOW BINLOG EVENTS in 'mysql-bin.000006'; +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+ | mysql-bin.000006 | 4 | Format_desc | 88 | 123 | Server ver: 5.7.7-rc-debug-log, Binlog ver: 4 | | mysql-bin.000006 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 | | mysql-bin.000006 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000006 | 259 | Query | 88 | 330 | BEGIN | | mysql-bin.000006 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) | | mysql-bin.000006 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F | ......

這意味着在MySQL 5.7版本中即使不開啟GTID,每個事務開始前也是會存在一個Anonymous_Gtid,而這GTID中就存在着組提交的信息。

LOGICAL_CLOCK

然而,通過上述的SHOW BINLOG EVENTS,我們並沒有發現有關組提交的任何信息。但是通過mysqlbinlog工具,用戶就能發現組提交的內部信息:

root@localhost:~# mysqlbinlog mysql-bin.0000006 | grep last_committed #150520 14:23:11 server id 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 sequence_number=1 #150520 14:23:11 server id 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 sequence_number=2 #150520 14:23:11 server id 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 sequence_number=3 #150520 14:23:11 server id 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 sequence_number=4 #150520 14:23:11 server id 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 sequence_number=5 #150520 14:23:11 server id 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 sequence_number=6 #150520 14:23:11 server id 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 sequence_number=7 #150520 14:23:11 server id 88 end_log_pos 8834 CRC32 0x96864e6b GTID last_committed=6 sequence_number=8 #150520 14:23:11 server id 88 end_log_pos 10057 CRC32 0x2de1ae55 GTID last_committed=6 sequence_number=9 #150520 14:23:11 server id 88 end_log_pos 11280 CRC32 0x5eb13091 GTID last_committed=6 sequence_number=10 #150520 14:23:11 server id 88 end_log_pos 12504 CRC32 0x16721011 GTID last_committed=6 sequence_number=11 #150520 14:23:11 server id 88 end_log_pos 13727 CRC32 0xe2210ab6 GTID last_committed=6 sequence_number=12 #150520 14:23:11 server id 88 end_log_pos 14952 CRC32 0xf41181d3 GTID last_committed=12 sequence_number=13 ...

可以發現較之原來的二進制日志內容多了last_committed和sequence_number,last_committed表示事務提交的時候,上次事務提交的編號,如果事務具有相同的last_committed,表示這些事務都在一組內,可以進行並行的回放。例如上述last_committed為0的事務有6個,表示組提交時提交了6個事務,而這6個事務在從機是可以進行並行回放的。

上述的last_committed和sequence_number代表的就是所謂的LOGICAL_CLOCK。先來看源碼中對於LOGICAL_CLOCK的定義:

class Logical_clock { private: int64 state; /* Offset is subtracted from the actual "absolute time" value at logging a replication event. That is the event holds logical timestamps in the "relative" format. They are meaningful only in the context of the current binlog. The member is updated (incremented) per binary log rotation. */ int64 offset; ......

state是一個自增的值,offset在每次二進制日志發生rotate時更新,記錄發生rotate時的state值。其實state和offset記錄的是全局的計數值,而存在二進制日志中的僅是當前文件的相對值。使用LOGICAL_CLOCK的場景如下:

class MYSQL_BIN_LOG: public TC_LOG { ... public: /* Committed transactions timestamp */ Logical_clock max_committed_transaction; /* "Prepared" transactions timestamp */ Logical_clock transaction_counter; ...

可以看到在類MYSQL_BIN_LOG中定義了兩個Logical_clock的變量:

  • max_c ommitted_transaction:記錄上次組提交時的logical_clock,代表上述mysqlbinlog中的last_committed
  • transaction_counter:記錄當前組提交中各事務的logcial_clock,代表上述mysqlbinlog中的sequence_number


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM