MYSQL主備的延遲時間確認

MySQL 本身通過 show slave status 提供了 Seconds_Behind_Master ,用於衡量主備之間的複製延遲,但是今天碰到了一個場景,發現 Seconds_Behind_Master 爲 , 備庫的 show slave status 顯示 IO/SQL 線程都是正常的 , MySQL 的主庫上的變更卻長時間無法同步到備庫上。如果沒有人爲干預,直到一個小時以後, MySQL 纔會自動重連主庫,繼續複製主庫的變更。

影響範圍: MySQL , Percona , MariaDB 的所有版本。


雖然這種場景非常特殊,遇到的概率並不高,但是個人覺得有必要提醒一下使用 MySQL 的 DBA 們。通過對這個場景的分析,也有助於我們更加深入的理解 MySQL replication 重試機制。


   一、重現步驟

搭建主備的複製,臨時斷開主庫的網絡,並 kill 掉主庫 MySQL 的 binlog dump 線程。

此時觀察備庫的複製情況, show slave status 中:

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

Seconds_Behind_Master: 0

但是此時你把網絡恢復以後,在主庫做任何變更,備庫都無法獲得數據更新了。而且備庫上的show slave status 顯示: IO 線程 SQL 線程一切正常,複製延遲一直是 

一切正常,普通的監控軟件都不會發現備庫有數據延遲。


   二、原理分析

MySQL 的 Replication 是區別於其他數據庫很關鍵的地方。也是可擴展性和高可用的基礎。它本身已經非常智能化,只需要我們調用 Change Master 指定 Binlog 文件名和偏移位置就可以搭建從主庫到備庫的複製關係。

MySQL 複製 線程 會自動將目前複製位置記錄下來,在主備複製中斷的時候自動連上主庫,並從上次中斷的位置重新開始複製。這些操作都是全自動化的,不需要人爲的干預。這給了 MySQL DBA 帶來了很多便利,同時卻也隱藏了很多細節。

要真正的理解前面問題的真相以及怎麼解決這個問題,我們還是需要真正的理解 MySQL  複製的原理。


   2.1“推”還是“拉”

首先, MySQL 的複製是“推”的,而不是“拉”的。“拉”是指 MySQL 的備庫不斷的循環詢問主庫是否有數據更新,這種方式資源消耗多,並且效率低。“推”是指 MySQL 的主庫在自己有數據更新的時候推送這個變更給備庫,這種方式只有在數據有變更的時候纔會發生交互,資源消耗少。如果你是程序員出身,你一定會選擇“推”的方式。

那麼 MySQL 具體是怎麼“推”的列,實際上備庫在向主庫申請數據變更記錄的時候,需要指定從主庫Binlog 的哪個文件 MASTER_LOG_FILE 的具體多少個字節偏移位置 MASTER_LOG_POS 。對應的,主庫會啓動一個 Binlog dump 的線程,將變更的記錄從這個位置開始一條一條的發給備庫。備庫一直監聽主庫過來的變更,接收到一條,纔會在本地應用這個數據變更。


   2.2 原因解析

從上面的分析,我們可以大致猜到爲什麼 show slave status 顯示一切正常,但是實際上主庫的變更都無法同步到備庫上來:

出現問題的時候, Binlog dump 程序被我們 kill 掉了。作爲監聽的一方,備庫一直沒有收到任何變更,它會認爲主庫上長時間沒有任何變更,導致沒有變更數據推送過來。備庫是無法判斷主庫上對應的Binlog dump 線程 到底是意外終止了,還是長時間沒有任何數據變更的。所以,對這兩種情況來說,備庫都顯示爲正常。

當然, MySQL 會盡量避免這種情況。比如:

l  在 Binlog dump 被 kill 掉時通知備庫 線程 被 kill 掉了。所以我們重現時需要保證這個通知發送不到備庫,也就是說該問題重現的關鍵在於 Binlog dump 被 kill 的消息由於網絡堵塞或者其他原因無法發送到備庫。

l  備庫如果長時間沒有收到從主庫過來的變更,它會每隔一段時間重連主庫。


   2.3 問題避免

基於上面的分析,我們知道 MySQL 在這種情況下確實無法避免,那麼我們可以有哪些辦法可以避開列:

1.  被動處理:修改延遲的監控方法,發現問題及時處理。

2.  主動預防:正確設置 --master-retry-count ,  --master-connect-retry ,  --slave-net-timeout 複製重試參數。


l  被動處理

MySQL 的延遲監控大部分直接採集 show slave status 中的  Seconds_Behind_Master 。這種情況下,Seconds_Behind_Master 就無法用來真實的衡量主備之間的複製延遲了。我們建議通過在主庫輪詢插入時間信息,並通過複製到備庫的時間差來獲得主備延遲的方案。 Percona 提供了一種類似的方案 pt-heartbeat 

發現這個問題以後,我們只需要 stop slave; start slave; 重啓複製就能解決這個問題。


l  主動預防

MySQL 可以指定三個參數,用於複製線程重連主庫: --master-retry-count ,  --master-connect-retry,  --slave-net-timeout 

其中 master-connect-retry 和 master-retry-count 需要在 Change Master 搭建主備複製時指定,而 slave-net-timeout 是一個全局變量,可以在 MySQL 運行時在線設置。

具體的重試策略爲:備庫過了 slave-net-timeout 秒還沒有收到主庫來的數據,它就會開始第一次重試。然後每過 master-connect-retry 秒,備庫會再次嘗試重連主庫。直到重試了 master-retry-count 次,它纔會放棄重試。如果重試的過程中,連上了主庫,那麼它認爲當前主庫是好的,又會開始 slave-net-timeout 秒的等待。

slave-net-timeout 的默認值是 3600 秒, master-connect-retry 默認爲 60 秒, master-retry-count 默認爲 86400 次。也就是說,如果主庫一個小時都沒有任何數據變更發送過來,備庫纔會嘗試重連主庫。這就是爲什麼在我們模擬的場景下,一個小時後,備庫纔會重連主庫,繼續同步數據變更的原因。

這樣的話,如果你的主庫上變更比較頻繁,可以考慮將 slave-net-timeout 設置的小一點,避免主庫Binlog dump 線程 終止了,無法將最新的更新推送過來。

當然 slave-net-timeout 設置的過小也有問題,這樣會導致如果主庫的變更確實比較少的時候,備庫頻繁的重新連接主庫,造成資源浪費。

因此我們可以採用了類似於 pt-heartbeat 的方式對主備進行復制延遲監控。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章