當機導致slave異常分析

longqidong發表於2014-10-24

線上一臺備份伺服器由於誤操作導致異常掉電,設定了開機自動啟動複製,重新啟動之後,檢視複製,報錯:

主鍵衝突, Slave SQL: Error 'Duplicate entry '5218036-4f8c3555-1e5f-4c8e-bed7-9c78d6ab8725' for key 'PRIMARY'' on query. Default database: .....

為何會報主鍵衝突,主鍵衝突,那就是說之前已經有同樣一條資料寫入到了slave,然後複製程式又寫一遍導致的,那為何會重寫一遍呢,要麼master重新寫入了,這點可以否決,因為是主鍵,master重寫也會失敗,壓根就不會傳送到slave來,要麼就是relay-log又重放了一遍導致,看來只能是這點了,每個故障都是有原因的。要處理一個問題,就需要把這個問題在心裡重現一遍,然後看看是哪個環節可能導致的問題。

下面來看看複製的原理,簡單描述如下:

master插入一條記錄,寫入binlogslave IO程式從主庫獲取這條記錄的資訊並寫入relay-log,接著slaveSQL程式解析到這條記錄,並寫入到slave,完成一條記錄的複製。複製過程中會涉及到檔案有:

relay-log存放從主庫獲取到的二進位制日誌,

relay-log.info  存放slave SQL執行緒執行到了master的哪個檔案和pos以及relay-log檔案和pos位置,這個檔案由SQL執行緒負責更新

master.info  存放slave 獲取到了master的二進位制日誌檔案和pos位置,複製有關的資訊,master-host,port,user,passwd等等,這個檔案由IO執行緒負責更新

上述三個檔案的資訊都是不斷更新的,注意這裡是不斷更新而不是實時更新,這個更新的頻率由下面幾個引數決定,摘自官方文件:

# sync_relay_log_info

If the value of this variable is greater than 0,

a replication slave synchronizes its relay-log.info file to disk (using fdatasync()) after every sync_relay_log_info transactions.

A value of 1 is the generally the best choice.

The default value of sync_relay_log_info is 0,

which does not force any synchronization to disk by the MySQL server—in this case,

the server relies on the operating system to flush the relay-log.info file's contents from time to time as for any other file.

# sync_master_info

If the value of this variable is greater than 0,

a replication slave synchronizes its master.info file to disk (using fdatasync()) after every sync_master_info events.

The default value of sync_relay_log_info is 0 (recommended in most situations),

which does not force any synchronization to disk by the MySQL server;

in this case, the server relies on the operating system to flush the master.info file's contents from time to time as for any other file.

# sync_relay_log

If the value of this variable is greater than 0,

the MySQL server synchronizes its relay log to disk (using fdatasync()) after every sync_relay_log writes to the relay log.

There is one write to the relay log per statement if autocommit is enabled, and one write per transaction otherwise.

The default value of sync_relay_log is 0, which does no synchronizing to disk—in this case,

the server relies on the operating system to flush the relay log's contents from time to time as for any other file.

A value of 1 is the safest choice because in the event of a crash you lose at most one statement or transaction from the relay log.

However, it is also the slowest choice (unless the disk has a battery-backed cache, which makes synchronization very fast).

這幾個引數控制著上面三個檔案的更新頻率,0由作業系統cache控制relay.infomaster.info的重新整理,N則表示N個事務後重新整理到磁碟,(和sync-binlog一樣)

預設都是0,都是依賴作業系統的重新整理來更新。檢視了出故障這臺slave,這幾個引數都是預設的。既然依賴作業系統的重新整理來更新,這就意味著有可能丟失資料,在異常掉電的情況下,作業系統cache來不及重新整理到磁碟,就會大導致slave複製資訊沒有及時重新整理到relay-log.infomaster.info而丟失,也就是此時的relay-log.infomaster.info是落後於複製執行緒的,複製資訊和disk存放的資訊不一致。這也是5.5版本複製稱為not crash safe的原因,5.6版本可以選擇採用表來存放複製資訊,稱為 crash safe,可以找時間驗證一下。

這裡還需要理解一點的是,如果slave設定了例項開啟時啟動複製的話,則會根據relay.infomaster.info這兩個檔案來啟動複製。

 

透過上述幾點理解,那就很容易理解為何例項啟動後會報主鍵衝突了,master.inforelay-log.info 在掉電後,複製資訊沒有及時重新整理到磁碟,落後於slave複製。例項啟動後,自動啟動複製,mysql根據這兩個落後的檔案來啟動的複製,實際上就是將一些relay-log重放了,從而導致了主鍵衝突。既然是重放,都是主鍵操作,選擇跳過異常。

而要避免這個問題的話,可以將上述幾個引數設定為1,每處理一個slave event後就重新整理relay.infomaster.info。這樣最多丟失一個event影響的記錄。

但是這幾個引數設定為1的話,對磁碟的效能還是有一定的消耗,每一個event都重新整理磁碟,必定對磁碟的訪問增加。和開啟sync-binlog道理一樣,這就需要在效能和安全之間做一個權衡。只要從庫和master配置差不多的話,配置為1的問題,對效能影響不大,畢竟master還為了安全還設定了sync-binlog=1



























來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22418990/viewspace-1309000/,如需轉載,請註明出處,否則將追究法律責任。

相關文章