MySQL數據庫的成功離不開其replicaiton,相對於Oracle DG和Microsoft SQL Server Log Shipping來講,其簡單易上手,基本上1,2分鐘內根據手冊就能完成環境的搭建。然而,隨着使用的深刻,replication自身的問題會慢慢顯露,其中非crash safe的特性使得許多DBA感到頭疼,甚至不能理解其所發問題的緣由。簡單來講,crash-safe replication是指當master/slave任何一個節點發生宕機等意外狀況下,服務器重啓後master/slave的數據依然可以保證一致性。mysql
crash-safe master相對比較簡單,只要使用事務的存儲引擎,而且正確的配置就能達到crash safe的效果。對於最爲常見的InnoDB存儲引擎而言,只需在配置文件中進行以下的設置:
MySQL 5.6版本以前存在一個bug,即當啓用上述兩個參數時,會使得InnoDB存儲引擎的group commit失效,從而致使在寫密集的環境中性能的急劇降低。所以,DBA在性能和數據一致性中作了妥協,一般將參數innodb-flush-log-at-trx-commit設置爲2,而這就致使了master再也不是crash safe的,主從數據可能會不一致。MariaDB真正解決了該問題,所以不少分支版本,好比Percona,Facebook MySQL,InnoSQL都將MariaDB的group commit方案移植到了本身的分支中,從而解決group commit失效的問題。
crash-safe slave的狀況就有些複雜,而這多是DBA更爲常見的問題。例如slave不斷的報1062錯誤,或者發現主從數據不一致(特別是表沒有主鍵的狀況)。而這時DBA的選擇一般也很無奈,基本就是全庫重建了。因此說,當你有運維超過200臺以上的MySQL服務器的經驗時,就會發現這是一個很大的問題。
致使不能實現crash-safe slave有兩方面的緣由,即replication中的SQL thread和IO thread。首先來看SQL thread,其主要完成兩個操做:
- 運行relay log中對應的事務信息
- 更新relay-info.log文件
更新relay-info.log文件是爲了記錄已經執行relay log中的位置,當slave重啓後能夠根據這個位置繼續同步relay log。可是,這裏用戶會發現這兩個操做不是在一個事務中,一個是數據庫操做,一個是文件操做,所以不能達到原子的效果。此外,MySQL數據庫默認對於文件relay-info.log是寫入到操做系統緩存,所以在發生宕機時可能致使大量的已更新位置的丟失,從而致使重複執行SQL語句,最終的現象就是主從數據不一致。MySQL 5.5新增了參數sync_relay_log_info,能夠控制每次事務更新relay-info.log後就進行一次fdatasync操做,這加劇了系統負擔,並且即便這樣也可能存在最後一個事務丟失的狀況。
MySQL 5.6採用了另外一種方法,就是將relay-info.log的信息保存在InnoDB的事務表中,這時兩個操做都是數據庫操做,在一個事務中就能獲得原子性。例如對於slave的日誌回放,其過程爲:
BEGIN;
apply log event;
apply log event;
UPDATE mysql.slave_relay_log_info
SET Master_log_pos = Exec_Master_Log_Pos,
Master_log_name = Relay_Master_Log_File,
Relay_log_name = Relay_Log_File,
Relay_log_pos = Relay_Log_Pos;
COMMIT
這樣的處理方式解決更新relay-info.log的原子性問題,可是這是最終完美的解決方案嗎?很惋惜,仍是存在一些缺陷。
能夠看到因爲最後表
slave_relay_log_info的更新會鎖住記錄,從而致使slave上的事務提交都是串行的。雖然MySQL 5.6支持並行複製,可是因爲串行更新表
slave_relay_log_info,再次致使group commit失效。所以經過--log-slave-updates再立級聯replication的話,性能又會受限。MariaDB正在解決該問題,很是有可能在MariaDB 10 GA版本中見到完美的解決方案。
IO thread用於同步master上的二進制日誌,可是其在crash時依然會致使數據不一致的狀況發生。IO thread將收到的二進制日誌寫入到relay log,每一個二進制日誌由多個log event組成,因此每接受到一個log event就須要更新master-info.log。和relay-info.log同樣,其也是寫入操做系統緩存,參數sync_master_info能夠控制fdatasync的時間。因爲IO thread的更新不能像SQL thread同樣進行放到一個事務進行原子操做,所以其是對數據一致性會產生影響,設想一個log event傳送到了relay log中兩次的情形。
不過好在從MySQL 5.5版本開始提供了參數relay_log_recovery,當發生crash致使重連master時,其不根據master-info.log的信息進行重連,而是根據relay-info中執行到master的位置信息從新開始拉master上的日誌數據(不過須要確保日誌依然存在於master上,不然就。。。)
crash-safe是運維人員不能忽略的一點,不然DBA將忙於處理這些異常情況致使的slave服務中止的情形。MySQL 5.6雖然提供了crash safe的解決方案,但依然存在一些不完美的可能性。因此,小夥伴們,讓咱們期待MariaDB 10 GA版本的發佈吧。