MySQL的高可用性
本章將講述提到的復制、可擴展性以及髙可用性三個主題中的第三個。歸根結底,高可用性實際上意味著“更少的宕機時間”。然而糟糕的是,高可用性經常和其他相關的概念混淆,例如冗余、保障數據不丟失,以及負載均衡。我們希望另外的兩章已經很清楚地理解高可用性做了足夠的鋪墊。跟其他兩章一樣,這一章也不僅僅是關注高可用性的內容,一些相關的話題也會綜合闡述。
1.什么是高可用性
髙可用性實際上有點像神秘的野獸。它通常以百分比表示,這本身也是一種暗示:髙可用性不是絕對的,只有相對更髙的可用性。100%的可用性是不可能達到的??捎眯缘摹?”規則是表示可用性目標最普遍的方法。你可能也知道,“5個9”表示99.999%的正??捎脮r間。換句話說,每年只允許5分鐘的宕機時間。對于大多數應用這已經是令人驚嘆的數字,盡管還有一些人試圖獲得更多的“9”。
每個應用對可用性的需求各不相同。在設定一個可用時間的目標之前,先問問自己,是不是確實需要達到這個目標??捎眯悦刻岣咭稽c,所花費的成本都會遠超之前;可用性的效果和開銷的比例并不是線性的。需要保證多少可用時間,取決于能夠承擔多少成本。高可用性實際上是在宕機造成的損失與降低宕機時間所花費的成本之間取一個平衡。換句話說,如果需要花大量金錢去獲得更好的可用時間,但所帶來的收益卻很低,可能就不值得去做??偟膩碚f,應用在超過一定的點以后追求更高的可用性是非常困難的,成本也會很高,因此我們建議設定一個更現實的目標并且避免過度設計。幸運的是,建立2個9或3個9的可用時間的目標可能并不困難,具體情況取決于應用。
有時候人們將可用性定義成服務正在運行的時間段。我們認為可用性的定義還應該包括應用是否能以足夠好的性能處理請求。有許多方法可以讓一個服務器保持運行,但服務并不是真正可用。對一個很大的服務器而言,重啟MySQL之后,可能需要幾個小時才能充分預熱以保證査詢請求的響應時間是可以接受的,即使服務器只接收了正常流量的一小部分也是如此。
另一個需要考慮的問題是,即使應用并沒有停止服務,但是否可能丟失了數據。如果服務器遭遇災難性故障,可能多少都會丟失一些數據,例如最近已經寫入(最新丟失的)二進制日志但尚未傳遞到備庫的中繼日志中的事務。你能夠容忍嗎?大多數應用能夠容忍;因為替代方案大多非常昂貴且復雜,或者有一些性能開銷。例如,可以使用同步復制,或是將二進制日志放到一個通過DRBD進行復制的設備上,這樣就算服務器完全失效也不用擔心丟失數據。(但是整個數據中心也有可能會掉電。)
一個良好的應用架構通常可以降低可用性方面的需求,至少對部分系統而言是這樣的,良好的架構也更容易做到高可用。將應用中重要和不重要的部分進行分離可以節約不少工作量和金錢,因為對于一個更小的系統改進可用性會更容易??梢酝ㄟ^計算“風險敞口(riskexposure)”,將失效概率與失效代價相乘來確認高優先級的風險。畫一個簡單的風險計算表,以概率、代價和風險敞口作為列,這樣很容易找到需要優先處理的項目。
在<MySQL的可擴展性>通過討論如何避免導致糟糕的可擴展性的原因,來推出如何獲得更好的可擴展性。這里也會使用相似的方法來討論可用性,因為相信,理解可用性最好的方法就是研究它的反面——宕機時間。接下來的小節會討論為什么會出現宕機。
2.導致宕機的原因
我們經常聽到導致數據庫宕機最主要的原因是編寫的SQL査詢性能很差,真的是這樣嗎?2009年我們決定分析我們客戶的數據庫所遇到的問題,以找出那些真正引起宕機的問題,以及如何避免這些問題。結果證實了一些我們已有的猜想,但也否定了一些(錯誤的)認識,我們從中學到了很多。
我們首先對宕機事件按表現方式而非導致的原因進行分類。一般來說,“運行環境”是排名第一的宕機類別,大約35%的事件屬于這一類。運行環境可以看作是支持數據庫服務器運行的系統和資源集合,包括操作系統、硬盤以及網絡等。性能問題緊隨其后,也是約占35% ;然后是復制,占20%;最后剩下的10%包含各種類型的數據丟失或損壞,以及其他問題。
我們對事件按類型進行分類后,確定了導致這些事件的原因。以下是一些需要注意的地方:
在運行環境的問題中,最普遍的問題是磁盤空間耗盡。
在性能問題中,最普遍的宕機原因確實是運行很糟糕的SQL,但也不一定都是這個原因,比如也有很多問題是由于服務器Bug或錯誤的行為導致的。
糟糕的Schema和索引設計是第二大影響性能的問題。
復制問題通常由于主備數據不一致導致。
數據丟失問題通常由于DROPTABLE的誤操作導致,并總是伴隨著缺少可用備份的問題。
復制雖然常被人們用來改善可用時間,但卻也可能導致宕機。這主要是由于不正確的使用導致的,即便如此,它也闡明了一個普遍的情況:許多高可用性策略可能會產生反作用,我們會在后面討論這個話題。
現在我們已經知道了主要宕機類別,以及有什么需要注意,下面我們將專門介紹如何獲得高可用性。
3.如何實現高可用性
可以通過同時進行以下兩步來獲得高可用性。首先,可以嘗試避免導致宕機的原因來減少宕機時間。許多問題其實很容易避免,例如通過適當的配置、監控,以及規范或安全保障措施來避免人為錯誤。第二,盡量保證在發生宕機時能夠快速恢復。最常見的策略是在系統中制造冗余,并且具備故障轉移能力。這兩個維度的髙可用性可以通過兩個相關的度量來確定:平均失效時間(MTBF)和平均恢復時間(MTTR)。一些組織會非常仔細地追蹤這些度量值。
第二步——通過冗余快速恢復——很不幸,這里是最應該注意的地方,但預防措施的投資回報率會很髙。接下來我們來探討一些預防措施。
3.1 提升平均失效時間(MTBF)
其實只要盡職盡責地做好一些應做的事情,就可以避免很多宕機。在分類整理宕機事件并追查導致宕機的根源時,我們還發現,很多宕機本來是有一些方法可以避免的。我們發現大部分宕機事件都可以通過全面的常識性系統管理辦法來避免。以下是從我們的白皮書中摘錄的指導性建議,在白皮書中有我們詳細的分析結果。
測試恢復工具和流程,包括從備份中恢復數據。
遵從最小權限原則。
保持系統干凈、整潔。
使用好的命名和組織約定來避免產生混亂,例如服務器是用于開發還是用于生產環境。
謹慎安排升級數據庫服務器。
在升級前,使用諸如PerconaToolkit中的pt-upgrade之類的工具仔細檢査系統。
使用InnoDB并進行適當的配置,確保InnoDB是默認存儲引擎。如果存儲引擎被禁止,服務器就無法啟動。
確認基本的服務器配置是正確的。
通過skip_name_resolve禁止DNS。
除非能證明有效,否則禁用査詢緩存。
避免使用復雜的特性,例如復制過濾和觸發器,除非確實需要。
監控重要的組件和功能,特別是像磁盤空間和RAID卷狀態這樣的關鍵項目,但也要避免誤報,只有當確實發生問題時才發送告警。
盡量記錄服務器的狀態和性能指數,如果可能就盡量久地保存。
定期檢查復制完整性。
將備庫設置為只讀,不要讓復制自動啟動。
定期進行查詢語句審査。
歸檔并清理不需要的數據。
為文件系統保留一些空間。在GNU/Linux中,可以使用-m選項來為文件系統本身保留空間。還可以在LVM卷組中留下一些空閑空間?;蛘?,更簡單的方法,僅僅創建一個巨大的空文件,在文件系統快滿時,直接將其刪除。
養成習慣,評估和管理系統的改變、狀態以及性能信息。
我們發現對系統變更管理的缺失是所有導致宕機的事件中最普遍的原因。典型的錯誤包括粗心的升級導致升級失敗并遭遇一些Bug,或是尚未測試就將Schema或査詢語句的更改直接運行到線上,或者沒有為一些失敗的情況制定計劃,例如達到了磁盤容量限制。另外一個導致問題的主要原因是缺少嚴格的評估,例如因為疏忽沒有確認備份是否是可以恢復的。最后,可能沒有正確地監控MySQL的相關信息。例如緩存命中率報警并不能說明出現問題,并且可能產生大量的誤報,這會使監控系統被認為不太有用,于是一些人就會忽略報警。有時候監控系統失效了,甚至沒人會注意到,直至你的老板質問你,“為什么Nagios沒有告訴我們磁盤已經滿了”。
3.2 降低平均恢復時間(MTTR)
之前提到,可以通過減少恢復時間來獲得高可用性。事實上,一些人走得更遠,只專注于減少恢復時間的某個方面:通過在系統中建立冗余來避免系統完全失效,并避免單點失效問題。
在降低恢復時間上進行投資非常重要,一個能夠提供冗余和故障轉移能力的系統架構,則是降低恢復時間的關鍵環節。但實現高可用性不單單是一個技術問題,還有許多個人和組織的因素。組織和個人在避免宕機和從宕機事件中恢復的成熟度和能力層次各不相同。
團隊成員是最重要的髙可用性資產,所以為恢復制定一個好的流程非常重要。擁有熟練技能、應變能力、訓練有素的雇員,以及處理緊急事件的詳細文檔和經過仔細測試的流程,對從宕機中恢復有巨大的作用。但也不能完全依賴工具和系統,因為它們并不能理解實際情況的細微差別,有時候它們的行為在一般情況下是正確的,但在某些場景下卻會是個災難!
對宕機事件進行評估有助于提升組織學習能力,可以幫助避免未來發生相似的錯誤,但是不要對“事后反思”或“事后的調査分析”期待太髙。后見之明被嚴重曲解,并且一味想找到導致問題的唯一根源,這可熊會影響你的判斷力。許多流行的方法,例如“五個為什么”,可能會被過度使用,導致一些人將他們的精力集中在找到唯一的替罪羊。很難去回顧我們解決的問題當時所處的狀況,也很難理解真正的原因,因為原因通常是多方面的。因此,盡管事后反思可能是有用的,但也應該對結論有所保留。即使是我們給出的建議,也是基于長期研究導致宕機事件的原因以及如何預防它們所得,并且只是我們的觀點而已。
這里我們要反復提醒:所有的宕機事件都是由多方面的失效聯合在一起導致的。因此,可以通過利用合適的方法確保單點的安全來避免。整個鏈條必須要打斷,而不僅僅是單個環節。例如,那些向我們求助恢復數據的人不僅遭受數據丟失(存儲失效,DBA誤操作等),同時還缺少一個可用的備份。
這樣說來,當開始調査并嘗試阻止失效或加速恢復時,大多數人和組織不應太過于內疚,而是要專注于技術上的一些措施——特別是那些很酷的方法,例如集群系統和冗余架構。這些是有用的,但要記住這些系統依然會失效。事實上,有一種MMM復制管理,雖然它被證明可能導致更多宕機時間。你應該不會奇怪一組Perl腳本會陷于混亂,但即使是特別昂貴并精密設計的系統也會出現災難性的失效——是的,即使是花費了大量金錢的SAN也是如此。我們已經見過太多的SAN失效。
4.避免單點失效
找到并消除系統中的可能失效的單點,并結合切換到備用組件的機制,這是一種通過減少恢復時間(MTTR)來改善可用性的方法。如果你夠聰明,有時候甚至能將實際的恢復時間降低至0,但總的來說這很困難。(即使一些非常引人注目的技術,例如昂貴的負載均衡器,在發現問題并進行反饋時也會導致一定的延遲。)
思考并梳理整個應用,嘗試去定位任何可能失效的單點。是一個硬盤驅動器,一臺服務器,一臺交換或路由器,還是某個機架的電源?所有數據都在一個數據中心,或者冗余數據中心是由同一個公司提供的嗎?系統中任何不冗余的部分都是一個可能失效的單點。其他比較普遍的單點失效依賴于一些服務,例如DNS、單一網絡提供商、單個云“可用區域”,以及單個電力輸送網,具體有哪些取決于你的關注點。
單點失效并不總是能夠消除。增加冗余或許也無法做到,因為有些限制無法避開,例如地理位置,預算,或者時間限制等。試著去理解每一個影響可用性的部分,采取一種平衡的觀點來看待風險,并首先解決其中影響最大的那個。一些人試圖編寫一個軟件來處理所有的硬件失效,但軟件本身導致的宕機時間可能比它節約的還要多。也有人想建立一種“永不沉沒”的系統,包括各種冗余,但他們忘記了數據中心可能掉電或失去連接?;蛟S他們徹底忘記了惡意攻擊者和程序錯誤的可能性,這些情況可能會刪除或損壞數據--個不小心執行的DROPTABLE也會產生宕機時間。
可以采用兩種方法來為系統增加冗余:增加空余容量和重復組件。增加容量余量通常很簡單——可以使用本章或前一章討論的任何技術。一個提升可用性的方法是創建一個集群或服務器池,并使用負載均衡解決方案。如果一臺服務器失效,其他服務器可以接管它的負載。有些人有意識地不使用組件的全部能力,這樣可以保留一些“動態余量”來處理因為負載增加或組件失效導致的性能問題。
出于很多方面的考慮會需要冗余組件,并在主要組件失效時能有一個備件來隨時替換。冗余組件可以是空閑的網卡、路由器或者硬盤驅動器——任何能想到的可能失效的東西。完全冗余MySQL服務器可能有點困難,因為一個服務器在沒有數據時毫無用處。這意味著你必須確保備用服務器能夠獲得主服務器上的數據。共享或復制存儲是一個比較流行的辦法,但這真的是一個高可用性架構嗎?讓我們深入其中看看。
4.1 共享存儲或磁盤復制
共享存儲能夠為數據庫服務器和存儲解耦合,通常使用的是SAN。使用共享存儲時,服務器常掛載文件系統并進行操作。如果服務器掛了,備用服務器可以掛載相同的文件系統,執行需要的恢復操作,并在失效服務器的數據上啟動MySQL。這個過程在邏輯上跟修復那臺故障的服務器沒什么兩樣,不過更快速,因為備用服務器已經啟動,隨時可以運行。當開始故障轉移時,檢査文件系統、恢復InnoDB以及預熱,最有可能遇到延遲的地方,但檢測失效本身在許多設置中也會花費很長時間。
共享存儲有兩個優點:可以避免除存儲外的其他任何組件失效所引起的數據丟失,并為非存儲組件建立冗余提供可能。因此它有助于減少系統一些部分的可用性需求,這樣就可以集中精力關注一小部分組件來獲得高可用性。不過,共享存儲本身仍是可能失效的單點。如果共享存儲失效了,那整個系統也失效了,盡管SAN通常設計良好,但也可能失效,有時候需要特別關注。就算SAN本身擁有冗余也會失效。
共享存儲本身也有風險,如果MySQL崩潰等故障導致數據文件損壞,可能會導致備用服務器無法恢復。我們強烈建議在使用共享存儲策略時選擇Innodb存儲引擎或其他穩定的ACID存儲引擎。一次崩潰幾乎肯定會損壞MyISAM表,需要花費很長時間來修復,并且會丟失數據。我們也強烈建議使用日志型文件系統。我們見過比較嚴重的情況是,使用非日志型文件系統和SAN(這是文件系統的問題,跟SAN無關)導致數據損壞無法恢復。
磁盤復制技術是另外一個獲得跟SAN類似效果的方法。MySQL中最普遍使用的磁盤復制技術是DRBD,并結合Linux-HA項目中的工具使用(后面會介紹到)。
DRBD是一個以Linux內核模塊方式實現的塊級別同步復制技術。它通過網卡將主服務器的每個塊復制到另外一個服務器的塊設備上(備用設備),并在主設備提交塊之前記錄下來由于在備用DRBD設備上的寫入必須要在主設備上的寫入完成之前,因此備用設備的性能至少要和主設備一樣,否則就會限制主設備的寫入性能。同樣,如果正在使用DRBD磁盤復制技術以保證在主設備失效時有一個可隨時替換的備用設備,備用服務器的硬件應該跟主服務器的相匹配。帶電池寫緩存的RAID控制器對DRBD而言幾乎是必需的,因為在沒有這樣的控制器時性能可能會很差。
如果主服務器失效,可以把備用設備提升為主設備。因為DRBD是在磁盤塊層進行復制,而文件系統也可能會不一致。這意味著最好是使用日志型文件系統來做快速恢復。一旦設備恢復完成,MySQL還需要運行自身的恢復。原故障服務器恢復后,會與新的主設備進行同步,并假定自身角色為備用設備。
從如何實際地實現故障轉移的角度來看,DRBD和SAN很相似:有一個熱備機器,開始提供服務時會使用和故障機器相同的數據。最大的不同是,DRBD是復制存儲——不是共享存儲——所以當使用DRBD時,獲得的是一份復制的數據,而SAN則是使用與故障機器同一物理設備上的相同數據副本。換句話說,磁盤復制技術的數據是冗余的,所以存儲和數據本身都不會存在單點失效問題。這兩種情況下,當啟動備用機器時,MySQL服務器的緩存都是空的。相比之下,備庫的緩存至少是部分預熱的。
DRBD有一些很好的特性和功能,可以防止集群軟件普遍會遇到的一些問題。一個典型 的例子是“腦裂綜合征”,在兩個節點同時提升自己為主服務器時會發生這種問題??梢酝ㄟ^配置DRBD來防止這種事件發生。但是DRBD也不是一個能滿足所有需求的完美解決方案。我們來看看它有哪些缺點:
DRBD的故障轉移無法做到秒級以內。它通常至少需要幾秒鐘時間來將備用設備提升成主設備,這還不包括任何必要的文件系統恢復和MySQL恢復。
它很昂貴,因為必須在主動一被動模式下運行。熱備服務器的復制設備因為處于被動模式,無法用于其他任務。當然這是不是缺點取決于看問題的角度。如果你希望獲得真正的髙可用性并且在發生故障時不能容忍服務降級,就不應該在一臺機器上運行兩臺服務器的負載量,因為如果這么做了,當其中一臺發生故障時,就無法處理這些負載了??梢杂眠@些備用服務器做一些其他用途,例如用作備庫,但還是會有一些資源浪費。
對于MyISAM表實際上用處不大,因為MyISAM表崩潰后需要花費很長時間來檢査和修復。對任何期望獲得高可用性的系統而言,MyISAM都不是一個好選擇;請使用InnoDB或其他支持快速、安全恢復的存儲引擎來代替MyISAM。
DRBD無法代替備份。如果磁盤由于蓄意的破壞、誤操作、Bug或者其他硬件故障導致數據損壞,DRBD將無濟于事。此時復制的數據只是被損壞數據的完美副本。你需要使用備份(或MySQL延時復制)來避免這些問題。
對寫操作而言增加了負擔。具體會增加多少負擔呢?通??梢允褂冒俜直葋肀硎荆@并不是一個好的度量方法。你需要理解寫入時增加的延遲主要由網絡往返開銷和遠程服務器存儲導致,特別是對于小的寫入而言延遲會更大。盡管增加的延遲可能也就0.3ms,這看起來比在本地磁盤上I/O的4?10ms的延遲要小很多,但卻是正常的帶有寫緩存的RAID控制器的延遲的3?4倍=使用DRBD導致服務器變慢最常見的原因是MySQL使用InnoDB并采取了完全持久化模式,這會導致許多小的寫入和fsync()調用,通過DRBD同步時會非常慢。
我們傾向于只使用DRBD復制存放二進制日志的設備。如果主動節點失效,可以在被動節點上開啟一個日志服務器,然后對失效主庫的所有備庫應用這些二進制日志。接下來可以選擇其中一個備庫提升為主庫,以代替失效的系統。
說到底,共享存儲和磁盤復制與其說是高可用性(低宕機時間)解決方案,不如說是一種保證數據安全的方法。只要擁有數據,就可以從故障中恢復,并且比無法恢復的情況的MTTR更低。(即使是很長的恢復時間也比不能恢復要快。)但是相比于備用服務器啟動并一直運行的架構,大多數共享存儲或磁盤復制架構會增加MTTR。有兩種啟用備用設備并運行的方法:以及接下來會討論的同步復制。
討論:主動一主動訪問模式的共享存儲怎么樣?
在一個SAN、NAS或者集群文件系統上以主動一主動模式運行多個實例怎么樣?MySQL不能這么做。因為MySQL并沒有被設計成和其他MySQL實例同步對數據的訪問,所以無法在同一份數據上開啟多個MySQL實例。(如果在一份只讀的靜態數據上使用MyISAM,技術上是可行的,但我們還沒有見過任何實際的應用。)
MySQL的一個名為ScaleDB的存儲引擎在底層提供了操作共享存儲的API,但我們還沒有評估過,也沒有見過任何生產環境使用。在mysql5.5發布時時它還是beta版。
4.2 MySQL同步復制
當使用同步復制時,主庫上的事務只有在至少一個備庫上提交后才能認為其執行完成。這實現了兩個目標:當服務器崩潰時沒有提交的事務會丟失,并且至少有一個備庫擁有實時的數據副本。大多數同步復制架構運行在主動-主動模式。這意味著每個服務器在任何時候都是故障轉移的候選者,這使得通過冗余獲得高可用性更加容易。
1.MySQLCluster
MySQL中的同步復制首先出現在MySQLCluster(NDBCluster)。它在所有節點上進行同步的主-主復制。這意味著可以在任何節點上寫入;這些節點擁有等同的讀寫能力。每一行都是冗余存儲的,這樣即使丟失了一個節點,也不會丟失數據,并且集群仍然能提供服務。盡管MySQLCluster還不是適用于所有應用的完美解決方案,但正如我們在前一章提到的,在最近的版本中它做了非??焖俚母倪M,現在已經擁有大量的新特性和功能:非索引數據的磁盤存儲、增加數據節點能夠在線擴展、使用ndbinfo表來管理集群、配置和管理集群的腳本、多線程操作、下推(push-down)的關聯操作(現在稱為自適應查詢本地化)、能夠處理BLOB列和很多列的表、集中式的用戶管理,以及通過像memcached協議一樣的NDBAPI來實現NoSQL訪問。在下一個版本中將包含最終一致運行模式,包括為跨數據中心的主動-主動復制提供事務沖突檢測和跨WAN解決方案。簡而言之,MySQLCluster是一項引人注目的技術。
現在至少有兩個為簡化集群部署和管理提供附加產品的供應商:Oracle針對MySQL Cluster的服務支持包含了MySQLClusterManager工具;Severalnines提供了ClusterControl工具,該工具還能夠幫助部署和管理復制集群。
2.PerconaXtraDBCluster
PerconaXtraDBCluster是一個相對比較新的技術,基于已有的XtraDB(InnoDB)存儲
引擎增加了同步復制和集群特性,而不是通過一個新的存儲引擎或外部服務器來實現。它是基于Galera(支持在集群中跨節點復制寫操作)實現的,這是一個在集群中不同節點復制寫操作的庫。跟MySQLCluster類似,PerconaXtraDBCluster提供同步多主庫復制,支持真正的任意節點寫入能力,能夠在節點失效時保證數據零丟失(持久性,ACID中的D),另外還提供高可用性,在整個集群沒有失效的情況下,就算單個節點失效也沒有關系。
Galera作為底層技術,使用一種被稱為寫入集合(write-set)復制的技術。寫入集合實際上被作為基于行的二進制日志事件進行編碼,目的是在集群中的節點間傳輸并進行更新,但是這不要求二進制日志是打開的。
PerconaXtraDBCluster的速度很快??绻濣c復制實際上比沒有集群還要快,因為在完全持久性模式下,寫入遠程RAM比寫入本地磁盤要快。如果你愿意,可以選擇通過降低每個節點的持久性來獲得更好的性能,并且可以依賴于多個節點上的數據副本來獲得持久性。NDB也是基于同樣的原理實現的。集群在整體上的持久性并沒有降低;僅僅是降低了本地節點的持久性。除此之外,還支持行級別的并發(多線程)復制,這樣就可以利用多個CPU核心來執行寫入集合。這些特性結合起來使得PerconaXtraDBCluster非常適合云計算環境,因為云計算環境中的CPU和磁盤通常比較慢。
在集群中通過設置auto_increment_offset和auto_increment_increment來實現自增鍵,以使節點間不會生成沖突的主鍵值。鎖機制和標準InnoDB完全相同,使用的是樂觀并發控制。當事務提交時,所有的更新是序列化的,并在節點間傳輸,同時還有一個檢測過程,以保證一旦發生更新沖突,其中一些更新操作需要丟棄。這樣如果許多節點同時修改同樣的數據,可能產生大量的死鎖和回滾。
PerconaXtraDBCluster只要集群內在線的節點數不少于“法定人數(quorum)”就能保證服務的高可用性。如果發現某個節點不屬于“法定人數”中的一員,就會從集群中將其踢出。被踢出的節點在再次加入集群前必須重新同步。因此集群也無法處理“腦裂綜合征”;如果出現腦裂則集群會停止服務。在一個只有兩個節點的集群中,如果其中一個節點失效,剩下的一個節點達不到“法定人數”,集群將停止服務,所以實際上最少需要三個節點才能實現高可用的集群。
PerconaXtraDBCluster有許多優點:
提供了基于InnoDB的透明集群,所以無須轉換到另外的技術,例如NDB這樣完全不同的技術需要很多學習成本和管理。
提供了真正的高可用性,所有節點等效,并在任何時候提供讀寫服務。相比較而言,MySQL內建的異步復制和半同步復制必須要有一個主庫,并且不能保證數據被復制到備庫,也無法保證備庫數據是最新的并能夠隨時提升為主庫。
節點失軟時保證數據不丟失。實際上,由于所有的節點都擁有全部數據,因此可以丟失任意一個節點而不會丟失數據(即使集群出現腦裂并停止工作)。這和NDB不同,NDB通過節點組進行分區,當在一個節點組中的所有服務器失效時就可能丟失數據。
備庫不會延遲,因為在事務提交前,寫入集合已經在集群的所有節點上傳播并被確認了。
因為是使用基于行的日志事件在備庫上進行更新,所以執行寫入集合比直接執行更新的開銷要小很多,就和使用基于行的復制差不多。當結合多線程應用的寫入集合時,可以使其比MySQL本身的復制更具備可擴展性。
當然我們也需要提及Percona
XtraDB Cluster的一些缺點:
它很新,因此還沒有足夠的經驗來證明其優點和缺點,也缺乏合適的使用案例。
整個集群的寫入速度由最差的節點決定。因此所有的節點最好擁有相同的硬件配置,如果一個節點慢下來(例如,RAID卡做了一次battery-learn循環),所有的節點都會慢下來。如果一個節點接收寫入操作變慢的可能性為P,那么有3個節點的集群變慢的可能性為3P。
沒有NDB那樣節省空間,因為每個節點都需要保存全部數據,而不是僅僅一部分。但另一方面,它基于Percona XtraDB (InnoDB的增強版本),也就沒有NDB關于磁盤數據限制的擔憂。
當前不支持一些在異步復制中可以做的操作,例如在備庫上離線修改schema,然后將其提升為主庫,然后在其他節點上重復離線修改操作。當前可替代的選擇是使用諸如PerconaToolkit中的在線schema修改工具。不過滾動式schema升級(rollingschemaupgrade)也發布。
當向集群中增加一個新節點時,需要復制所有的數據,還需要跟上不斷進行的寫入操作,所以一個擁有大量寫入的大型集群很難進行擴容。這實際上限制了集群的數據大小。我們無法確定具體的數據。但悲觀地估計可能低至100GB或更小,也可能會大得多。這一點需要時間和經驗來證明。
復制協議在寫入時對網絡波動比較敏感,這可能導致節點停止并從集群中踢出。所以我們推薦使用高性能網絡,另外還需要很好的冗余。如果沒有可靠的網絡,可能會導致需要頻繁地將節點加入到集群中。這需要重新同步數據。有一個幾乎接近可用的特性,即通過增量狀態傳輸來避免完全復制數據集,因此未來這并不是一個問題。還可以配置Galera以容忍更大的網絡延遲(以延遲故障檢測為代價),另外更加可靠的算法也計劃在未來的版本中實現。
如果沒有仔細關注,集群可能會增長得太大,以至于無法重啟失效節點,就像在一個合理的時間范圍內,如果在日常工作中沒有定期做恢復演練,備份也會變得太過龐大而無法用于恢復。我們需要更多的實踐經驗來了解它事實上是如何工作的。
由于在事務提交時需要進行跨節點通信,寫入會更慢,隨著集群中增加的節點越來越多,死鎖和回滾也會更加頻繁。(參閱前一章了解為什么會發生這種情況。)
Percona XtraDB
Cluster和Galera都處于其生命周期的早期,正在被快速地修改和改進。在mysql5.5發布時,正在進行或即將進行的改進包括群體行為、安全性、同步性、內存管理、狀態轉移等。未來還可以為離線節點執行諸如滾動式schema變更的操作。
4.3 基于復制的冗余
復制管理器是使用標準MySQL復制來創建冗余的工具。盡管可以通過復制來改善可用性,但也有一些“玻璃天花板”會阻止MySQL當前版本的異步復制和半同步復制獲得和真正的同步復制相同的結果。復制無法保證實時的故障轉移和數據零丟失,也無法將所有節點等同對待。
復制管理器通常監控和管理三件事:應用和MySQL間的通信、MySQL服務器的健康度,以及MySQL服務器間的復制關系。它們既可以修改負載均衡的配置,也可以在必要的時候轉移虛擬IP地址以使應用連接到合適的服務器上,還能夠在一個偽集群中操縱復制以選擇一個服務器作為寫入節點。大體上操作并不復雜:只需要確定寫入不會發送到一個還沒有準備好提供寫服務的服務器上,并保證當需要提升一臺備庫為主庫時記錄下正確的復制坐標。
這聽起來在理論上是可行的,但我們的經驗表明實際上并不總是能有效工作。事實上這非常糟糕,有些時候最好有一些輕量級的工具集來幫助從常見的故障中恢復并以很少的開銷獲得較髙的可用性。不幸的是,在mysql5.5時還沒有聽說任何一個好的工具集可以可靠地完成這一點。稍后我們會介紹兩個復制管理器,其中一個很新,而另外一個則有很多問題。
我們發現很多人試圖去寫自己的復制管理器。他們常常會陷入很多人已經遭遇過的陷阱。自己去寫一個復制管理器并不是好主意。異步組件有大量的故障形式,很多你從未親身經歷過,其中一些甚至無法理解,并且程序也無法適當處理,因此從這些異步組件中得到正確的行為相當困難,并且可能遭遇數據丟失的危險。事實上,機器剛開始出現問題時,由一個經驗豐富的人來解決是很快的,但如果其他人做了一些錯誤的修復操作則可能導致問題更嚴重。
我們要提到的第一個復制管理器是MMM,本書的作者對于該工具集是否適用于生產環境部署的意見并不一致(盡管該工具的原作者也承認它并不可靠)。我們中有些人認為它在一些人工一故障轉移模式下的場景中比較有用,而有些人甚至從不便用這個工具。我們的許多客戶在自動一故障轉移模式下使用該工具時確實遇到了許多嚴重的問題。它會導致健康的服務器離線,也可能將寫入發送到錯誤的地點,并將備庫移動到錯誤的坐標。有時混亂就接踵而至。
另外一個比較新一點的工具是YoshinoriMatsunobu的MHA工具集。它和MMM—樣是一組腳本,使用相同的通用技術來建立一個偽集群,但它不是一個完全的替換者,它不會去做太多的事情,并且依賴干Pacemaker來轉移虛擬IP地址。一個主要的不同是,MHA有一個很好的測試集,可以防止一些MMM遇到過的問題。除此之外,我們對該工具集還沒有更多的認識,我們只和Yoshinori討論過,但還沒有真正使用過。
基于復制的冗余最終來說好壞參半。只有在可用性的重要性遠比一致性或數據零丟失保
證更重要時才推薦使用。例如,一些人并不會真的從他們的網站功能中獲利,而是從它的可用性中賺錢。誰會在乎是否出現了故障導致一張照片丟失了幾條評論或其他什么東西呢?只要廣告收益繼續滾滾而來,可能并不值得花更多成本去實現真正的高可用性。但還是可以通過復制來建立“盡可能的”高可用性,當遇到一些很難處理的嚴重宕機時可能會有所幫助。這是一個大賭注,并且可能對大多數人而言太過于冒險,除非是那些老成(或者專業)的用戶。
問題是許多用戶不知道如何去證明自己有資格并評估復制“輪盤賭”是否適合他們。這
有兩個方面的原因。第一,他們并沒有看到“玻璃天花板”,錯誤地認為一組虛擬IP地址、復制以及管理腳本能夠實現真正的髙可用性。第二,他們低估了技術的復雜度,因此也低估了嚴重故障發生后從中恢復的難度。一些人認為他們能夠使用基于復制的冗余技術,但隨后他們可能會更希望選擇一個有更強保障的簡單系統。
其他一些類型的復制,例如DRBD或者SAN,也有它們的缺點——請不要認為我們將這些技術說得無所不能而把MySQL自身的復制貶得一團糟,那不是我們的本意。你可以為DRBD寫出低質量的故障轉移腳本,這很簡單,就像為MySQL復制編寫腳本一樣。主要的區別是MySQL復制非常復雜,有很多非常細小的差別,并且不會阻止你干壞事。
5.故障轉移和故障恢復
冗余是很好的技術,但實際上只有在遇到故障需要恢復時才會用到。(見鬼,這可以用備份來實現)。冗余一點兒也不會增加可用性或減少宕機。在故障轉移的過程中,高可用性是建立在冗余的基礎上。當有一個組件失效,但存在冗余時,可以停止使用發生故障的組件,而使用冗余備件。冗余和故障轉移結合可以幫助更快地恢復,如你所知,MTTR的減少將降低宕機時間并改善可用性。
在繼續這個話題之前,我們先來定義一些術語。我們統一使用“故障轉移(failover)”,有些人使用“回退”(fallback)表達同一意思。有時候也有人說“切換(switchover)”,以表明一次計劃中的切換而不是故障后的應對措施。我們也會使用“故障恢復”來表示故障轉移的反面。如果系統擁有故障恢復能力,故障轉移就是一個雙向過程:當服務器A失效,服務器B代替它,在修復服務器A后可以再替換回來。
故障轉移比僅僅從故障中恢復更好。也可以針對一些情況制訂故障轉移計劃,例如升級、schema變更、應用修改,或者定期維護,當發生故障時可以根據計劃進行故障轉移來減少宏機時間(改善可用性)。
你需要確定故障轉移到底需要多快,也要知道在一次故障轉移后替換一個失效組件應該多快。在你恢復系統耗盡的備件容量之前,會出現冗余不足,并面臨額外風險。因此,擁有一個備件并不能消除即時替換失效組件的需求。構建一個新的備用服務器,安裝操作系統,并復制數據的最新副本,可以多快呢?有足夠的備用機器嗎?你可能需要不止一臺以上。
故障轉移的緣由各不相同。我們已經討論了其中的一些,因為負載均衡和故障轉移在很多方面很相似,它們之間的分界線比較模糊??偟膩碚f,我們認為一個完全的故障轉移解決方案至少能夠監控并自動替換組件。它對應用應該是透明的。負載均衡不需要提供這些功能。
在UNIX領域,故障轉移常常使用HighAvailabilityLinux項目提供的工具來完成,該項目可在許多類UNIX系統上運行,而不僅僅是Linux。Linux-HA棧在最近幾年明顯多了很多新特性?,F在大多數人認為Pacemaker是棧中的一個主要組件。Pacemaker替代了老的心跳工具。還有其他一些工具實現了IP托管和負載均衡功能??梢詫⑺鼈兏鶧RBD和/或者LVS結合起來使用。
故障轉移最重要的部分就是故障恢復。如果服務器間不能自如切換,故障轉移就是一個死胡同,只能是延緩宕機時間而已。這也是我們傾向于對稱復制布局,例如雙主配置,而不會選擇使用三臺或更多的聯合主庫(co-master)來進行環形復制的原因。如果配置是對等的,故障轉移和故障恢復就是在相反方向上的相同操作。(值得一提的是DRBD具有內建的故障恢復功能。)
在一些應用中,故障轉移和故障恢復需要盡量快速并具備原子性。即便這不是決定性的,不依靠那些不受你控制的東西也依然是個好主意,例如DNS變更或者應用程序配置文件。一些問題直到系統變得更加龐大時才會顯現出來,例如當應用程序強制重啟以及原子性需求出現時。
由于負載均衡和故障轉移兩者聯系較緊密,有些硬件和軟件是同時為這兩個目的設計的,因此我們建議所選擇的任何負載均衡技術應該都提供故障轉移功能。這也是我們建議避免使用DNS和修改代碼來做負載均衡的真實原因。如果為負載均衡采用了這些策略,就需要做一些額外的工作:當需要高可用性時,不得不重寫受影響的代碼。
以下小節討論了一些比較普遍的故障轉移技術。可以手動執行或使用工具來實現。
5.1 提升備庫或切換角色
提升一臺備庫為主庫,或者在一個主一主復制結構中調換主動和被動角色,這些都是許多MySQL故障轉移策略很重要的一部分。正如本章之前提到的,我們不能認定自動化工具總能在所有的情況下做正確的事情——或者至少以我們的名譽擔保沒有這樣的工具。
你不應該假定在發生故障時能夠立刻切換到被動備庫,這要看具體的工作負載。備庫會重放主庫的寫入,但如果不用來提供讀操作,就無法進行預熱來為生產環境負載提供服務。如果希望有一個隨時能承擔讀負載的備庫,就要不斷地“訓練”它,既可以將其用于分擔工作負載,也可以將生產環境的讀査詢鏡像到備庫上。我們有時候通過監聽TCP流量,截取出其中的SELECT査詢,然后在備庫上重放來實現這個目的。PerconaToolkit中有一些工具可以做到這一點。
5.2 虛擬IP地址或IP接管
可以為需要提供特定服務的MySQL實例指定一個邏輯IP地址。當MySQL實例失效時,可以將IP地址轉移到另一臺MySQL服務器上。這和我們在前一章提到的思想本質上是相同的,唯一的不同是現在是用于故障轉移,而不是負載均衡。
這種方法的好處是對應用透明。它會中斷已有的連接,但不要求修改配置。有時候還可以原子地轉移IP地址,保證所有的應用在同一時間看到這一變更。當服務器在可用和不可用狀態間“搖擺”時,這一點尤其重要。
以下是它的一些不足之處:
需要把所有的IP地址定義在同一網段,或者使用網絡橋接。
改變IP地址需要系統root權限。
有時候還需要更新ARP緩存。有些網絡設備可能會把ARP信息保存太久,以致無法即時將一個IP地址切換到另一個MAC地址上。我們看到過很多網絡設備或其他組件不配合切換的例子,結果系統的許多部分可能無法確定IP地址到底在哪里。
需要確定網絡硬件支持快速IP接管。有些硬件需要克隆MAC地址后才能工作。
有些服務器即使完全喪失功能也會保持持有IP地址,所以可能需要從物理上關閉或斷開網絡連接。這就是為人所熟知的“擊中其他節點的頭部”(shoottheothernodeinthehead,簡稱STONITH)。它還有一個更加微妙并且比較官方的名字:擊劍(fencing) 。
浮動IP地址和IP接管能夠很好地應付彼此臨近(也就是在同一子網內)的機器之間的故障轉移。但是最后需要提醒的是,這種策略并不總是萬無一失,還取決于網絡硬件等因素。
討論:等待更新擴散
經常有這種情況,在某一層定義了一個冗余后,需要等待低層執行一些改變。在本章前面的篇幅里,我們指出通過DNS修改服務器是一個很脆弱的解決方案,因為DNS的更新擴散速度很慢,改變IP地址可給予你更多的控制,但在一個LAN中的IP地址同樣依賴于更低層——ARP——來擴散更新。
5.3 中間件解決方案
可以使用代理、端口轉發、網絡地址轉換(NAT)或者硬件負載均衡來實現故障轉移和故障恢復。這些都是很好的解決方案,不像其他方法可能會引入一些不確定性(所有系統組件認同哪一個是主庫嗎?它能夠及時并原子地更改嗎?),它們是控制應用和服務器間連接的中樞。但是,它們自身也引入了單點失效,需要準備冗余來避免這個問題。
使用這樣的解決方案,你可以將一個遠程數據中心設置成看起來好像和應用在同一個網絡里。這樣就可以使用諸如浮動IP地址這樣的技術讓應用和一個完全不同的數據中心開始通信。你可以配置每個數據中心的每臺應用服務器,通過它自己的中間件連接,將流量路由到活躍數據中心的機器上。圖12-1描述了這種配置。
如果活躍數據中心安裝的MySQL徹底崩潰了,中間件可以路由流量到另外一個數據中心的服務器池中,應用無須知道這個變化。
這種配置方法的主要缺點是在一個數據中心的Apache服務器和另外一個數據中心的MySQL服務器之間的延遲比較大。為了緩和這個問題,可以把Web服務器設置為重定向模式。這樣通信都會被重定向到放置活躍MySQL服務器的數據中心。還可以使用HTTP代理來實現這一目標。
圖12-1顯示了如何使用代理來連接MySQL服務器,也可以將這個方法和許多別的中間件架構結合在一起,例如LVS和硬件負載均衡器。
5.4 在應用中處理故障轉移
有時候讓應用來處理故障轉移會更簡單或者更加靈潔。例如,如果應用遇到一個錯誤,這個錯誤外部觀察者正常情況下是無法察覺的,例如關于數據庫損壞的錯誤日志信息,那么應用可以自己來處理故障轉移過程。
雖然把故障轉移處理過程整合到應用中看起來比較吸引人,但可能沒有想象中那么有效。大多數應用有許多組件,例如cron任務、配置文件,以及用不同語言編寫的腳本。將故障轉移整合到應用中可能導致應用變得太過笨拙,尤其是當應用增大并變得更加復雜時。
但是將監控構建到應用中是一個好主意,當需要時,能夠立刻開始故障轉移過程。應用應該也能夠管理用戶體驗,例如提供降級功能,并顯示給用戶合適的信息。
6.總結
可以通過減少宕機來獲得高可用性,這需要從以下兩個方面來思考:增加兩次故障之間的正常運行時間(MTBF),或者減少從故障中恢復的時間(MTTR)。
要增加兩次故障之間的正常運行時間,就要嘗試去防止故障發生。悲劇的是,在預防故障發生時,它仍然會覺得你做的不夠多,所以預防故障的努力經常會被忽視掉。我們已經著重提到了如何在MySQL系統中預防宕機;具體的細節可以參閱我們的白皮書,從上可以獲得。試著從宏機中獲得經驗教訓,但也要謹防在故障根源分析和事后檢驗時集中在某一點上而忽略其他因素。
縮短恢復時間可能更復雜并且代價很髙。從簡單和容易的方面來說,可以通過監控來更快地發現問題,并記錄大量的度量值以幫助診斷問題。作為回報,有時候可以在發生宕機前就發現問題。監控并有選擇地報警以避免無用的信息,但也要及時記錄狀態和性能度量值。
另外一個減少恢復時間的策略是為系統建立冗余,并使系統具備故障轉移能力,這樣當故障發生時,可以在冗余組件間進行切換。不幸的是,冗余會讓系統變得相當復雜?,F在應用不再是集中化的,而是分布式的,這意味著協調、同步、CAP定理、拜占庭將軍問題,以及所有其他各種雜亂的東西。這也是像NDBCluster這樣的系統很難創建并且很難提供足夠的通用性來為所有的工作負載提供服務的原因。
本章和前面兩章提及的話題常常被放在一起討論:復制、可擴展性,以及高可用性。我們已經盡量將它們獨立開來,因為這有助于理清這些話題的不同之處。那么這三章有哪些關聯之處呢?
在其應用增長時,人們一般希望從他們的數據庫中知道三件事:
他們希望能夠增加容量來處理新增的負載而不會損失性能。
他們希望保證不丟失已提交的事務。
他們希望應用能一直在線并處理事務,這樣他們就能夠一直賺錢。
為了達到這些目的,人們常常首先增加冗余。結合故障轉移機制,通過最小化MTTR來提供高可用性。這些冗余還提供了空閑容量,可以為更多的負載提供服務。
當然,除了必要的資源外,還必須要有一份數據副本。這有助于在損失服務器時避免丟失數據,從而增強持久性。生成數據副本的唯一辦法是通過某種方法進行復制。不幸的是,數據副本可能會引入不一致。處理這個問題需要在節點間協調和通信。這給系統帶來了額外的負擔;這也是系統或多或少存在擴展性問題的原因。
數據副本還需要更多的資源(例如更多的硬盤驅動器,更多的RAM),這會增加開銷。有一個辦法可以減少資源消耗和維護一致性的開銷,就是為數據分區(分片)并將每個分片分發到特定的系統中。這可以減少需要復制的重復數據的次數,并從資源冗余中分離數據冗余。
所以,盡管一件事總會導致另外一件事,但我們是在討論一組相關的觀點和實踐來達成一系列目的。他們不僅僅是講述同一件事的不同方式。
最后,需要選擇一個對你和應用有意義的策略。決定選擇一個完全的端到端(end-to-end)髙可用性策略并不能通過簡單的經驗法則來處理,但我們給出的一些粗略的指引也許會有所幫助。
為了獲得很短的宕機時間,需要冗余服務器能夠及時地接管應用的工作負載。它們必須在線并一直執行查詢,而不僅僅是備用,因此它們是“預熱”過的,處于隨時可用的狀態。
如果需要很強的可用性保證,就需要諸如MySQLCluster、PerconaXtraDBCluster,或者Clustrix這樣的集群產品。如果能容忍在故障轉移過程中稍微慢一些,標準的MySQL復制也是個很好的選擇。要謹慎使用自動化故障轉移機制;如果沒有按照正確的方式工作,它們可能會破壞數據。
如果不是很在意故障轉移花費的時間,但希望避免數據丟失,就需要一些強力保證數據
的冗余——例如,同步復制。在存儲層,這可以通過廉價的DRBD來實現,或者使用兩個昂貴的SAN來進行同步復制。也可以選擇在數據庫層復制數據,可以使用的技術包括MySQLCluster、PerconaXtraDBCluster或者Clustrix。也可以使用一些中間件,例如TungstenReplicator。如果不需要強有力的保護,并且希望盡量保證簡單,那么正常的異步復制或半同步復制在開銷合理時可能是很好的選擇。
或者也可以將應用放到云中。為什么不呢?這樣難道不是能夠立刻獲得髙可用性和無限擴展能力嗎?云廠商過多,這里就不做討論。
作者:小家電維修
出處:https://www.cnblogs.com/lizexiong/
轉世燕還故榻,為你銜來二月的花。
?
總結
以上是生活随笔為你收集整理的MySQL的高可用性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于web性能一些特性汇总
- 下一篇: pc端和移动端的区别