如何解決 MySQL 主從延時問題?

資料庫工作筆記發表於2023-11-01

來源:樓仔

大家好呀,我是樓仔。

最近面試了十幾個同學,關於 MySQL 主從延時問題,我一般都會問。

MySQL 主從延時的原因是什麼?

具體哪個環節發生延時?

如何解決呢?

對於這“三連問”,極少有同學能通關,甚至有同學連主從複製原理都不清楚。

這個並不是存粹的八股文,因為在實際工作場景中,很多同學都遇到過。

不 BB,上文章目錄。

如何解決 MySQL 主從延時問題?

01 什麼是主從延時?

有時候我們遇到從資料庫中獲取不到資訊的詭異問題時,會糾結於程式碼中是否有一些邏輯會把之前寫入的內容刪除,但是你又會發現,過了一段時間再去查詢時又可以讀到資料了,這基本上就是主從延遲在作怪。

主從延遲,其實就是“從庫回放” 完成的時間,與 “主庫寫 binlog” 完成時間的差值,會導致從庫查詢的資料,和主庫的不一致

02 為什麼會主從延時?

探討這個問題前,我們需要知道主從複製的原理。

2.1 主從複製原理

MySQL 的主從複製是依賴於 binlog,也就是記錄 MySQL 上的所有變化並以二進位制形式儲存在磁碟上二進位制日誌檔案。

主從複製就是將 binlog 中的資料從主庫傳輸到從庫上,一般這個過程是非同步的,即主庫上的操作不會等待 binlog 同步地完成。

如何解決 MySQL 主從延時問題?

詳細流程如下:

  1. 主庫寫 binlog:主庫的更新 SQL(update、insert、delete) 被寫到 binlog;
  2. 主庫傳送 binlog:主庫建立一個 log dump 執行緒來傳送 binlog 給從庫;
  3. 從庫寫 relay log:從庫在連線到主節點時會建立一個 IO 執行緒,以請求主庫更新的 binlog,並且把接收到的 binlog 資訊寫入一個叫做 relay log 的日誌檔案;
  4. 從庫回放:從庫還會建立一個 SQL 執行緒讀取 relay log 中的內容,並且在從庫中做回放,最終實現主從的一致性。

2.2 主從延時原因

我們分析一下主從複製的過程。

MySQL 的主從複製都是單執行緒的操作,主庫對所有 DDL 和 DML 產生 binlog,binlog 是順序寫,所以效率很高。

Slave 的 Slave_IO_Running 執行緒會到主庫取日誌,放入 relay log,效率會比較高。

Slave 的 Slave_SQL_Running 執行緒將主庫的 DDL 和 DML 操作都在 Slave 實施,DML 和 DDL 的 IO 操作是隨機的,不是順序的,因此成本會很高

還可能是 Slave 上的其他查詢產生 lock 爭用,由於 Slave_SQL_Running 也是單執行緒的,所以一個 DDL 卡住了,需要執行 10 分鐘,那麼所有之後的 DDL 會等待這個 DDL 執行完才會繼續執行,這就導致了延時。

總結一下主從延遲的主要原因:主從延遲主要是出現在 “relay log 回放” 這一步,當主庫的 TPS 併發較高,產生的 DDL 數量超過從庫一個 SQL 執行緒所能承受的範圍,那麼延時就產生了,當然還有就是可能與從庫的大型 query 語句產生了鎖等待。

03 如何解決主從延時?

3.1 主從延遲情況

我們先看看,哪些情況會導致主從延時:

  • 從庫機器效能:從庫機器比主庫的機器效能差,只需選擇主從庫一樣規格的機器就好。
  • 從庫壓力大:可以搞了一主多從的架構,還可以把 binlog 接入到 Hadoop 這類系統,讓它們提供查詢的能力。
  • 從庫過多:要避免複製的從節點數量過多,從庫資料一般以3-5個為宜。
  • 大事務:如果一個事務執行就要 10 分鐘,那麼主庫執行完後,給到從庫執行,最後這個事務可能就會導致從庫延遲 10 分鐘啦。日常開發中,不要一次性 delete 太多 SQL,需要分批進行,另外大表的 DDL 語句,也會導致大事務。
  • 網路延遲:最佳化網路,比如頻寬 20M 升級到 100M。
  • MySQL 版本低:低版本的 MySQL 只支援單執行緒複製,如果主庫併發高,來不及傳送到從庫,就會導致延遲,可以換用更高版本的 MySQL,支援多執行緒複製。

3.2 主從延時解決方案

面試時,有些同學能回答出使用快取、查詢主庫、提升機器配置等,僅僅這些麼?

最容易想到的方法,縮短主從同步時間:

  • 提升從庫機器配置,可以和主庫一樣,甚至更好;
  • 避免大事務
  • 搞多個從庫,即一主多從,分擔從庫查詢壓力;
  • 最佳化網路寬頻
  • 選擇高版本 MySQL,支援主庫 binlog 多執行緒複製。

也可以從業務場景考慮:

  • 使用快取:我們在同步寫資料庫的同時,也把資料寫到快取,查詢資料時,會先查詢快取,不過這種情況會帶來 MySQL 和 Redis 資料一致性問題。
  • 查詢主庫:直接查詢主庫,這種情況會給主庫太大壓力,核心場景可以使用,比如訂單支付。

如果能把上面基本回答出來,就已經非常厲害了,還有麼?

其實還可以在 MySQL 架構上來考慮。

主庫對資料安全性較高,設定配置如下:

sync_binlog = 1
innodb_flush_log_at_trx_commit = 1

而 slave 不需要這麼高的資料安全,完全可以將 sync_binlog 設定為 0,或者關閉 binlog,innodb_flushlog 也可以設定為 0,來提高 sql 的執行效率。

架構方案:使用多臺 slave 來分攤讀請求,再從這些 slave 中取一臺專用的伺服器,只作為備份用,不進行其他任何操作,比如設定 sync_binlog 為0,或者關閉 binglog 等,提升從庫查詢效能。

再問一下,還有麼?可以文末私信我哈~~

04 後記

再回過頭來看這個問題,估計很多同學能回答出一二,但是這個不能成為你的加分項。

面對如此激烈的競爭環境,同樣一個問題,你就需要比別人掌握得更多,回答得更全面,面試官才能對你刮目相看。

其實我當年面試小米時,也面試過這個問題,當時就是基於上面回答的。

後來的一次 MySQL 分享,講得還不錯,當時我們主管就說,樓仔的 MySQL 掌握得挺好的,記得當時面試時,我就問過一個 MySQL 主從複製問題,他都能回答到非常底層。

我沒想到,這都一年多了,當時的那場面試,居然給我主管留下那麼深刻的映像。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027826/viewspace-2992224/,如需轉載,請註明出處,否則將追究法律責任。

相關文章