天天看點

MySQL · 特性分析 ·MySQL 5.7新特性系列四

繼上三期月報:

這期我們一起來學習下mysql 5.7的并行複制。

mysql的master<->slave的部署結構,使用binlog日志保持資料的同步,全局有序的binlog在備庫按照送出順序進行回放。

由于新硬體的發展,ssd的引入和多core的cpu,master節點的并發處理能力持續提升,slave節點完全按照binlog寫入順序的單線程回放,已完全跟不上master節點的吞吐能力,導緻ha切換和資料保護帶來巨大的挑戰。

從mysql5.5版本以後,開始引入并行複制的機制,是mysql的一個非常重要的特性。

mysql5.6開始支援以schema為次元的并行複制,即如果binlog row event操作的是不同的schema的對象,在确定沒有ddl和foreign key依賴的情況下,就可以實作并行複制。

社群也有引入以表為次元或者以記錄為次元的并行複制的版本,不管是schema,table或者record,都是建立在備庫slave實時解析row格式的event進行判斷,保證沒有沖突的情況下,進行分發來實作并行。

mysql5.7的并行複制,multi-threaded slave即mts,期望最大化還原主庫的并行度,實作方式是在binlog event中增加必要的資訊,以便slave節點根據這些資訊實作并行複制。

下面我們就來看下mysql 5.7的實作方式:

mysql 5.7的并行複制建立在group commit的基礎上,所有在主庫上能夠完成prepared的語句表示沒有資料沖突,就可以在slave節點并行複制。

我們先來回顧一下group commit的情況:

在ordered commit的過程中:

1. 由leader線程幫助flush隊列中的線程完成flush binlog操作,

2. 由leader線程幫助sync隊列中的線程完成sync binlog操作,

為了表示主庫并行度,在binlog row event增加了如下的辨別:

即在gtid_event中增加兩個字段:

代碼中為每一個transaction準備了如下的字段:

mysql_bin_log全局對象中維護了兩個結構:

事務中的sequence_number是一個全局有序遞增的數字,每個事務遞增1,來源mysql_bin_log.tranaction_counter.

和gtid一對一的關系,即在flush階段,和gtid生成的時機一緻,代碼參考:

事務中last_committed表示在這個commit下的事務,都是可以并行的,即沒有沖突,

transaction_ctx中的last_committed在每個語句prepared的時候進行初始化,來源mysql_bin_log.max_committed_transaction

而mysql_bin_log.max_committed_transaction的更新是在group commit送出的時候進行變更。

即擷取這個group commit隊列中的最大的sequence_number當成目前的max_committed_transaction。

是以,這個機制可以了解成,在group commit完成之前,所有可以成功prepared的語句,沒有事實上的沖突,

配置設定成相同的last_committed,就可以在slave節點并行複制。

例如下面時序的事務:

binlog日志片段如下:

兩個insert語句在prepared的時候,沒有事實上的沖突,都擷取目前最大的committed number = 5.

送出的過程中,保持sequence_number生成時候的全局有序性,備庫恢複的時候,這兩個事務就可以并行完成。

但又如下面的case:

産生如下的順序:

session 1和session 2語句執行不沖突,配置設定了相同的last_committed,

session 2送出,推高了last_committed,是以session 3的laste_committed變成了1,

最後session 1送出。

注意: 這就是mysql 5.7.3之後的改進:

在mysql 5.7.3之前,必須在一個group commit之内的事務,才能夠在slave節點并行複制,但如上面的這個case。

session 1 和session 2雖然commit的時間有差,并且不在一個group commit,生成的binlog也沒有連續,但事實上是可以并行恢複執行的。

是以從mysql 5.7.3之後,并行恢複,減少了group commit的依賴,但group commit仍然對并行恢複起着非常大的作用。

mysql 5.7增加了如下參數:

slave_parallel_type取值:

1. database: 預設值,相容5.6以schema次元的并行複制

2. logical_clock: mysql 5.7基于組送出的并行複制機制

group commit delay

首先,并行複制必須建立在主庫的真實負載是并行的基礎上,才能使mts有機會在slave節點上完成并行複制,

其次,mysql 5.7前面讨論的實作機制,可以人工的增加group commit的delay,打包更多的事務在一起,提升slave複制的并行度。但從5.7.3開始,已經減少了group commit的依賴,

盡量減少delay參數設定對主庫的影響。

合理設定如下參數;

盡量使用row格式的binlog

slave_parallel_workers 太多的線程會增加線程間同步的開銷,建議4-8個slave線程,根據測試來最終确定。

如果用戶端有并行度,不用刻意增加master的group commit,減少對主庫的影響。

另外:

booking在使用的時候遇到的如下case:

資料庫的部署結構是:master->slave1->slave2

假設,當t1,t2,t3,t4四個事務在master group commit中,那麼slave1線程就可以并行執行這四個事務,

但在slave1執行的過程中,分成了兩個group commit,那麼在slave2節點上,并行度就降低了一倍。

booking給出的後續的解法,如果slave不多,建議都挂載在master上,如果slave過多,考慮使用binlog server,來避免這樣的問題。

但其實在slave1節點上進行并行恢複的時候,保持着主庫的last_committed和sequence_number不變,雖然無法保證binlog寫入的順序完全和主庫一緻,但可以緩解這種情況。

繼續閱讀