MySQL主從同步機制和同步延時問題追查

今天遇到一個問題,Mysql持續報錯,主從同步延時數過大或錯誤。所以這篇文章給大家分享下主從同步的機制原理以及問題排查思路。

故障表現

最直觀的表現爲:

mysql> show slave status\G;
    // 狀態一
    Seconds_Behind_Master: NULL
    // 狀態二
    Seconds_Behind_Master: 0
    // 狀態三
    Seconds_Behind_Master: 79

連續查詢,大部分時間該屬性值=0,偶發性出現Null或者79等延時值。導致觀察主從同步延時的監控持續報警。

故障原因及解決方案

多臺備機的server-id一致,導致主機無法長時間同某一臺備機連接,進而無法正常同步。

修改server-id後,重啓數據庫恢復。

主從同步機制

圖片描述

MySQL的主從同步,又稱爲複製(replication),是一種內置的高可用高性能集羣解決方案,主要功能有:

  1. 數據分佈:同步不需要很大帶寬,可以實現多數據中心複製數據。
  2. 讀取的負載均衡:通過服務器集羣,可以通過DNS輪詢、Linux LVSGSLB(全局負載均衡)方式,降低主服務器的讀壓力。
  3. 數據庫備份:複製是備份的一部分,但並不能代替備份。還需要與快照相結合。
  4. 高可用性和故障轉移:從服務器可以快速切換爲主服務器,減少故障的停機時間和恢復時間。

主從同步分爲3步:

  1. 主服務器(master)把數據更改記錄到二進制日誌(binlog)中。
  2. 從服務器(slave)把主服務器的二進制日誌複製到自己的中繼日誌(relay log)中。
  3. 從服務器重做中繼日誌中的日誌,把更改應用到自己的數據庫上,達到數據的一致性。

主從同步是一個異步實時的同步,會實時的傳輸,但存在執行上的延時,如果主服務器壓力很大,延時也會相應擴大。

通過上面的圖,可以看到一共需要3個線程:

  1. 主服務器的日誌傳送線程:負責將二進制日誌增量傳送到備機
  2. 從服務器的I/O線程:負責讀取主服務器的二進制日誌,並保存爲中繼日誌
  3. 從服務器的SQL線程,負責執行中繼日誌

查看MySQL線程

我們可以使用show full processlist;命令來查看MySQL的狀態:

主機的狀態:
圖片描述

備機的狀態:
圖片描述

可以看到,我的集羣架構爲1臺主機、4臺備機,所以在主機中有4個同步線程(已經發送所有的binlog數據到備機,等待binlog日誌更新),1個查看命令線程(show full processlist)。在備機中有1個查看命令線程,1個I/O線程(等待主機發送同步數據事件),1個SQL線程(已經讀取了所有中繼日誌,等待I/O線程來更新它)。

查看同步狀態

因爲主從同步是異步實時的,也就是會存在延時的情況,我們可以通過show slave status;來查看備機上的同步延時:

圖片描述

在主從同步中我們需要關注的一些屬性,已經給大家標紅了:

  1. Slave_IO_State: 當前I/O線程的狀態
  2. Master_Log_File: 當前同步的主服務器的二進制文件
  3. Read_Master_Log_Pos: 當前同步的主服務器的二進制文件的偏移量,單位爲字節,如圖中爲已經同步了12.9M(13630580/1024/1024)的內容
  4. Relay_Master_Log_File: 當前中繼日誌同步的二進制文件
  5. Slave_IO_Running: 從服務器中I/O線程的運行狀態,YES爲運行正常
  6. Slave_SQL_Running: 從服務器中SQL線程的運行狀態,YES爲運行正常
  7. Exec_Master_Log_Pos: 表示同步完成的主服務器的二進制日誌偏移量
  8. Seconds_Behind_Master: 表示從服務器數據比主服務器落後的持續時長

同樣可以通過show master status;命令來查看主服務器的運行狀態:
圖片描述

正常運行的主從同步狀態:

Slave_IO_Running: YES
Slave_SQL_Running: YES
Seconds_Behind_Master: 0

問題排查

在理解了主從同步的機制後,再來看今天遇到的問題,通過查看備機狀態,我們觀察在三種狀態下的幾個關鍵屬性值:

mysql> show slave status\G;
#狀態一:
    Slave_IO_State: Reconnecting after a failed master event read
    Slave_IO_Running: No
    Slave_SQL_Running: Yes
    Seconds_Behind_Master: NULL
#狀態二:
    Slave_IO_State: Waiting for master to send event
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
    Seconds_Behind_Master: 0
#狀態三:
    Slave_IO_State: Queueing master event to the relay log
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
    Seconds_Behind_Master: 636

通過MySQL主從複製線程狀態轉變,我們可以看到三種狀態的不同含義:

# 狀態一
# 線程正嘗試重新連接主服務器,當連接重新建立後,狀態變爲Waiting for master to send event。
Reconnecting after a failed master event read
# 狀態二
# 線程已經連接上主服務器,正等待二進制日誌事件到達。如果主服務器正空閒,會持續較長的時間。如果等待持續slave_read_timeout秒,則發生超時。此時,線程認爲連接被中斷並企圖重新連接。
Waiting for master to send event

# 狀態三
# 線程已經讀取一個事件,正將它複製到中繼日誌供SQL線程來處理。
Queueing master event to the relay log

在這裏,我們可以猜測,由於某些原因,從服務器不斷的和主服務器進行斷開並嘗試重連,重連成功後又再次斷開。

我們再看看主機的運行情況:
圖片描述

發現問題出在10.144.63.*10.144.68.*兩臺機器上,我們查看其中一臺的錯誤日誌:

190214 11:33:20 [Note] Slave: received end packet from server, apparent master shutdown: 
190214 11:33:20 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log 'mysql-bin.005682' at postion 13628070

拿到關鍵字Slave: received end packet from server, apparent master shutdown: Google搜索一下,在文章Confusing MySQL Replication Error Message中可以看到原因爲兩臺備機的server-id重複。

One day it happen to me, and took me almost an hour to find that out.
Moving foward I always use a base my.cnf to I copy to any other server and the first thing is to increase the server-id.
Could MySQL just use the servername intead of a numeric value?

問題修復

定位了問題,我們確認下是否重複,發現兩臺備機的該字段確實相同:

vim my.cnf

#replication
log-bin=mysql-bin
# 這個隨機數字相同導致的
server-id=177230069
sync_binlog=1

更改一個其他不同的數字,保存,重啓MySQL進程,報警恢復。

總結

最終來看,這個問題的解決非常簡單,但從剛開始的迷茫到最後的思路清晰,都是我們排查問題所常見的,這篇文章的主要收穫是讓你明白主從同步的機制和追查問題的思路,希望下次我們都能很快的解決主從同步帶給我們的問題。

參考資料

  1. 《MySQL基礎內幕 InnoDB存儲引擎 第2版》P8.7 複製
  2. MySQL主從複製線程狀態轉變: http://www.ywnds.com/?p=3821
  3. Confusing MySQL Replication Error Message: https://www.percona.com/blog/...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章