天天看點

大衆點評工程師:從黃金圈法則看MySQL資料庫複制

每當我們讨論一項(新的)領域技術的時候,最好的方式通常是首先抛出一些問題,這些問題大緻分為三類:

诶?這項技術又是什麼玩意(what)?

這項技術為什麼會存在?我們已經有那麼多解決方案(method)了,我們問什麼要用它(why)?

如果這項技術那麼好且我們正好有場景可以用到這項技術,且能使我們的系統得到很樂觀的優化,那麼我們怎麼用呢(how)?

大概已經有同學覺得這些問題很熟悉了,是的,這就是黃金圈法則提出的三個問題,對于每種新鮮事物我們首先基于這三個問題去了解,更有利于弄清楚事情的本質,端正态度去了解,而不是因為新,因為大家都說好,才要去了解。

說了那麼多前言,接下來就開始了,今天我們就帶着黃金圈法則提出的三個問題去看看mysql資料庫複制這項領域技術,然後再結合實際應用擴充一些問題,本文也僅僅是結合自己了解的皮毛以抛磚引玉的态度和大家一起分享。

 what?

mysql複制使得一台mysql資料庫伺服器的資料被拷貝到其他一台或者多台資料庫伺服器,前者通常被叫做master,後者通常被叫做slave。

大衆點評工程師:從黃金圈法則看MySQL資料庫複制

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複制工作示意圖

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能夠同步到磁盤,這樣下次啟動的時候就不會讀取錯誤的資訊,這有助于減少錯誤的發生機率。另外想要找到正确的複制位置是困難的,我們也可以選擇忽略錯誤。

……

其實問題也是蠻多的,這裡就不再繼續提問了,包括如果主庫二進制日志檔案損壞怎麼辦?從庫中繼日志檔案損壞怎麼辦?因為每個環節都不是百分之一百可靠的,是以我們必須對可能遇到的問題提出假設,思考解決方案。

本文通過黃金圈法則提出的三個問題來認識mysql複制,通過自問自答的形式來對主體的一些可能存在的應用問題進行讨論,對于複制方面還存在很多的實際應用問題,這裡隻是抛磚引玉,還請資料庫大牛們多多指教。

參考文獻:

《高性能mysql》

官方《refman》

作者介紹  陸晨

大衆點評網開發工程師,擅長java,熱愛開源,喜歡研究各種中間件,關注高并發、高性能領域問題及解決方案。

<b></b>

<b>本文來自雲栖社群合作夥伴"dbaplus",原文釋出時間:2016-06-02</b>