十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
先前碰到一個(gè)故障,于是引入了crash-safe replication,下面仔細(xì)描述;
故障描述:
從庫(slave端)宕機(jī),重啟后,mysql同步發(fā)現(xiàn)有數(shù)據(jù)主鍵沖突;
故障分析:
從庫宕機(jī)后,從庫的mysql服務(wù)遭到非正常退出,部分?jǐn)?shù)據(jù)可能未刷新到磁盤;但這個(gè)案例是已經(jīng)有數(shù)據(jù)刷新到磁盤了.重啟后,從庫又重新從主庫拉取了這部分?jǐn)?shù)據(jù),再次進(jìn)行了應(yīng)用,所以導(dǎo)致數(shù)據(jù)沖突了.所以接下來就要分析主從相關(guān)的一些參數(shù)了;
先說說,主從同步的那點(diǎn)事兒.
所謂主從同步,就是主庫在生成binlog后,從庫拉取主庫的binlog,然后將數(shù)據(jù)應(yīng)用到從庫的過程;
同步分為半同步和異步同步.這個(gè)案例是異步,半同步就不細(xì)說了.異步同步是指,在主庫生成binlog后,從庫拉取主庫的binlog應(yīng)用到從庫本機(jī)的過程;
那這里就要重點(diǎn)介紹幾個(gè)名詞信息了:
IO_thread
SQL_thread
master-info.log
relay-info.log
IO_tread和SQL_thread,經(jīng)常搭建主從的同學(xué)都知道,這是從庫上面用于同步的兩個(gè)關(guān)鍵線程(show processlist可以看到);
master-info.log和relay-info.log是記錄從庫同步位置和狀態(tài)等一些信息.
來看下這幾個(gè)名詞間的聯(lián)系:
從主庫生成binlog開始,從庫拉取binlog到本機(jī),傳輸完成后,IO_thread會(huì)將拉取到的binlog的文件名及事務(wù)位置(postion和gtid)記錄到master-info.log,同時(shí),SQL_thread會(huì)將拉取到的binlog應(yīng)用到本地,應(yīng)用完成后會(huì)將完成的binlog文件名和事務(wù)位置(postion和gtid)寫入到relay-info.log.
這是整個(gè)的同步過程.(注意:這兩個(gè)文件記錄的binlog相關(guān)信息都是主庫的信息,從庫的binlog是不會(huì)記錄到這兩個(gè)文件的.)
這個(gè)過程有兩點(diǎn)需要注意:
1.在默認(rèn)配置的情況下,master-info.log和relay-info.log文件系統(tǒng)層面完成寫入操作的.也就是說mysql在將更改信息完成后提交給OS的緩存,什么時(shí)候刷盤是由OS決定的.
2.如果從庫宕機(jī),重啟后,會(huì)去讀取master-info.log的位置信息.5.6后啟用了relay_log_recovery參數(shù),將讀取relay-info.log的位置,而不讀取master-info.log;
那么結(jié)合這個(gè)案例,我們就很清晰的知道問題出在哪了.
1.IO_thread拉取完數(shù)據(jù),master_info的更改信息在OS的緩存里,還未更改文件,同時(shí),SQL_thread已經(jīng)應(yīng)用完數(shù)據(jù),這個(gè)時(shí)候宕機(jī)了.那就造成了,master-info.log未更新,但數(shù)據(jù)庫已經(jīng)將數(shù)據(jù)寫入了.重啟后,IO_thread根據(jù)未更新的master-info.log重新拉取了重復(fù)的數(shù)據(jù).
2.在啟用了relay_log_recovery后,重啟從庫后讀取的是relay-info.log文件,跟上面情況類似,也是未更新到relay-info.log,然后重新應(yīng)用了.
3.sync_relay_log和master_relay_log參數(shù)為1,這種情況會(huì)丟失最后一個(gè)事務(wù).導(dǎo)致最后同步的一個(gè)事務(wù)沖突.
解決方法:
查看沖突數(shù)據(jù)是否一致,要么在從庫刪除該數(shù)據(jù),讓從庫重新應(yīng)用,要么就跳過該錯(cuò)誤,繼續(xù)同步,具體方法不累述,網(wǎng)上大把大把的案例.
總結(jié):
主從異步同步,很多場(chǎng)景都會(huì)用到,主從不同步也是經(jīng)常發(fā)生.好在mysql一直在不斷的進(jìn)步,修改.到mysql5.7,主從架構(gòu)已經(jīng)相當(dāng)成熟了.你要相信,你踩到的坑,肯定有很多前輩已經(jīng)踩過很多次了,所以,放心大膽的用吧.為了讓大家少掉坑,我總結(jié)下使用異步同步的一些參數(shù)設(shè)置和一些坑.
主庫:1.binlog_format=row 能選用row格式,其他兩種就別考慮了,具體的坑太多了.
2.sync_binlog=1,innodb_flush_log_at_trx_commit=1 不要問我為什么.安全是數(shù)據(jù)庫的唯一標(biāo)準(zhǔn).
3.log_bin_trust_function_creators =1 這個(gè)開一下吧,備用,萬一被那個(gè)二貨給改了binlog行模式勒.
4.binlog_rows_query_log_events =1 這個(gè)挺有用的,記錄sql,row格式下,看binlog是挺不好看的.有這參數(shù),杠杠的.
從庫:master-info-repository=table
relay-log-info-repository=table 改成table吧... SQL_thread會(huì)吧更改relay-log-info放到應(yīng)用事務(wù)的同一個(gè)事務(wù)里面,這樣就實(shí)現(xiàn)了事務(wù)與日志修改的原子性了
relay_log_recovery = 1 讀的是relay-info的信息,而且會(huì)把未執(zhí)行的relay-log給刪掉,重新拉取.
sync_relay_log_info=1 這個(gè),如果relay-info為table的話,可用可不用.如果是file,加個(gè)保險(xiǎn)吧.
sync_master_info=1 能保證master-info的一致性.
crash-safe 不管是主庫還是從庫,都挺蛋疼的.上面主要講的還是crash-safe replication的一些參數(shù).總之保證安全的前提下,在去提升效率吧.如果你覺得可以犧牲安全來保證效率,那就忽略吧.