MySQL#復(fù)制 雙Yes的假死故障造成主從不一致
點(diǎn)擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)”
回復(fù)”669“獲取獨(dú)家整理的精選資料集
回復(fù)”加群“加入全國(guó)服務(wù)端高端社群「后端圈」
? 作者 | 神諭丶
復(fù)制雙YES,延遲也為0,但主庫(kù)新寫(xiě)入的數(shù)據(jù)在從庫(kù)查不到,主從數(shù)據(jù)已經(jīng)不一致了。我稱(chēng)這種情況為“復(fù)制假死”。
很多DBA配置“主從復(fù)制是否異?!钡谋O(jiān)控是依賴(lài)SHOW SLAVE STATUS的輸出,看如下兩個(gè)值是否為Yes,若其中一個(gè)不為Yes,會(huì)認(rèn)為復(fù)制狀態(tài)異常。
Slave_IO_Running:?Yes
Slave_SQL_Running:?Yes
但在一些場(chǎng)景下,可能會(huì)造成ro節(jié)點(diǎn)不知自己已經(jīng)和主庫(kù)失聯(lián)了?,F(xiàn)象和影響就是,復(fù)制狀態(tài)正常,但從庫(kù)的數(shù)據(jù)已經(jīng)不對(duì)了。如一些容災(zāi)場(chǎng)景時(shí),新的主庫(kù)已經(jīng)接管業(yè)務(wù),并產(chǎn)生了新的binlog events,但從庫(kù)查不到也沒(méi)有報(bào)錯(cuò)。
這種失聯(lián)導(dǎo)致的復(fù)制假死場(chǎng)景,可能有很多,但可以圍繞以下點(diǎn)來(lái)排查:
主庫(kù)自己掛了,沒(méi)來(lái)得及通知從庫(kù)。 主庫(kù) Binlog Dump線(xiàn)程不干活(比如掛了因?yàn)榉N種原因沒(méi)拉起)。Binlog Dump想干活但是突然沒(méi)網(wǎng)了,沒(méi)法通知從庫(kù)。……
如果想模擬也比較簡(jiǎn)單,建立一個(gè)最簡(jiǎn)單的主從關(guān)系。給主庫(kù)來(lái)個(gè)偷襲,不要講武德,在主庫(kù)OS上來(lái)一發(fā):
ifconfig?eth0?down
此時(shí)在主庫(kù)上寫(xiě)數(shù)據(jù),從庫(kù)會(huì)看起來(lái)一切正常。(如果配置了半同步,第一次寫(xiě)數(shù)據(jù)時(shí),默認(rèn)會(huì)等待10秒。rpl_semi_sync_master_timeout=10000)。
這種情況在生產(chǎn)環(huán)境也是存在的,如網(wǎng)絡(luò)環(huán)境極差。(需要考慮如何監(jiān)控覆蓋這種場(chǎng)景)。
直接原因很好理解,如上所說(shuō),從庫(kù)節(jié)點(diǎn)的IO_Thread不知道原主庫(kù)已經(jīng)掛了,還在憨等主庫(kù)的Binlog Dump線(xiàn)程的新推送。
相關(guān)配置:
對(duì)于這種情況,MySQL提供了幾個(gè)超時(shí)參數(shù)可供配置:
slave_net_timeout:
可接受的Binlog Dump線(xiàn)程的無(wú)響應(yīng)時(shí)間(秒)。超過(guò)這個(gè)時(shí)間,從庫(kù)認(rèn)為主庫(kù)連接已經(jīng)丟失連接,并嘗試重新建立連接。默認(rèn)3600秒??梢詫?xiě)在配置文件,其實(shí)它是一個(gè)全局參數(shù)。master_connect_retry:
IO_Thraed嘗試重新建立連接失敗后,再次嘗試所間隔的時(shí)間(秒)。默認(rèn)60秒。通過(guò)CHANGE MASTER指定,存于master info中。master_retry_count:
最大嘗試的次數(shù)。超過(guò)這個(gè)值后就不嘗試重連了,并將Slave_IO_Running設(shè)置為No,默認(rèn)為86400次。通過(guò)CHANGE MASTER指定,存于master info中。
三個(gè)參數(shù)揉在一起就是:
超過(guò)slave_net_timeout秒,如果沒(méi)有新的binlog events發(fā)送過(guò)來(lái),從庫(kù)認(rèn)為已經(jīng)和主庫(kù)斷開(kāi)了連接,這時(shí)IO_Thread嘗試重新建立連接。
重連等待的時(shí)間取決于master_connect_retry。
并且嘗試次數(shù)不超過(guò)master_retry_count。(如果明顯知道連接已經(jīng)斷開(kāi),則該參數(shù)不生效。)

