天天看點

【MySQL】MySQL5.6新特性之crash-safe

一 介紹

  MySQL 5.6 針對複制功能提供了新特性: slave支援crash-safe. 該功能可以解決之前版本中系統異常斷電可能導緻的SQL thread 資訊不準确的問題。本文從原理方面對該特性進行介紹。

二 原理

  在了解crash-safe slave 之前,我們先分析一下MySQL 5.6 之前的版本出現 crash-unsafe 的原因。在slave上,複制包含兩個線程:即replication中的IO thread和SQL thread。

IO thread負責從master拷貝binlog檔案并儲存到本地,拷貝過來的binlog稱為relay-log. 

SQL thread負責執行relay-log.

兩個線程的執行進度(偏移量)都儲存在檔案中.IO thread的執行狀态資訊儲存在master.info檔案,SQL thread的執行狀态資訊儲存在relay-log.info檔案。系統運作正常的情況下,這種模式到目前為止還沒有問題。需要注意的是這些檔案被修改後不是同步寫入磁盤的,每當系統發生crash,存儲的偏移量可能都不準确.MySQL 5.5通過兩個參數修複了該問題,使用sync_master_info=1和sync_replay_log_info=1 來保證Slave 的兩個線程每次寫一個事務就分别向兩個檔案同步一次 IO thread和SQL thread目前執行的資訊。當然同步操作不是免費的,頻繁更新磁盤檔案需要消耗性能,如果你的RAID裝置的IO政策設定為WRITEBACK 模式,那麼這種方法便可以接受的。

 但是,即使設定了sync_master_info=1和sync_relay_info=1, 問題還是會出現,因為複制資訊是在transactions送出後寫入的,如果crash發生在事務送出和OS寫檔案之間,那麼relay-log.info就可能是錯誤的。當slave從新啟動的時候,最後那個事務可能會被執行兩次.具體的影響取決于事務的具體操作.複制可能會繼續運作比如update/delete,或者報錯 比如insert操作,此時主從資料的一緻性可能會被破壞。

 MySQL 5.6版本通過将複制資訊存放到表中來解決此問題.通過配置兩個參數 relay_log_info_repository=TABLE,master_info_repository=TABLE,relay log info 會存放到 mysql.slave_relay_log_info表中,master info 會存放mysql.slave_master_info表中。就是把SQL線程執行事務和更新mysql.slave_replay_log_info的語句看成一個事務處理,這樣就會一直同步的.

我們可以通過僞代碼來了解crash-safe 的原理

crash-unsafe情況下 SQL_thread 的 的工作模式

crash-safe情況下 SQL_thread 的 的工作模式

crash-safe就是将relay-info.log的資訊儲存在InnoDB的事務表中,這時執行relay log中的事務和寫relay info在一個事務中,就能得到原子性保證。進而避免已執行的binlog位點和寫入relay log info 的位點資訊不一緻的情況發生。看到這裡也請各位讀者思考一下 ,現在的這種方案是否完美,有哪些問題?

 從上面的改變解決了SQL thread記錄執行狀态可能導緻不一緻的風險,但是對于IO thread 依然存在問題 。IO thread 從master上拷貝binlog寫入 relay log中,每個二進制日志由多個log event組成,是以每接收到一個log event就需要更新master-info.log而且該是寫入作業系統緩存。從IO thread的工作原理來看,它沒有辦法 将寫入master info和拉取binlog放到同一個事務中而保持原子操作,是以IO thread 的行為是會對資料一緻性會産生影響,設想一個log event傳送到了relay log中兩次的情形。如何解決呢?

 方案一 通過參數sync_master_info可以控制fdatasync的時間。預設值是10000,表示IO線程的偏移量每10000個事務更新一次 ,通過設定其為1,每寫一次事務便同步到master.info 。

 方案二 通過MySQL 5.5版本開始提供的參數relay_log_recovery ,當slave發生crash後重新開機之後重連master時,slave不根據master-info.log的資訊進行重連,而是根據relay-info中執行到master的位置資訊重新開始拉master上的日志資料。

三 如何使用 

  1 停止slave的mysql執行個體

  2 my.cnf檔案中添加

     master-info-repository=TABLE

     relay-log-info-repository=TABLE

     relay-log-recovery

  3 重新開機slave的mysql執行個體

注意:

如果是MySQL 5.6.5 或者更早期。slave_master_info 和 slave_relay_log_info 表預設使用MyISAM 引擎。是以還得修改成innodb,如下:

四 小結 

   MySQL 5.6 版本為MySQL的穩定性做出了很多改進,這點值得MySQL DBA 去關注,也值得大家去思考,這些改善點還有那些不足之處?有如何解決?

五 參考文章