MySQL 主備延遲有哪些坑?主備切換策略
大家好,我是Tom哥!
作為一名開發(fā)同學(xué),大家對 MySQL 一定不陌生,像常見的 事務(wù)特性、隔離級別 、索引等也都是老生常談。
今天,我們就來聊個深度話題,關(guān)于 MySQL 的 高可用。
一、什么是高可用?
維基百科定義:
高可用性(high availability,縮寫 HA),指系統(tǒng)無中斷地執(zhí)行其功能的能力,代表系統(tǒng)的可用性程度。高可用性通常通過提高系統(tǒng)的容錯能力來實(shí)現(xiàn)。
MySQL 的高可用是如何實(shí)現(xiàn)的呢?
首先,我們來看張圖:
過程:
- 開始時,處理流程主要是 場景一;
- 客戶端讀、寫,訪問的是主庫;
- 主庫通過某種機(jī)制,將數(shù)據(jù)實(shí)時同步給備庫;
- 當(dāng)主庫突然發(fā)生故障(如:磁盤損壞等),無法正常響應(yīng)客戶端的請求。此時會自動主備切換,進(jìn)入 場景二;
- 客戶端讀寫,訪問的是備庫(此時備庫升級為新主庫);
看似天衣無縫,那是不是可以高枕無憂了呢???兄弟,想多了。
主備切換,確實(shí)能滿足高可用。但有個前提,主備庫的數(shù)據(jù)要同步。
不過,數(shù)據(jù)同步是個異步操作,不可能做到實(shí)時,所以說主備延遲是一定存在的。
二、什么是主備延遲?
主庫完成一個事務(wù),寫入binlog。binlog 中有一個時間字段,用于記錄主庫寫入的時間【時刻 t1】;
- binlog 同步給備庫,備庫接收并存儲到中繼日志 【時刻 t2】;
- 備庫SQL執(zhí)行線程執(zhí)行binlog,數(shù)據(jù)寫入到備庫表中 【時刻 t3】;
主備延遲時間計算公式:t3 - t1
有沒有簡單命令,直接查看。在備庫執(zhí)行 show slave status 命令。
seconds_behind_master,表示當(dāng)前備庫延遲了多少秒。
心細(xì)的同學(xué)會有疑問了, t3 和 t1 分屬于兩臺機(jī)器,如果時鐘不一致怎么辦?
初始化時,備庫連接到主庫,會執(zhí)行 SELECT UNIX_TIMESTAMP() 來獲得當(dāng)前主庫的系統(tǒng)時間。
如果發(fā)現(xiàn)主庫的系統(tǒng)時間與備庫不一致,備庫在計算 seconds_behind_master 會自動減掉這個差值。
注意:
binlog 數(shù)據(jù)傳輸?shù)臅r間(t2 - t1)非常短,可以忽略。主要延遲花費(fèi)在備庫執(zhí)行binlog日志。
三、主備延遲常見原因
1.備庫機(jī)器配置差
這個不難理解,“門當(dāng)戶對”、“志同道合”,如果主備機(jī)器的性能差別大,直接導(dǎo)致備庫的同步速度跟不上主庫的生產(chǎn)節(jié)奏。
就像跑步一樣,落后差距會越來越大。
解決方案:升級備庫的機(jī)器配置
2.備庫干私活
備庫除了服務(wù)于正常的讀業(yè)務(wù)外,是否有被其他特殊業(yè)務(wù)征用,如:運(yùn)營數(shù)據(jù)統(tǒng)計等,這類操作非常消耗系統(tǒng)資源,也會影響數(shù)據(jù)同步速度。
解決方案:可以借助大數(shù)據(jù)平臺,數(shù)據(jù)異構(gòu),滿足各種這些特殊的統(tǒng)計類查詢。
3.大事務(wù)
我們知道 binglog 是在事務(wù)提交時才生成的。
如果是處理大事務(wù),執(zhí)行時間比較長(比如 5分鐘)。雖然備庫很快拿到 binlog,但是在備庫回放執(zhí)行也要花費(fèi)差不多的時間,也要 5分鐘 (備庫中,只有這個事務(wù)執(zhí)行完提交,備庫才真正對外可見),從而導(dǎo)致主備延遲很大。
比如 delete 操作,慎用 delete from 表名,建議采用分批刪除,減少大事務(wù)。
四、主庫不可用,主備切換有哪些策略?
1.可靠優(yōu)先
當(dāng)主庫A 發(fā)生故障不可用時,開始進(jìn)入主備切換。
- 首先,判斷 B庫 seconds_behind_master 是否小于設(shè)定的閾值(比如 4 秒),如果滿足條件
- 將 A庫 改為只讀狀態(tài),將 readonly 設(shè)置為 true。斷掉 A 庫的寫入操作,保證不會有新的寫流量進(jìn)來
- 判斷 B庫的 seconds_behind_master ,直到為 0
- 修改 B庫 為 讀、寫狀態(tài)
- 客戶端的請求打到 B庫
此時,主備切換完成。
優(yōu)點(diǎn):
數(shù)據(jù)不會丟失,所以我們稱為可靠性高。
缺點(diǎn):
中間有個階段,A庫和B庫都是只讀狀態(tài),此時系統(tǒng)對外不能提供寫服務(wù)。
2.可用優(yōu)先
當(dāng)然我們也可以不用等主備數(shù)據(jù)同步完成,在一開始時就直接將流量切到備庫。
這樣備庫的流量就可能有兩個來源:
- 主庫之前的剩余流量 binlog;
- 客戶端新請求進(jìn)來的流量。
兩部分流量沖擊,會對 數(shù)據(jù)一致性 造成一些影響。
我們來做個實(shí)驗:
首次創(chuàng)建一個用戶表:
CREATE TABLE `person` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
插入2條記錄:
insert into person(name) values ("tom");
insert into person(name) values ("jerry");
實(shí)驗一:
將 binlog 的格式設(shè)為 binlog_format=row;
說明:row 模式,寫 binlog 時會記錄所有字段的值;
庫A 、庫B 在做數(shù)據(jù)同步時,都會報主鍵沖突,最后只有一行數(shù)據(jù)不一致,但是會丟數(shù)據(jù)。
優(yōu)點(diǎn):同步過程中,出現(xiàn)問題能夠及時發(fā)現(xiàn)。
實(shí)驗二:
將 binlog 格式設(shè)置為 statement 或者 mixed;
按照 SQL 原始語句同步 binlog,可以看到,數(shù)據(jù)條數(shù)不會少,但是主鍵id會出現(xiàn)混亂。
3.結(jié)論
本著 "攘外必先安內(nèi)" ,保證內(nèi)部的數(shù)據(jù)的正確性是我們的首選。所以,一般建議大家選擇 可靠優(yōu)先。
但是可靠優(yōu)先可能會導(dǎo)致一定時間內(nèi),數(shù)據(jù)庫不可用。這個時間值取決于主備延遲的時間大小。
所以,我們應(yīng)盡可能縮短主備庫的延遲時間大小,這樣一旦主庫發(fā)生故障,備庫才會更快的同步完數(shù)據(jù),主備切換才能完成,服務(wù)才能更快恢復(fù)。