天天看點

MySQL核心月報 2015.01-MySQL · 性能優化· Group Commit優化

<b>背景</b>

關于group commit網上的資料其實已經足夠多了,我這裡隻簡單的介紹一下。

衆所周知,在mysql5.6之前的版本,由于引入了binlog/innodb的xa,binlog的寫入和innodb commit完全串行化執行,大概的執行序列如下:

當sync_binlog=1時,很明顯上述的第二步會成為瓶頸,而且還是持有全局大鎖,這也是為什麼性能會急劇下降。

oracle mysql 在5.6版本開始也支援binlog group commit,使用了和mariadb類似的思路,但将group commit的過程拆分成了三個階段:flush stage 将各個線程的binlog從cache寫到檔案中; sync stage 對binlog做fsync操作(如果需要的話);commit stage 為各個線程做引擎層的事務commit。每個stage同時隻有一個線程在操作。

tips:當引入group commit後,sync_binlog的含義就變了,假定設為1000,表示的不是1000個事務後做一次fsync,而是1000個事務組。

<b>xa recover</b>

在binlog打開的情況下,mysql預設使用mysql_bin_log來做xa協調者,大緻流程為:

通過這種方式,可以讓innodb和binlog中的事務狀态保持一緻。顯然隻要事務在innodb層完成了prepare,并且寫入了binlog,就可以從崩潰中恢複事務,這意味着我們無需在innodb commit時顯式的write/fsync redo log。

tips:mysql為何隻需要掃描最後一個binlog檔案呢 ? 原因是每次在rotate到新的binlog檔案時,總是保證沒有正在送出的事務,然後fsync一次innodb的redo log。這樣就可以保證老的binlog檔案中的事務在innodb總是送出的。

<b>問題</b>

其實問題很簡單:每個事務都要保證其prepare的事務被write/fsync到redo log檔案。盡管某個事務可能會幫助其他事務完成redo 寫入,但這種行為是随機的,并且依然會産生明顯的log_sys-&gt;mutex開銷。

<b>優化</b>

從xa恢複的邏輯我們可以知道,隻要保證innodb prepare的redo日志在寫binlog前完成write/sync即可。是以我們對group commit的第一個stage的邏輯做了些許修改,大概描述如下:

通過延遲寫redo log的方式,顯式的為redo log做了一次組寫入,并減少了log_sys-&gt;mutex的競争。

目前官方mysql已經根據我們report的bug#73202鎖提供的思路,對5.7.6的代碼進行了優化,對應的release note如下:

<b>性能資料</b>

簡單測試了下,使用sysbench, update_non_index.lua, 100張表,每張10w行記錄,innodb_flush_log_at_trx_commit=2, sync_binlog=1000,關閉gtid

繼續閱讀