誒?這項技術又是什麼玩意(What)?
這項技術為什麼會存在?我們已經有那麼多解決方案(Method)了,我們為什麼要用它(Why)?
如果這項技術那麼好且我們正好有場景可以用到這項技術,且能使我們的系統得到很樂觀的最佳化,那麼我們怎麼用呢(How)?
大概已經有同學覺得這些問題很熟悉了,是的,這就是黃金全法則提出的三個問題,對於每種新鮮事物我們首先基於這三個問題去了解,更有利於弄清楚事情的本質,端正態度去了解,而不是因為新,因為大家都說好,才要去了解……。說了那麼多前奏,我們可以開始了,今天我們就帶著黃金圈法則提出的三個問題去看看MySQL資料庫複製這項領域技術,然後再結合實際應用擴充套件一些問題,本文也僅僅是結合自己瞭解的皮毛以拋磚引玉的態度和大家一起分享。
WHAT?
MySQL複製使得一臺MySQL資料庫伺服器的資料被複製到其他一臺或者多臺資料庫伺服器,前者通常被叫做Master,後者通常被叫做Slave。
MySQL複製示意圖
複製的結果是叢集(Cluster)中的所有資料庫伺服器得到的資料理論上都是一樣的,都是同一份資料,只是有多個copy。MySQL預設內建的複製策略是非同步的,基於不同的配置,Slave不一定要一直和Master保持連線不斷的複製或等待複製,我們指定複製所有的資料庫,一部分資料庫,甚至是某個資料庫的某部分的表。
MySQL複製支援多種不同的複製策略,包括同步、半同步、非同步和延遲策略等。
同步策略:Master要等待所有Slave應答之後才會提交(MySql對DB操作的提交通常是先對操作事件進行二進位制日誌檔案寫入然後再進行提交)。
半同步策略:Master等待至少一個Slave應答就可以提交。
非同步策略:Master不需要等待Slave應答就可以提交。
延遲策略:Slave要至少落後Master指定的時間。
MySQL複製同時支援多種不同的複製模式:
基於語句的複製,Statement Based Replication(SBR)。
基於行的複製Row Based Replication(RBR)。
混合複製(Mixed)。
WHY?
這個問題其實也就是MySQL複製有什麼好處,我們可以將複製的好處歸結於下面幾類:
效能方面:MySQL複製是一種Scale-out方案,也即“水平擴充套件”,將原來的單點負載擴散到多臺Slave機器中去,從而提高總體的服務效能。在這種方式下,所有的寫操作,當然包括UPDATE操作,都要發生在Master伺服器上。讀操作發生在一臺或者多臺Slave機器上。這種模型可以在一定程度上提高總體的服務效能,Master伺服器專注於寫和更新操作,Slave伺服器專注於讀操作,我們同時可以透過增加Slave伺服器的數量來提高讀服務的效能。
防腐化:由於資料被複制到了Slave,Slave可以暫停複製程序,進行資料備份,因此可以防止資料腐化。
故障恢復:同時多臺Slave如果有一臺Slave掛掉之後我們還可以從其他Slave讀取,如果配置了主從切換的話,當Master掛掉之後我們還可以選擇一臺Slave作為Master繼續提供寫服務,這大大增加了應用的可靠性。
資料分析:實時資料可以儲存在Master,而資料分析可以從Slave讀取,這樣不會影響Master的效能。
HOW?
這裡我們只介紹一下MySQL的複製是如何工作的,至於配置,網上也有很多相關的介紹,讀者具體應用的時候可以再去查閱。我們拿最常用的基於二進位制檔案的複製來看看。
MySQL複製工作示意圖
MySQL的複製過程大概如下:
首先,主庫在每次準備提交事務完成資料更新操作之前都會將資料更改操作記錄到二進位制日誌中,這些日誌是以二進位制的方式記錄資料更改的事件。值得一提的是二進位制日誌中記錄的順序實際上是事務的提交順序,而非SQL執行語句的順序。在記錄二進位制日誌之後,主庫會告訴儲存引擎事務可以提交了。
然後,備庫會啟動一個IO執行緒,之所以叫做IO執行緒是因為這個執行緒專門做IO相關的工作,包括和主庫建立連線,然後在主庫上啟動一個特殊的二進位制轉儲執行緒,這個轉儲執行緒會不斷的讀取二進位制日誌中的事件,傳送給備庫的IO執行緒,備庫的IO執行緒會將事件記錄到中繼日誌中。
備庫會有一個叫做SQL的執行緒被開啟,這個執行緒做的事情是讀取中繼日誌中的DB操作事件在備庫執行,從而實現資料更新。
總的來說,在發生複製的主庫伺服器和備庫伺服器中,一共有三個執行緒在工作。
上面我們已經大概瞭解的什麼是複製?為什麼要複製?如何複製?這三個問題了,接下來我們基於上面的介紹,提出一些實際應用可能會發生的問題來思考如何解決。博主自問自答的方式-。-
問答環節
問題一:透過複製模型雖然讀能力可以透過擴充套件slave機器來達到提高,而寫能力卻不能,如果寫達到瓶頸我們應該怎麼做呢?
答:我們首先會得出結論,這種複製模型對於寫少讀多型應用是非常有優勢的,其次,當遇到這種問題的時候我們可以對資料庫進行分庫操作,所謂分庫,就是將業務相關性比較大的表放在同一個資料庫中,例如之前資料庫有A,B,C,D四張表,A表和B表關係比較大,而C表和D表關係比較大,這樣我們把C表和D表分離出去成為一個單獨的資料庫,透過這種方式,我們可以將原有的單點寫變成雙點寫或多點些,從而降低原有主庫的寫負載。
問題二:因為複製是有延遲的,肯定會發生主庫寫了,但是從庫還沒有讀到的情況,遇到這種問題怎麼辦?
答:MySQL支援不同的複製策略,基於不同的複製策略達到的效果也是不一樣的,如果是非同步複製,MySQL不能保證從庫立馬能夠讀到主庫實時寫入的資料,這個時候我們要權衡選擇不同複製策略的利弊來進行取捨。所謂利弊,就是我們是否對從庫的讀有那麼高的實時性要求,如果真的有,我們可以考慮使用同步複製策略,但是這種策略相比於非同步複製策略會大大降低主庫的響應時間和效能。我們是否可以在應用的設計層面去避開這個問題?
問題三:複製的不同模式有什麼優缺點?我們如何選擇?
答:基於語句的複製實際上是把主庫上執行的SQL在從庫上重新執行一遍,這麼做的好處是實現起來簡單,當前也有缺點,比如我們SQL裡面使用了NOW(),當同一條SQL在從庫中執行的時候顯然和在主庫中執行的結果是不一樣的,注入此類問題可以類推。其次問題就是這種複製必須是序列的,為了保證序列執行,就需要更多的鎖。
基於行的複製的時候二進位制日誌中記錄的實際上是資料本身,這樣從庫可以得到正確的資料,這種方式缺點很明顯,資料必須要儲存在二進位制日誌檔案中,這無疑增加的二進位制日誌檔案的大小,同時增加的IO執行緒的負載和網路頻寬消耗。而相比於基於語句的複製還有一個優點就是基於行的複製無需重放查詢,省去了很多效能消耗。
無論哪種複製模式都不是完美的,日誌如何選擇,這個問題可以在理解他們的優缺點之後進行權衡。
問題四:複製的工作過程只有三個執行緒來完成,對於Master來說,寫是併發的,也就出現了一個IO執行緒要把所有併發的資料變更事件記錄,這個IO執行緒會不會累死?當一個Master對應多個Slave的時候,其實在Master中會喚起多個IO執行緒,這無疑會增加Master的資源開銷,如果出現事件堆積,也就是事件太多,來不及及時傳送出去怎麼辦?另外就是Slave那邊的IO執行緒和SQL執行緒也會有對應主庫併發資料變更事件,而Slave方單個執行緒處理的問題,這個時候Slave執行緒會不會累死?
答:上面的問題確實會發生,上面第一個問題和第二個問題其實是寫負載的問題,當事件堆積太多,從庫時延就會變大,Slave單SQL執行緒問題據說有引數可以開啟並行操作,這個大家可以確認一下。
問題五:針對複製工作過程可能會出現的問題,主庫寫完二進位制日誌檔案同時都會儲存二進位制日誌的偏移量,但是當斷電的時候,二進位制日誌檔案沒有重新整理到磁碟,主庫重新啟動之後,從庫嘗試讀該偏移量的二進位制日誌,會出現讀不到的情況,這個問題應該怎麼解決?
答:首先如果開啟了sync_binlog選項,對於innodb同時設定innodb_flush_log_at_trx_commot=1,則可以保證二進位制日誌檔案會被寫入磁碟,但MyISAM引擎可能會導致資料損壞。如果沒有開啟這個選項,則可以透過制定從庫的二進位制偏移量為下一個二進位制日誌檔案的開頭,但是不能解決事件丟失問題。
問題六:從庫在非計劃的關閉或重啟時,回去讀master.info檔案去找上次停止複製的位置,這同樣會有一個問題,如果master.info不正確,就會導致複製資料不一致的情況,遇到這個問題怎麼辦?
答:這個問題可以透過兩種方式解決,一是控制master.info在從庫非計劃關閉或重啟的時候讓master.info能夠同步到磁碟,這樣下次啟動的時候就不會讀取錯誤的資訊,這有助於減少錯誤的發生機率。另外想要找到正確的複製位置是困難的,我們也可以選擇忽略錯誤。
誒?這項技術又是什麼玩意(What)?
這項技術為什麼會存在?我們已經有那麼多解決方案(Method)了,我們為什麼要用它(Why)?
如果這項技術那麼好且我們正好有場景可以用到這項技術,且能使我們的系統得到很樂觀的最佳化,那麼我們怎麼用呢(How)?
大概已經有同學覺得這些問題很熟悉了,是的,這就是黃金全法則提出的三個問題,對於每種新鮮事物我們首先基於這三個問題去了解,更有利於弄清楚事情的本質,端正態度去了解,而不是因為新,因為大家都說好,才要去了解……。說了那麼多前奏,我們可以開始了,今天我們就帶著黃金圈法則提出的三個問題去看看MySQL資料庫複製這項領域技術,然後再結合實際應用擴充套件一些問題,本文也僅僅是結合自己瞭解的皮毛以拋磚引玉的態度和大家一起分享。
WHAT?
MySQL複製使得一臺MySQL資料庫伺服器的資料被複製到其他一臺或者多臺資料庫伺服器,前者通常被叫做Master,後者通常被叫做Slave。
MySQL複製示意圖
複製的結果是叢集(Cluster)中的所有資料庫伺服器得到的資料理論上都是一樣的,都是同一份資料,只是有多個copy。MySQL預設內建的複製策略是非同步的,基於不同的配置,Slave不一定要一直和Master保持連線不斷的複製或等待複製,我們指定複製所有的資料庫,一部分資料庫,甚至是某個資料庫的某部分的表。
MySQL複製支援多種不同的複製策略,包括同步、半同步、非同步和延遲策略等。
同步策略:Master要等待所有Slave應答之後才會提交(MySql對DB操作的提交通常是先對操作事件進行二進位制日誌檔案寫入然後再進行提交)。
半同步策略:Master等待至少一個Slave應答就可以提交。
非同步策略:Master不需要等待Slave應答就可以提交。
延遲策略:Slave要至少落後Master指定的時間。
MySQL複製同時支援多種不同的複製模式:
基於語句的複製,Statement Based Replication(SBR)。
基於行的複製Row Based Replication(RBR)。
混合複製(Mixed)。
WHY?
這個問題其實也就是MySQL複製有什麼好處,我們可以將複製的好處歸結於下面幾類:
效能方面:MySQL複製是一種Scale-out方案,也即“水平擴充套件”,將原來的單點負載擴散到多臺Slave機器中去,從而提高總體的服務效能。在這種方式下,所有的寫操作,當然包括UPDATE操作,都要發生在Master伺服器上。讀操作發生在一臺或者多臺Slave機器上。這種模型可以在一定程度上提高總體的服務效能,Master伺服器專注於寫和更新操作,Slave伺服器專注於讀操作,我們同時可以透過增加Slave伺服器的數量來提高讀服務的效能。
防腐化:由於資料被複制到了Slave,Slave可以暫停複製程序,進行資料備份,因此可以防止資料腐化。
故障恢復:同時多臺Slave如果有一臺Slave掛掉之後我們還可以從其他Slave讀取,如果配置了主從切換的話,當Master掛掉之後我們還可以選擇一臺Slave作為Master繼續提供寫服務,這大大增加了應用的可靠性。
資料分析:實時資料可以儲存在Master,而資料分析可以從Slave讀取,這樣不會影響Master的效能。
HOW?
這裡我們只介紹一下MySQL的複製是如何工作的,至於配置,網上也有很多相關的介紹,讀者具體應用的時候可以再去查閱。我們拿最常用的基於二進位制檔案的複製來看看。
MySQL複製工作示意圖
MySQL的複製過程大概如下:
首先,主庫在每次準備提交事務完成資料更新操作之前都會將資料更改操作記錄到二進位制日誌中,這些日誌是以二進位制的方式記錄資料更改的事件。值得一提的是二進位制日誌中記錄的順序實際上是事務的提交順序,而非SQL執行語句的順序。在記錄二進位制日誌之後,主庫會告訴儲存引擎事務可以提交了。
然後,備庫會啟動一個IO執行緒,之所以叫做IO執行緒是因為這個執行緒專門做IO相關的工作,包括和主庫建立連線,然後在主庫上啟動一個特殊的二進位制轉儲執行緒,這個轉儲執行緒會不斷的讀取二進位制日誌中的事件,傳送給備庫的IO執行緒,備庫的IO執行緒會將事件記錄到中繼日誌中。
備庫會有一個叫做SQL的執行緒被開啟,這個執行緒做的事情是讀取中繼日誌中的DB操作事件在備庫執行,從而實現資料更新。
總的來說,在發生複製的主庫伺服器和備庫伺服器中,一共有三個執行緒在工作。
上面我們已經大概瞭解的什麼是複製?為什麼要複製?如何複製?這三個問題了,接下來我們基於上面的介紹,提出一些實際應用可能會發生的問題來思考如何解決。博主自問自答的方式-。-
問答環節
問題一:透過複製模型雖然讀能力可以透過擴充套件slave機器來達到提高,而寫能力卻不能,如果寫達到瓶頸我們應該怎麼做呢?
答:我們首先會得出結論,這種複製模型對於寫少讀多型應用是非常有優勢的,其次,當遇到這種問題的時候我們可以對資料庫進行分庫操作,所謂分庫,就是將業務相關性比較大的表放在同一個資料庫中,例如之前資料庫有A,B,C,D四張表,A表和B表關係比較大,而C表和D表關係比較大,這樣我們把C表和D表分離出去成為一個單獨的資料庫,透過這種方式,我們可以將原有的單點寫變成雙點寫或多點些,從而降低原有主庫的寫負載。
問題二:因為複製是有延遲的,肯定會發生主庫寫了,但是從庫還沒有讀到的情況,遇到這種問題怎麼辦?
答:MySQL支援不同的複製策略,基於不同的複製策略達到的效果也是不一樣的,如果是非同步複製,MySQL不能保證從庫立馬能夠讀到主庫實時寫入的資料,這個時候我們要權衡選擇不同複製策略的利弊來進行取捨。所謂利弊,就是我們是否對從庫的讀有那麼高的實時性要求,如果真的有,我們可以考慮使用同步複製策略,但是這種策略相比於非同步複製策略會大大降低主庫的響應時間和效能。我們是否可以在應用的設計層面去避開這個問題?
問題三:複製的不同模式有什麼優缺點?我們如何選擇?
答:基於語句的複製實際上是把主庫上執行的SQL在從庫上重新執行一遍,這麼做的好處是實現起來簡單,當前也有缺點,比如我們SQL裡面使用了NOW(),當同一條SQL在從庫中執行的時候顯然和在主庫中執行的結果是不一樣的,注入此類問題可以類推。其次問題就是這種複製必須是序列的,為了保證序列執行,就需要更多的鎖。
基於行的複製的時候二進位制日誌中記錄的實際上是資料本身,這樣從庫可以得到正確的資料,這種方式缺點很明顯,資料必須要儲存在二進位制日誌檔案中,這無疑增加的二進位制日誌檔案的大小,同時增加的IO執行緒的負載和網路頻寬消耗。而相比於基於語句的複製還有一個優點就是基於行的複製無需重放查詢,省去了很多效能消耗。
無論哪種複製模式都不是完美的,日誌如何選擇,這個問題可以在理解他們的優缺點之後進行權衡。
問題四:複製的工作過程只有三個執行緒來完成,對於Master來說,寫是併發的,也就出現了一個IO執行緒要把所有併發的資料變更事件記錄,這個IO執行緒會不會累死?當一個Master對應多個Slave的時候,其實在Master中會喚起多個IO執行緒,這無疑會增加Master的資源開銷,如果出現事件堆積,也就是事件太多,來不及及時傳送出去怎麼辦?另外就是Slave那邊的IO執行緒和SQL執行緒也會有對應主庫併發資料變更事件,而Slave方單個執行緒處理的問題,這個時候Slave執行緒會不會累死?
答:上面的問題確實會發生,上面第一個問題和第二個問題其實是寫負載的問題,當事件堆積太多,從庫時延就會變大,Slave單SQL執行緒問題據說有引數可以開啟並行操作,這個大家可以確認一下。
問題五:針對複製工作過程可能會出現的問題,主庫寫完二進位制日誌檔案同時都會儲存二進位制日誌的偏移量,但是當斷電的時候,二進位制日誌檔案沒有重新整理到磁碟,主庫重新啟動之後,從庫嘗試讀該偏移量的二進位制日誌,會出現讀不到的情況,這個問題應該怎麼解決?
答:首先如果開啟了sync_binlog選項,對於innodb同時設定innodb_flush_log_at_trx_commot=1,則可以保證二進位制日誌檔案會被寫入磁碟,但MyISAM引擎可能會導致資料損壞。如果沒有開啟這個選項,則可以透過制定從庫的二進位制偏移量為下一個二進位制日誌檔案的開頭,但是不能解決事件丟失問題。
問題六:從庫在非計劃的關閉或重啟時,回去讀master.info檔案去找上次停止複製的位置,這同樣會有一個問題,如果master.info不正確,就會導致複製資料不一致的情況,遇到這個問題怎麼辦?
答:這個問題可以透過兩種方式解決,一是控制master.info在從庫非計劃關閉或重啟的時候讓master.info能夠同步到磁碟,這樣下次啟動的時候就不會讀取錯誤的資訊,這有助於減少錯誤的發生機率。另外想要找到正確的複製位置是困難的,我們也可以選擇忽略錯誤。