MySQL 入門(5):複製

紅雞菌發表於2020-05-18

摘要

在這篇文章中,我將從MySQL為什麼需要主從複製開始講起,然後會提到MySQL複製的前提,bin log

在這裡會說明三種格式的bin log分別會有什麼優缺點。

隨後會講到主從延遲方面的問題,我將從幾個角度出發,提供一些可能造成延遲的思路。

1 為什麼需要複製

MySQL內建的複製功能是構建大型,高效能應用程式的基礎。隨著目前併發量的增加,單機的MySQL漸漸沒有辦法承擔這些請求,所以MySQL伺服器也需要進行擴充套件。

MySQL的複製功能不僅可以提高可用性,還能用作災備,資料倉儲等。

2 如何複製

說到複製,那麼問題的關鍵就在於資料從主庫複製到從庫時間需要多少,準確度能有多高。

對於MySQL來說,複製使用的是bin log

對於bin log相信你不會陌生,我們在聊到MySQL的“兩階段提交”的時候有說到這個。

也就是說,MySQL會將主庫記錄的bin log傳送到從庫中,然後從庫按照bin log的內容,“重放一遍”主庫執行過的操作,達到主從同步的目的。

在這裡我們先詳細說一說bin log記錄了什麼。

2.1 SBR(statement-based replication)

在這種模式下,bin log會完整的記錄下所執行的SQL語句。也就是說,如果使用了statement格式的bin log的話,主庫執行的SQL語句就會在從庫中完整的再執行一遍。

可是,這樣的做法,是有可能導致主從不一致的。

例如下面這樣的語句:

delete from t where a >= 1 and b => 2 limit 1;

這樣的語句在從庫中就不一定能夠實現跟主庫一樣的效果。因為我們不能夠確定在從庫中是否走的跟主庫是同樣的索引,所查詢的第一條資料,是不是跟主庫一樣的,也就可能刪除的資料不是同一行。

又或者主庫執行的SQL語句裡面有一些鎖相關的語句,也可能會造成主從不一致的問題。

但是要注意的是,NOW()函式是可以被正確執行的,因為在bin log語句中會記錄時間戳。

也就是說,基於statement模式,在上下文不同的時候,是有可能造成資料不一致的。

至於其他的不安全情況,可以參考官方文件,這裡不展開介紹。

2.2 RBR(row-based replication)

既然statement模式下會造成資料不一致,那麼有沒有一種模式是上下文無關的呢?

所以就有了row模式。

在這個模式中,bin log中只記錄了所操作的行的修改情況,會精確到某一行。

比如你更新了某一行,在bin log中就會記錄在id等於多少多少,某某欄位等於多少多少的行中,將某個欄位的值從A改成了B。

甚至是刪除操作,都會記錄刪除了id等於多少,A欄位等於多少,B欄位等於多少的一行資料。

聽到這裡你可能會覺得很方便,也很精確,主從不再會發生不一致的情況了。甚至於刪庫了都不需要跑路了,只需要檢視bin log就能恢復相應的資料了。

但是使用row模式同樣會有一些問題。比如你在主庫執行了delete from t where id < 10000這麼一行sql語句,如果使用statement格式,在bin log內記錄只有這麼一條,但是如果你使用的是row模式,那麼就需要記錄10000條資料,佔用很大的空間。

2.3 MBR(mixd-based replication)

於是就有了mixd模式。

混合了以上兩種模式的優點,MySQL會在沒有歧義的時候使用statement格式,在有歧義的時候使用row格式。

3 複製的具體過程

上面介紹了bin log的作用,以及bin log的組成形式,在這一章中我們聊一聊整個的複製流程。

我們拿《高效能MySQL》中的圖來解釋:

這裡涉及到了有三個執行緒:

  • Binlog dump thread
    這個執行緒在MySQL主庫中,負責讀取bin log中的內容,並將這些內容推送到從庫IO程式中。

  • I/O thread
    這個執行緒在MySQL從庫中,負責跟主庫建立一條長連線,並且將讀取到的bin log資料儲存到從庫的中繼日誌(relay log)中。

  • SQL thread
    這個執行緒也是在MySQL的從庫中,負責讀取中繼日誌中的內容,然後執行這些語句,將對資料的修改應用到從庫中。

簡單的來講,就是主庫經過兩階段提交後,把修改內容儲存在了bin log中,然後把這個bin log傳送給從庫,讓從庫也執行一次,以達到同步的目的。

而這裡採用了中繼日誌的原因是從庫消費bin log的速度和主庫生產bin log的速度是不一致的,所以需要一箇中繼日誌作為緩衝。

4 複製可能造成的問題

在MySQL複製的過程中,經常出現的問題是延遲

  • 假設我們把主庫一個事務提交後bin log落盤的時間點設為t1

  • 把從庫接受到主庫新事務寫的bin log並寫入relay log的時間節點設為t2

  • 把從庫執行完這個新的事務的時間節點設為t3

那麼執行一條事務,從庫的延遲可以認為是(t3 - t1)。

也就是說,如果我們需要分析造成主從延遲的原因,應該從兩個方面考慮:傳輸過程,以及從庫消費relay log的速度。

4.1 網路問題

網路確實可能會造成主從延遲,比如主庫或者從庫的頻寬打滿,又或者是主庫的bin log被設定成了row格式,導致有大量的資料需要傳輸,造成了主庫的bin log沒有及時的同步到從庫中,導致了主從的延遲。

4.2 機器效能

但是除了網路,更多的是從庫的消費速度,跟不上主庫的生產速度。

這方面有很多原因,比如可能從庫的機器配置低於主庫,因為會有人覺得既然是備庫,沒什麼請求,就把備庫配置在了比較差的機器上面。

又或者在是後臺的資料分析,將CPU打滿。

總之,如果在從庫中需要有大量的查詢分析操作,需要考慮多個從庫。

4.3 大事務

如果主庫執行了一條耗時很長的事務,那麼這條事務傳送到從庫中,可能也需要執行這麼長的時間。而這個時候,從庫是沒有辦法繼續消費新的relay log的。這就造成了主從延遲。

4.4 鎖

我們之前提到過了,不僅僅寫資料會加鎖,使用“當前讀”,也一樣可能會加鎖。

所以,如果在從庫上執行了一些諸如select ... for update,或者一些DDL語句,可能也會造成從庫加鎖,導致主從延遲。

4.5 併發

在我們上面的介紹中,SQL執行緒是單執行緒的,所以,如果能夠讓SQL執行緒可以併發消費,那麼主從延遲就可以大幅度的降低了。

關於MySQL的併發複製策略,MySQL5.6開始已經正式支援了,本文不詳細解釋。

寫在最後

首先,謝謝你能看到這裡。

這一篇的文章,其實說的內容不多,大多都是一些理論性質的內容,目的是能夠對MySQL的主從複製有一些大體上的瞭解,並且知道對於延遲方面的問題,應該從哪個方向去考慮。

至於其他更具體的操作、如何調優,以及更深的原理,我想在今後的《進階篇》來提到。

並且,《MySQL 入門》系列到這裡就完結了。希望這五篇的內容能夠給你帶來一些幫助,能夠讓你對MySQL的瞭解更深一些。

當然了,在學習MySQL的過程中,我可能也會有一些錯誤的理解,如果有哪裡是不對的,希望你能指出,謝謝你!

PS:如果有其他的問題,也可以在公眾號找到我,歡迎來找我玩~

相關文章