?圖源哪里我忘記了,可能是什么percona的博客,這個(gè)學(xué)習(xí)筆記其實(shí)是幾年前寫(xiě)的。。最近才整理。
所以上面復(fù)制假死的問(wèn)題,其實(shí)將@@slave_net_timeout設(shè)置為一個(gè)較小的值就可以了,比如可以是60,可以是30,可以是10。這樣從庫(kù)可以很快發(fā)現(xiàn)自己或主庫(kù)已經(jīng)掉線(xiàn)了,即便是無(wú)法重連到正確的主庫(kù)上,也可以很快將故障告出來(lái),而不是表面上雙Yes。(修改好了記得重啟IO線(xiàn)程)
該值默認(rèn)是1個(gè)小時(shí),所以也有一些從庫(kù)監(jiān)控上會(huì)看到延遲突增到1個(gè)小時(shí),又緩慢降下來(lái)的情況。
那如果主庫(kù)真的沒(méi)有新增的binlog events可以推送,從庫(kù)等待@@slave_net_timeout就要去嘗試重連,豈不是有點(diǎn)僵?

還有個(gè)叫master_heartbeat_period的家伙可供配置,該值也存于master info中,默認(rèn)是@@slave_net_timeout的一半。作用和名字一樣,主庫(kù)向從庫(kù)發(fā)送心跳包的間隔時(shí)間,這樣從庫(kù)就知道自己的主庫(kù)不是掛了,或者只是沒(méi)有新的binlog events產(chǎn)生。
另,上面提到的master info其實(shí)是指mysql.slave_master_info(當(dāng)master_info_repository=TABLE時(shí))
相關(guān)的監(jiān)控:
5.5\5.6 可以通過(guò)SHOW GLOBAL STATUS LIKE '%heart%';來(lái)查看相關(guān)狀態(tài):
mysql>?SHOW?GLOBAL?STATUS?LIKE?'%heart%';
+---------------------------+-------+
|?Variable_name?????????????|?Value?|
+---------------------------+-------+
|?Slave_heartbeat_period????|?0.000?|???
--?表示心跳間隔時(shí)間的配置信息
|?Slave_last_heartbeat??????|???????|???
--?5.6新增,表示最后一次收到心跳的時(shí)間
|?Slave_received_heartbeats?|?0?????|???
--?表示總共收到的心跳次數(shù)
+---------------------------+-------+
3?rows?in?set?(0.00?sec)
5.7+ 可以通過(guò)performance_schema.replication_connection_status來(lái)檢查這幾個(gè)狀態(tài)。
mysql>?SELECT?*?FROM?performance_schema.replication_connection_status\G
***************************?1.?row?***************************
?????????????CHANNEL_NAME:?
???????????????GROUP_NAME:?
??????????????SOURCE_UUID:?
????????????????THREAD_ID:?NULL
????????????SERVICE_STATE:?CONNECTING
COUNT_RECEIVED_HEARTBEATS:?0
?LAST_HEARTBEAT_TIMESTAMP:?0000-00-00?00:00:00
?RECEIVED_TRANSACTION_SET:?
????????LAST_ERROR_NUMBER:?2003
???????LAST_ERROR_MESSAGE:?error?connecting?to?master?'1@1:3306'?
???????-?retry-time:?60??retries:?1
?????LAST_ERROR_TIMESTAMP:?2020-11-11?17:00:46
1?row?in?set?(0.00?sec)
--?這里是我的實(shí)驗(yàn)環(huán)境,隨便配置了一個(gè)從庫(kù)。
p.s. 但雙YES且Seconds_Behind_Master=0不一定是上面這種假死,還有很多其他的情況也會(huì)造成Seconds_Behind_Master=0,但實(shí)際上主從數(shù)據(jù)不一致,這個(gè)是另一篇文章要寫(xiě)的了。
— 本文結(jié)束 —

●?漫談設(shè)計(jì)模式在 Spring 框架中的良好實(shí)踐
關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。
對(duì)「服務(wù)端思維」有期待,請(qǐng)?jiān)谖哪c(diǎn)個(gè)在看
喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈


