如何解決 MySQL 主從延時問題?
大家好呀,我是樓仔。
最近面試了十幾個同學(xué),關(guān)于 MySQL 主從延時問題,我一般都會問。
- MySQL 主從延時的原因是什么?
- 具體哪個環(huán)節(jié)發(fā)生延時?
- 如何解決呢?
對于這“三連問”,極少有同學(xué)能通關(guān),甚至有同學(xué)連主從復(fù)制原理都不清楚。
這個并不是存粹的八股文,因為在實際工作場景中,很多同學(xué)都遇到過。
不 BB,上文章目錄。
一、什么是主從延時?
有時候我們遇到從數(shù)據(jù)庫中獲取不到信息的詭異問題時,會糾結(jié)于代碼中是否有一些邏輯會把之前寫入的內(nèi)容刪除,但是你又會發(fā)現(xiàn),過了一段時間再去查詢時又可以讀到數(shù)據(jù)了,這基本上就是主從延遲在作怪。
主從延遲,其實就是“從庫回放” 完成的時間,與 “主庫寫 binlog” 完成時間的差值,會導(dǎo)致從庫查詢的數(shù)據(jù),和主庫的不一致。
二、為什么會主從延時?
探討這個問題前,我們需要知道主從復(fù)制的原理。
1.主從復(fù)制原理
MySQL 的主從復(fù)制是依賴于 binlog,也就是記錄 MySQL 上的所有變化并以二進制形式保存在磁盤上二進制日志文件。
主從復(fù)制就是將 binlog 中的數(shù)據(jù)從主庫傳輸?shù)綇膸焐希话氵@個過程是異步的,即主庫上的操作不會等待 binlog 同步地完成。
詳細流程如下:
- 主庫寫 binlog:主庫的更新 SQL(update、insert、delete) 被寫到 binlog;
- 主庫發(fā)送 binlog:主庫創(chuàng)建一個 log dump 線程來發(fā)送 binlog 給從庫;
- 從庫寫 relay log:從庫在連接到主節(jié)點時會創(chuàng)建一個 IO 線程,以請求主庫更新的 binlog,并且把接收到的 binlog 信息寫入一個叫做 relay log 的日志文件;
- 從庫回放:從庫還會創(chuàng)建一個 SQL 線程讀取 relay log 中的內(nèi)容,并且在從庫中做回放,最終實現(xiàn)主從的一致性。
2.主從延時原因
我們分析一下主從復(fù)制的過程。
MySQL 的主從復(fù)制都是單線程的操作,主庫對所有 DDL 和 DML 產(chǎn)生 binlog,binlog 是順序?qū)?,所以效率很高?/p>
Slave 的 Slave_IO_Running 線程會到主庫取日志,放入 relay log,效率會比較高。
Slave 的 Slave_SQL_Running 線程將主庫的 DDL 和 DML 操作都在 Slave 實施,DML 和 DDL 的 IO 操作是隨機的,不是順序的,因此成本會很高。
還可能是 Slave 上的其他查詢產(chǎn)生 lock 爭用,由于 Slave_SQL_Running 也是單線程的,所以一個 DDL 卡住了,需要執(zhí)行 10 分鐘,那么所有之后的 DDL 會等待這個 DDL 執(zhí)行完才會繼續(xù)執(zhí)行,這就導(dǎo)致了延時。
總結(jié)一下主從延遲的主要原因:主從延遲主要是出現(xiàn)在 “relay log 回放” 這一步,當(dāng)主庫的 TPS 并發(fā)較高,產(chǎn)生的 DDL 數(shù)量超過從庫一個 SQL 線程所能承受的范圍,那么延時就產(chǎn)生了,當(dāng)然還有就是可能與從庫的大型 query 語句產(chǎn)生了鎖等待。
三、如何解決主從延時?
1.主從延遲情況
我們先看看,哪些情況會導(dǎo)致主從延時:
- 從庫機器性能:從庫機器比主庫的機器性能差,只需選擇主從庫一樣規(guī)格的機器就好。
- 從庫壓力大:可以搞了一主多從的架構(gòu),還可以把 binlog 接入到 Hadoop 這類系統(tǒng),讓它們提供查詢的能力。
- 從庫過多:要避免復(fù)制的從節(jié)點數(shù)量過多,從庫數(shù)據(jù)一般以3-5個為宜。
- 大事務(wù):如果一個事務(wù)執(zhí)行就要 10 分鐘,那么主庫執(zhí)行完后,給到從庫執(zhí)行,最后這個事務(wù)可能就會導(dǎo)致從庫延遲 10 分鐘啦。日常開發(fā)中,不要一次性 delete 太多 SQL,需要分批進行,另外大表的 DDL 語句,也會導(dǎo)致大事務(wù)。
- 網(wǎng)絡(luò)延遲:優(yōu)化網(wǎng)絡(luò),比如帶寬 20M 升級到 100M。
- MySQL 版本低:低版本的 MySQL 只支持單線程復(fù)制,如果主庫并發(fā)高,來不及傳送到從庫,就會導(dǎo)致延遲,可以換用更高版本的 MySQL,支持多線程復(fù)制。
2.主從延時解決方案
面試時,有些同學(xué)能回答出使用緩存、查詢主庫、提升機器配置等,僅僅這些么?
最容易想到的方法,縮短主從同步時間:
- 提升從庫機器配置,可以和主庫一樣,甚至更好;
- 避免大事務(wù);
- 搞多個從庫,即一主多從,分擔(dān)從庫查詢壓力;
- 優(yōu)化網(wǎng)絡(luò)寬帶;
- 選擇高版本 MySQL,支持主庫 binlog 多線程復(fù)制。
也可以從業(yè)務(wù)場景考慮:
- 使用緩存:我們在同步寫數(shù)據(jù)庫的同時,也把數(shù)據(jù)寫到緩存,查詢數(shù)據(jù)時,會先查詢緩存,不過這種情況會帶來 MySQL 和 Redis 數(shù)據(jù)一致性問題。
- 查詢主庫:直接查詢主庫,這種情況會給主庫太大壓力,核心場景可以使用,比如訂單支付。
如果能把上面基本回答出來,就已經(jīng)非常厲害了,還有么?
其實還可以在 MySQL 架構(gòu)上來考慮。
主庫對數(shù)據(jù)安全性較高,設(shè)置配置如下:
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
而 slave 不需要這么高的數(shù)據(jù)安全,完全可以將 sync_binlog 設(shè)置為 0,或者關(guān)閉 binlog,innodb_flushlog 也可以設(shè)置為 0,來提高 sql 的執(zhí)行效率。
架構(gòu)方案:使用多臺 slave 來分攤讀請求,再從這些 slave 中取一臺專用的服務(wù)器,只作為備份用,不進行其他任何操作,比如設(shè)置 sync_binlog 為0,或者關(guān)閉 binglog 等,提升從庫查詢性能。
再問一下,還有么?可以文末私信我哈~~
四、后記
再回過頭來看這個問題,估計很多同學(xué)能回答出一二,但是這個不能成為你的加分項。
面對如此激烈的競爭環(huán)境,同樣一個問題,你就需要比別人掌握得更多,回答得更全面,面試官才能對你刮目相看。
其實我當(dāng)年面試小米時,也面試過這個問題,當(dāng)時就是基于上面回答的。
后來的一次 MySQL 分享,講得還不錯,當(dāng)時我們主管就說,樓仔的 MySQL 掌握得挺好的,記得當(dāng)時面試時,我就問過一個 MySQL 主從復(fù)制問題,他都能回答到非常底層。
我沒想到,這都一年多了,當(dāng)時的那場面試,居然給我主管留下那么深刻的映像。