今天遇到一個問題,Mysql
持續報錯,主從同步延時數過大或錯誤。因此這篇文章給你們分享下主從同步的機制原理以及問題排查思路。mysql
最直觀的表現爲:sql
mysql> show slave status\G; // 狀態一 Seconds_Behind_Master: NULL // 狀態二 Seconds_Behind_Master: 0 // 狀態三 Seconds_Behind_Master: 79
連續查詢,大部分時間該屬性值=0
,偶發性出現Null
或者79
等延時值。致使觀察主從同步延時的監控持續報警。數據庫
多臺備機的server-id
一致,致使主機沒法長時間同某一臺備機鏈接,進而沒法正常同步。vim
修改server-id
後,重啓數據庫恢復。服務器
MySQL
的主從同步,又稱爲複製(replication
),是一種內置的高可用高性能集羣解決方案,主要功能有:架構
數據分佈
:同步不須要很大帶寬,能夠實現多數據中心複製數據。讀取的負載均衡
:經過服務器集羣,能夠經過DNS
輪詢、Linux LVS
等GSLB
(全局負載均衡)方式,下降主服務器的讀壓力。數據庫備份
:複製是備份的一部分,但並不能代替備份。還須要與快照相結合。高可用性和故障轉移
:從服務器能夠快速切換爲主服務器,減小故障的停機時間和恢復時間。主從同步分爲3步:app
master
)把數據更改記錄到二進制日誌(binlog
)中。slave
)把主服務器的二進制日誌複製到本身的中繼日誌(relay log
)中。主從同步是一個異步實時的同步,會實時的傳輸,但存在執行上的延時,若是主服務器壓力很大,延時也會相應擴大。負載均衡
經過上面的圖,能夠看到一共須要3個線程:異步
I/O
線程:負責讀取主服務器的二進制日誌,並保存爲中繼日誌SQL
線程,負責執行中繼日誌MySQL
線程咱們可使用show full processlist;
命令來查看MySQL
的狀態:post
主機的狀態:
備機的狀態:
能夠看到,個人集羣架構爲1臺主機、4臺備機,因此在主機中有4個同步線程(已經發送全部的binlog
數據到備機,等待binlog
日誌更新),1個查看命令線程(show full processlist
)。在備機中有1個查看命令線程,1個I/O
線程(等待主機發送同步數據事件),1個SQL
線程(已經讀取了全部中繼日誌,等待I/O
線程來更新它)。
由於主從同步是異步實時的,也就是會存在延時的狀況,咱們能夠經過show slave status;
來查看備機上的同步延時:
在主從同步中咱們須要關注的一些屬性,已經給你們標紅了:
Slave_IO_State
: 當前I/O
線程的狀態Master_Log_File
: 當前同步的主服務器的二進制文件Read_Master_Log_Pos
: 當前同步的主服務器的二進制文件的偏移量,單位爲字節,如圖中爲已經同步了12.9M(13630580/1024/1024)
的內容Relay_Master_Log_File
: 當前中繼日誌同步的二進制文件Slave_IO_Running
: 從服務器中I/O
線程的運行狀態,YES
爲運行正常Slave_SQL_Running
: 從服務器中SQL
線程的運行狀態,YES
爲運行正常Exec_Master_Log_Pos
: 表示同步完成的主服務器的二進制日誌偏移量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
進程,報警恢復。
最終來看,這個問題的解決很是簡單,但從剛開始的迷茫到最後的思路清晰,都是咱們排查問題所常見的,這篇文章的主要收穫是讓你明白主從同步的機制和追查問題的思路,但願下次咱們都能很快的解決主從同步帶給咱們的問題。