切換語言為:簡體

如何處理 MySQL 主從延遲?

  • 爱糖宝
  • 2024-08-26
  • 2059
  • 0
  • 0

既然是主從,是讀寫分離,那就不可避免會產生延遲,因為資料從主機同步到從機,總是需要時間的。

一般來說這個時間不會太久,可能就是 1ms 左右。

不過,如果你的系統資料量比較大,亦或者業務對資料實時性要求比較高,那麼我們還是需要想辦法去處理這個主從延遲。

一般來說有如下幾種思路,鬆哥來和大家一一說明。

一 強制讀主庫

第一種方案就是強制讀主庫。

這種方案看著有點笨重,但卻是我司用的最多的一種方案。

簡單來說,就是將查詢請求進行分類:一類是對資料實時性要求不高的請求,這種請求直接去讀從庫;另一類則是對實時性要求比較高的請求,這種就強制讀主庫。

舉個簡單例子:讀取系統配置、讀取使用者基本資訊等等,都算是對資料實時性要求不高的請求,這種直接讀取從庫就可以了;但是像使用者下單獲取訂單狀態的話,這種就需要讀主庫了,確保資料的一致性。

強制讀主庫我們可以在程式碼裏邊透過 AOP 的方式實現,也可以透過一些資料庫中間如 ShardingJDBC 去配置。

二 sleep 方案

這種方案就是剛剛插入完成之後,此時如果去讀取從機的話,先 sleep 一會再讀,這樣就能儘量保證從機的資料已經同步過來了。

不過這個方案顯然不夠優雅,發請求先 sleep,怎麼想都覺得彆扭。

三 判斷主從是否延遲

第三種方案就是我們去判斷一下主從是否延遲,如果發生延遲了,就等一會,如果資料已經同步了,那就直接查詢就行了。

判斷是否發生主從延遲,一般來說可以透過兩種方式。

3.1 seconds_behind_master

seconds_behind_master 引數是一個只讀變數,用於表示從伺服器(slave)相對於主伺服器(master)的複製延遲時間。

這個引數反映了從伺服器在複製過程中落後於主伺服器的時間長度(以秒為單位)。

這個引數的取值如下:

  1. 正值:表示從伺服器正在追趕主伺服器的複製進度。具體的數值表示從屬伺服器的複製程序落後於主伺服器的時間長度。例如,如果此值為 60 秒,那麼意味著從伺服器的複製操作比主伺服器晚了 60 秒。

  2. 0:表示從屬伺服器與主伺服器的複製同步是實時的,沒有延遲。這意味著從屬伺服器已經完成了所有可用的複製事件,且沒有新的事件等待應用。

  3. NULL

  • 如果從伺服器剛剛啟動,還沒有開始複製過程,那麼此值可能是 NULL。

  • 如果從伺服器與主伺服器之間的連線斷開,或者從屬伺服器正在處理非複製任務(例如,正在進行表修復),也可能顯示為 NULL。

  • 如果從伺服器已經追上了主伺服器,並且沒有新的事件需要複製,也會顯示為 NULL。

要檢視 seconds_behind_master 的值,我們可以使用以下 SQL 命令:

 SHOW SLAVE STATUS\G;

輸出中會有一行顯示 Seconds_Behind_Master,這就是你要找的資訊。

利用 seconds_behind_master 引數,我們可以監控複製延遲,管理員可以據此瞭解從伺服器的複製進度,並確定是否存在複製延遲問題。

在 MySQL8.0 之後的版本中,seconds_behind_master 被替換為 replication_lag,但這兩個引數的功能是一樣的。

3.2 GTID

GTID 是 MySQL5.6 引入的一個特性,用於跟蹤事務在主伺服器上的執行情況,並確保這些事務按順序在從伺服器上重現。使用 GTID 進行主從複製可以簡化管理和監控,特別是在有多個從伺服器或複雜的複製拓撲中。

下面鬆哥給大家簡單演示下如何利用 GTID 判斷 MySQL 主從複製是否發生延遲。

步驟 1:確認主伺服器和從伺服器都啟用了 GTID

確保主伺服器和從伺服器都配置了 GTID。需要在 MySQL 的配置檔案(如 my.cnfmy.ini)中設定 server-idgtid_mode

[mysqld]

server-id = 1 # 主伺服器的 server-id

gtid_mode = ON # 啟用 GTID

[mysqld]

server-id = 2 # 從伺服器的 server-id

gtid_mode = ON # 啟用 GTID

步驟 2:檢查 GTID 執行狀態

可以使用 SHOW MASTER STATUSSHOW SLAVE STATUS 命令來檢查主伺服器和從伺服器的 GTID 狀態。

在主伺服器上
 SHOW MASTER STATUS;

這裏多說一句,從 MySQL8.4 開始,不再使用 SHOW MASTER STATUS;,取而代之的是 SHOW BINARY LOG STATUS

輸出將包括當前的 GTID 執行位置,如下所示:

File: mysql-bin.000001

Position: 107

Binlog_Do_DB:

Binlog_Ignore_DB:

Executed_Gtid_Set: 11111111-1111-1111-1111-111111111111:1-100

這裏 Executed_Gtid_Set 顯示了主伺服器已經執行的所有 GTID 的集合。

在從伺服器上
 SHOW SLAVE STATUS\G;

輸出將包括從伺服器的 GTID 執行位置,如下所示:

...

Master_Host: master.example.com

Master_User: replication

Master_Port: 3306

Master_Log_File: mysql-bin.000001

Read_Master_Log_Pos: 107

Relay_Master_Log_File: mysql-bin.000001

...

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

Replicate_Do_DB:

Replicate_Ignore_DB:

Replicate_Do_Table:

Replicate_Ignore_Table:

Replicate_Wild_Do_Table:

Replicate_Wild_Ignore_Table:

Last_Errno: 0

Last_Error:

Skip_Counter: 0

Exec_Master_Log_Pos: 107

Auto_Position: 1

...

其中 Auto_Position 的值為 1 表示從伺服器正在使用 GTID 進行復制。

步驟 3:比較 GTID 集合

比較主伺服器和從伺服器的 Executed_Gtid_Set。如果兩者相同,則表示複製沒有延遲;如果有差異,則表示存在延遲。

步驟 4:分析 GTID 集合差異

如果發現 GTID 集合之間存在差異,可以透過以下命令檢視具體的 GTID:

 SELECT @@gtid_executed;

透過比較主從上兩個命令執行的結果,就可以知道是否發生了延遲。如果發生了延遲,我們就停一會再去讀。

鬆哥這邊的專案第一種方案是使用比較多的,另外兩種使用相對比較少。小夥伴們有無遇到類似問題,都是怎麼解決的?歡迎留言討論。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.