天天看點

MySQL并發複制演進

MySQL5.5版本及以前的複制

一般主從複制有三個線程且都是單線程:Binlog Dump(主)—> IO Thread(從)—> SQL Thread(從)。

MySQL并發複制演進

  1. master節點的Binlog dump Thread,當slave節點與master正常連接配接的時候,master把更新的binlog内容推送到slave節點。
  2. slave節點的I/O Thread ,該線程通過讀取master節點binlog日志名稱以及偏移量資訊将其拷貝到本地relay log日志檔案。
  3. slave節點的SQL Thread,該線程讀取relay log日志資訊,将在master節點上送出的事務在本地回放,達到與主庫資料保持一緻的目的。

一般複制出現延遲主要在兩個方面:

  1. SQL線程忙不過來(可能大事物操作資料量較大;可能和從庫本身的一些操作有關,有鎖和資源的沖突;主庫可以并發寫,SQL線程不可以;主要原因)
  2. 網絡抖動導緻IO線程複制延遲(次要原因)。

MySQL5.6的改進

MySQL 5.6版本引入并發複制(schema級别),基于schema級别的并發複制核心思想:“不同schema下的表并發送出時的資料不會互相影響,即slave節點可以用對relay log中不同的schema各配置設定一個類似SQL功能的線程,來重放relay log中主庫已經送出的事務,保持資料與主庫一緻”。可見MySQL5.6版本的并發複制,一個schema配置設定一個類似SQL線程的功能。

MySQL并發複制演進

在上圖的紅色框框部分就是實作并行複制的關鍵所在。在MySQL 5.6版本之前,Slave伺服器上有兩個線程I/O線程和SQL線程。I/O線程負責接收二進制日志(更準确的說是二進制日志的event),SQL線程進行回放二進制日志。如果在MySQL 5.6版本開啟并行複制功能(slave_parallel_workers > 0),那麼SQL線程就變為了coordinator線程,coordinator線程主要負責以下兩部分内容:

  • 若判斷可以并行執行,那麼選擇worker線程執行事務的二進制日志。
  • 若判斷不可以并行執行,如該操作是DDL,亦或者是事務跨schema操作,則等待所有的worker線程執行完成之後,再執行目前的日志。

這意味着coordinator線程并不是僅将日志發送給worker線程,自己也可以回放日志,但是所有可以并行的操作傳遞由worker線程完成。

上述機制實作的基于schema的并行複制存在的問題是這樣設計的并行複制效果并不高,如果使用者執行個體僅有一個庫,那麼就無法實作并行回放,甚至性能會比原來的單線程更差,而單庫多表是比多庫多表更為常見的一種情形。

MySQL5.7的MTS(Enhanced Muti-threadedslaves)

MySQL 5.7引入了新的機制來實作并行複制,不再有基于庫的并行複制限制,主要思想就是slave伺服器的回放與主機是一緻的,即master伺服器上是怎麼并行執行,slave上就怎樣進行并行回放。為了相容MySQL 5.6基于庫的并行複制,5.7引入了新的變量slave-parallel-type,其可以配置的值有:

  • DATABASE:預設值,基于庫的并行複制方式(相容MySQL5.6)
  • LOGICAL_CLOCK:基于組送出的并行複制方式

當slave配置slave_parallel_workers(=8)>0并且global.slave_parallel_type='LOGICAL_CLOCK' 時,可支援一個schema下,slave_parallel_workers個的worker線程并發執行relay log中主庫送出的事務。但是要實作以上功能,需要在master機器标記binary log中送出的事務哪些事物是可以并發執行,MySQL5.7将組送出的資訊存放在GTID中。

那麼如果使用者沒有開啟GTID功能,即将參數gtid_mode設定為OFF呢?故MySQL 5.7又引入了稱之為Anonymous_Gtid的二進制日志event類型,如:

MySQL并發複制演進

在MySQL 5.7的master機器上,用指令 mysqlbinlog mysql-bin.0000006| grep last_committed 可以看到last_committed和sequence_number,last_committed和sequence_number代表的就是LOGICAL_CLOCK。

server id 15102  end_log_pos14623 CRC32  0x767a33fa GTID      last_committed=18         sequence_number=26server id 15102  end_log_pos15199  CRC32 0x7dd1bf05 GTID     last_committed=26         sequence_number=27server id 15102  end_log_pos15773  CRC32 0xb01dc76e GTID     last_committed=26         sequence_number=28server id 15102  end_log_pos16347  CRC32 0x7a8e0ee8 GTID     last_committed=26         sequence_number=29server id 15102  end_log_pos16921  CRC32 0x92516d17 GTID     last_committed=26         sequence_number=30server id 15102  end_log_pos17495  CRC32 0xeb14a51e GTID     last_committed=26         sequence_number=31server id 15102  end_log_pos18071  CRC32 0x750667d0 GTID     last_committed=26         sequence_number=32server id 15102  end_log_pos18645  CRC32 0xcaed6159 GTID     last_committed=26         sequence_number=33server id 15102  end_log_pos19219  CRC32 0x62408408 GTID     last_committed=26         sequence_number=34server id 15102  end_log_pos19793  CRC32 0x5cf46239 GTID     last_committed=33         sequence_number=35      

在slave機器的relay log中 last_committed相同的事務(sequence_num不同)可以并發執行。一個組送出的事務(group commit)都是可以并行回放,因為這些事務都已進入到事務的prepare階段,說明事務之間沒有任何沖突(否則就不可能送出)。從上面截取的資訊可以看出last_committed=26的事務一共有8個:從sequence_number=27-34,假設當slave_parallel_workers=8時,Coordinator線程配置設定這一組事務到worker中排隊去執行。增加master庫binary log group commit組中事務的數量可以提高slave機器并發處理事務的數量,MySQL5.7引入 binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count參數來提高binary log組送出并發數量。MySQL等待binlog_group_commit_sync_delay毫秒的時間直到binlog_group_commit_sync_no_delay_count個事務數時,将進行一次組送出。