MySQL 5.7並行複製實踐
MySQL 5.7並行複製原理
MySQL 從 5.6 開始引入了多庫並行主從複製,但是其並行只是基於 Schema
的,也就是基於庫的。如果使用者的 MySQL 資料庫例項中存在多個 Schema
,對於從機複製的速度的確可以有比較大的幫助。MySQL 5.6 並行複製的架構如下所示:
在上圖的紅色框框部分就是實現並行複製的關鍵所在。在 MySQL 5.6 版本之前,Slave 伺服器上有兩個執行緒 I/O 執行緒和 SQL 執行緒。I/O 執行緒負責接收二進位制日誌(更準確的說是二進位制日誌的 event ),SQL 執行緒進行回放二進位制日誌。如果在 MySQL 5.6 版本開啟並行複製功能,那麼SQL執行緒就變為了 Coordinator
Coordinator
執行緒主要負責以前兩部分的內容:
- 若判斷可以並行執行,那麼選擇
Worker
執行緒執行事務的二進位制日誌。 - 若判斷不可以並行執行,如該操作是
DDL
,亦或者是事務跨Schema
操作,則等待所有的Worker
執行緒執行完成之後,再執行當前的日誌。
這意味著 Coordinator
執行緒並不是僅將日誌傳送給 Worker
執行緒,自己也可以回放日誌,但是所有可以並行的操作交付由 Worker
執行緒完成。Coordinator
執行緒與 Worker
是典型的生產者與消費者模型。
上述機制實現的基於 Schema
的並行複製存在兩個問題,首先是 Crash Safe
Low-Water-Mark
標記來解決該問題,從設計上看,其是希望藉助於日誌的冪等性來解決該問題,不過 5.6 的二進位制日誌回放還不能實現冪等性。另一個最為關鍵的問題是這樣設計的並行複製效果並不高,如果使用者例項僅有一個庫,那麼就無法實現並行回放,甚至效能會比原來的單執行緒更差。而單庫多表是比多庫多表更為常見的一種情形。
MySQL 5.7 才可稱為真正的並行複製,這其中最為主要的原因就是 Slave 伺服器的回放與主機是一致的即 Master 伺服器上是怎麼並行執行的 Slave 上就怎樣進行並行回放。不再有庫的並行複製限制,對於二進位制日誌格式也無特殊的要求(基於庫的並行複製也沒有要求)。
從 MySQL 官方來看,其並行複製的原本計劃是支援表級的並行複製和行級的並行複製,行級的並行複製通過解析 ROW 格式的二進位制日誌的方式來完成。但是最終出現的是在開發計劃中稱為:MTS: Prepared transactions slave parallel applier
。
該並行複製的思想最早是由 MariaDB 的 Kristain 提出,並已在 MariaDB 10 中出現,MySQL 5.7 並行複製的思想簡單易懂,一言以蔽之:一個組提交的事務都是可以並行回放,因為這些事務都已進入到事務的 Prepare
階段,則說明事務之間沒有任何衝突(否則就不可能提交)。
為了相容 MySQL 5.6 基於庫的並行複製,5.7 引入了新的變數 slave-parallel-type
,其可以配置的值有:
- DATABASE:預設值,基於庫的並行複製方式。
- LOGICAL_CLOCK:基於組提交的並行複製方式。
如何知道事務是否在一組中,又是一個問題,因為原版的 MySQL 並沒有提供這樣的資訊。在 MySQL 5.7版本中,其設計方式是將組提交的資訊存放在 GTID
中。那麼如果使用者沒有開啟 GTID
功能,即將引數 gtid_mode
設定為 OFF 呢?故 MySQL 5.7 又引入了稱之為 Anonymous_Gtid
的二進位制日誌 event
型別,如:
mysql> SHOW BINLOG EVENTS in 'mysql-bin.000011'; | mysql-bin.000011 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 | | mysql-bin.000011 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' | | mysql-bin.000011 | 259 | Query | 88 | 330 | BEGIN | | mysql-bin.000011 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) | | mysql-bin.000011 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F | ......
這意味著在 MySQL 5.7 版本中即使不開啟 GTID
,每個事務開始前也是會存在一個 Anonymous_Gtid
,而這 GTID
中就存在著組提交的資訊。
組提交是個比較好玩的方式,我們根據 MySQL 的
binlog
可以發現較之原來的二進位制日誌內容多了last_committed
和sequence_number
。$ mysqlbinlog mysql-bin.000011 |grep last_committed #170607 11:24:57 server id 353306 end_log_pos 876350 CRC32 0x92093332 GTID last_committed=654 sequence_number=655 #170607 11:24:58 server id 353306 end_log_pos 880406 CRC32 0x344fdf71 GTID last_committed=655 sequence_number=656 #170607 11:24:58 server id 353306 end_log_pos 888700 CRC32 0x4ba2b05b GTID last_committed=656 sequence_number=657
上面是沒有開啟組提交的一個日誌,我們可以看得到 binlog
當中有兩個引數 last_committed
和 sequence_number
,我們可以看到,下一個事務在主庫配置好組提交以後,last_committed
永遠都和上一個事務的 sequence_number
是相等的。這也很容易理解,因為事務是順序提交的。
下面看一下組提交模式的事務:
$ mysqlbinlog mysql-bin.000012|grep last_commit #170609 10:11:07 server id 353306 end_log_pos 75629 CRC32 0xd54f2604 GTID last_committed=269 sequence_number=270 #170609 10:13:03 server id 353306 end_log_pos 75912 CRC32 0x43675b14 GTID last_committed=270 sequence_number=271 #170609 10:13:24 server id 353306 end_log_pos 76195 CRC32 0x4f843438 GTID last_committed=270 sequence_number=272
我們可以看到最後兩個事務的 last_committed
是相同的,這意味著這兩個事務是作為一個組提交的,兩個事務在 Perpare
階段獲取相同的 last_committed
而且相互不影響,最終是會作為一個組進行提交。這就是所謂的組提交。組提交的事務是可以在從機進行並行回放的。
上述的 last_committed
和 sequence_number
代表的就是所謂的 LOGICAL_CLOCK
。
配置MySQL並行複製
環境準備
這裡一共使用了二臺機器,MySQL 版本都為 5.7.18。
安裝MySQL
MySQL 安裝比較簡單,在 「MySQL 5.7多源複製實踐」一文中我們也講了,這裡就不在重複講了。如果你還不會安裝,可以先參考此文安裝好 MySQL 。
啟用MySQL並行複製
MySQL 5.7的並行複製建立在組提交的基礎上,所有在主庫上能夠完成 Prepared
的語句表示沒有資料衝突,就可以在 Slave 節點並行複製。
關於 MySQL 5.7 的組提交,我們要看下以下的引數:
mysql> show global variables like '%group_commit%'; +-----------------------------------------+-------+ | Variable_name | Value | +-----------------------------------------+-------+ | binlog_group_commit_sync_delay | 0 | | binlog_group_commit_sync_no_delay_count | 0 | +-----------------------------------------+-------+ 2 rows in set (0.00 sec)
要開啟 MySQL 5.7 並行複製需要以下二步,首先在主庫設定 binlog_group_commit_sync_delay
的值大於0 。
mysql> set global binlog_group_commit_sync_delay=10;
這裡簡要說明下 binlog_group_commit_sync_delay
和 binlog_group_commit_sync_no_delay_count
引數的作用。
binlog_group_commit_sync_delay
全域性動態變數,單位微妙,預設0,範圍:0~1000000(1秒)。
表示
binlog
提交後等待延遲多少時間再同步到磁碟,預設0 ,不延遲。當設定為 0 以上的時候,就允許多個事務的日誌同時一起提交,也就是我們說的組提交。組提交是並行複製的基礎,我們設定這個值的大於 0 就代表打開了組提交的功能。
binlog_group_commit_sync_no_delay_count
全域性動態變數,單位個數,預設0,範圍:0~1000000。
表示等待延遲提交的最大事務數,如果上面引數的時間沒到,但事務數到了,則直接同步到磁碟。若
binlog_group_commit_sync_delay
沒有開啟,則該引數也不會開啟。
其次要在 Slave 主機上設定如下幾個引數:
# 過多的執行緒會增加執行緒間同步的開銷,建議4-8個Slave執行緒。 slave-parallel-type=LOGICAL_CLOCK slave-parallel-workers=4
或者直接線上啟用也是可以的:
mysql> stop slave; Query OK, 0 rows affected (0.07 sec) mysql> set global slave_parallel_type='LOGICAL_CLOCK'; Query OK, 0 rows affected (0.00 sec) mysql> set global slave_parallel_workers=4; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.06 sec) mysql> show variables like 'slave_parallel_%'; +------------------------+---------------+ | Variable_name | Value | +------------------------+---------------+ | slave_parallel_type | LOGICAL_CLOCK | | slave_parallel_workers | 4 | +------------------------+---------------+ 2 rows in set (0.00 sec)
檢查Worker執行緒的狀態
當前的 Slave 的 SQL 執行緒為 Coordinator
(協調器),執行 Relay log
日誌的執行緒為 Worker
(當前的 SQL 執行緒不僅起到協調器的作用,同時也可以重放 Relay log
中主庫提交的事務)。
我們上面設定的執行緒數是 4 ,從庫就能看到 4 個 Coordinator
(協調器)程序。
並行複製配置與調優
開啟 MTS 功能後,務必將引數 master-info-repository
設定為 TABLE ,這樣效能可以有 50%~80% 的提升。這是因為並行複製開啟後對於 master.info
這個檔案的更新將會大幅提升,資源的競爭也會變大。
在 MySQL 5.7 中,推薦將 master-info-repository
和 relay-log-info-repository
設定為 TABLE ,來減小這部分的開銷。
master-info-repository = table relay-log-info-repository = table relay-log-recovery = ON
並行複製監控
複製的監控依舊可以通過 SHOW SLAVE STATUS\G
,但是 MySQL 5.7 在 performance_schema
架構下多了以下這些元資料表,使用者可以更細力度的進行監控:
mysql> use performance_schema; mysql> show tables like 'replication%'; +---------------------------------------------+ | Tables_in_performance_schema (replication%) | +---------------------------------------------+ | replication_applier_configuration | | replication_applier_status | | replication_applier_status_by_coordinator | | replication_applier_status_by_worker | | replication_connection_configuration | | replication_connection_status | | replication_group_member_stats | | replication_group_members | +---------------------------------------------+ 8 rows in set (0.00 sec)
文章來自微信公眾號:運維之美