高可用是構建分佈式系統的基石。一方面,出於成本考慮, 分佈式系統每每採起比較廉價的硬件,其可靠性相對於小型機、專有硬件有很大的不足, 而分佈式系統的規模通常比較大,假如硬件的可靠性只有三個9(99.9%), 一個1000臺機器規模的集羣天天將面臨1臺機器宕機的風險,在如此大規模的狀況下,存儲介質,好比硬盤可能會隨時都有損壞,結點之間的網絡可能隨時都會有抖動,機房可能局部或總體斷電,地區或數據中心可能會出現不可用,若是不在設計時考慮這些問題,當這些狀況出現的時候,系統將很快處於不可用的狀態;另外一方面,分佈式系統的程序在設計與實現上也更爲複雜,軟件上既要容錯硬件的不可靠,同時軟件自身也有可能有問題, 在對外部環境容錯的同時須要考慮對軟件BUG的容錯。linux
OceanBase在設計之初就充分考慮了高可用問題,確保OceanBase有能力在這些異常出現後,仍然能最大可能的提供服務。算法
冗餘是實現高可用的通用方法,爲防止數據丟失,將數據冗餘多份;爲防止系統中某些節點故障,對某些功能節點進行冗餘。 冗餘帶來的好處是能夠抵禦某些節點的損失,而帶來的壞處則主要是成本、性能和一致性問題。數據庫
成本主要包括額外的存儲、網絡、機櫃等硬件成本,這是構建高可用分佈式系統的必不可少的開銷,其整體成本較專有硬件仍然要低,由於專有硬件實際上也須要在內部對某些模塊進行冗餘以獲取高可用性。 性能和一致性問題則是高可用分佈式系統必需要處理問題,這兩個問題直接影響整個系統正確性、延時與吞吐量。安全
在傳統myql或oracle中,咱們每每經過添加備機來實現高可用,且爲了實現高性能和高可用,通常會使用「最大可用」模式:服務器
主機盡力將數據同步到備機,而無論是否同步成功,當主機掛掉之後,將備機升級成主機以繼續提供服務,這就意味着若是主機在宕機前有數據沒有同步到備機,要麼經過某種特殊的手段將數據從宕掉的主機同步到備機,要麼就接受暫時的數據不一致而繼續提供服務,在這種狀況下,若是出現主機永久損壞,則會形成數據丟失:網絡
爲了解決這個問題,可使用最大保護模式(早期的MySQL版本不支持),即主機將日誌同步到備機成功後再應答客戶,這樣會引入另一個問題,即備機故障或網絡抖動會致使失敗,影響可用性; 小微引入了共享存儲,將數據庫redo log放在共享存儲上,主機宕機之後,備機須要確保主機全部的數據都已經同步才能對外提供服務:併發
這樣在主機宕機時,備機做一些額外的檢查後升級爲主機繼續提供服務,這樣能夠確保數據一致性,但引入了共享存儲。傳統的主備模式還有另一個問題是主備之間沒法經過自身決出主備,須要人工切換或者使用一個第三方組件:oracle
可是又引入了HA模塊的穩定性問題,若是HA模塊和主機的網絡不通, HA將不能識別主機是活着仍是網絡有問題,此時HA若是進行切換而主機還活着則會形成後果很嚴重的雙主問題。異步
故障能夠分爲單機故障(磁盤、內存等硬件介質損壞或單臺軟件Crash都屬於單機故障),機架/機房故障(好比整個機架或機房的電源斷電)以及地區/數據中心(好比地區地震形成該區網絡隔離)故障,通常來講,故障單位越小,出現頻率越高,而除非天然災害,一個地區出現故障的機率極小,故障單位越小,實現高可用的難度和成本越低,故障單位越大,因爲引入環境、距離等因素,實現高可用的難度和成本會呈指數倍增加。好比爲了預防單機故障,只須要在本機房預備冗餘節點,故障時經過某些技術方案,能夠作到實時切換;而爲了預防數據中心故障,則須要在另一個地區預備冗餘的數據中心,在故障時因爲通訊距離等緣由,基本上沒法作到無損切換。分佈式
OceanBase雖然在設計之初就考慮到了硬件和軟件的不可靠,但OceanBase的高可用並不是一蹴而就,在實現過程當中,爲了快速實現或者繞過某個暫時沒法攻克的技術難點,會進行綜合權衡,只實現一些出現機率較高的基本高可用策略,而經過人肉或其它手段來保證在某些很難出現的災難出現後能夠儘快恢復。而後經過逐步迭代,逐漸完善,將高可用的範圍提升,好比OceanBase最初的時候只考慮單機故障的高可用,到目前爲止已經能夠實現同城IDC之間的容災。
分佈式系統爲了設計與實現的簡單,每每會在系統中設置一個全局單點,來負責相對比較輕量的管理任務, OceanBase中的rootserver就是這樣一個角色;它主要負責集羣中其它角色的管理並做爲用戶的入口,一般其壓力不高且無本地數據須要存儲,所需信息均可以經過其它角色的彙報來重建。
而做爲一個分佈式數據庫,OceanBase面臨着兩個很難解決的問題:數據一致性與分佈式事務,在早期的OceanBase版本中,採起的策略是暫時繞過這兩個問題,等技術積累到必定程度後再回過頭來解決,因此在OceanBase中另外增長了一個單寫入節點,這個節點的壓力很高,數據沒法經過其它節點來恢復,咱們須要保證這些單節點的高可用。另一個是保存基線數據結點的高可用,這些結點被設計成能夠彈性伸縮,自己具有高可用屬性,但仍然須要考慮磁盤故障以及數據副本之間的一致性。 咱們會在下面的章節分別描述對這兩類節點的高可用策略。
在早期OceanBase的版本中,主要依靠主備來爲單點提供高可用, 使用兩臺機器,其中的一臺角色爲主的機器對外提供服務,另一臺機器作爲熱備, 當主機掛掉後,備機切換爲主,繼續提供服務。
如前所述,這種「最大可用」模式的主備機制主要有兩個問題:第一個問題在於這兩臺機器沒法經過自身來決出主備,必需要依賴於一個第三方組件,早期咱們使用了HA(linux-ha.org) 來作爲仲裁組件,HA使用VIP機制,兩臺機器共享VIP, 同一時刻VIP只會加載在其中的一臺機器, VIP會提供給外部應用程序做爲OceanBase集羣的入口地址,即VIP加載在哪一臺機器上,該機就會做爲主對外提供服務,程序能夠經過不斷檢測VIP是否存在來判斷本機是否爲主機,當HA經過咱們提供的檢測程序檢測到主機故障後,就會將VIP切換到備機, 此時外部請求就會路由到原來的備機,原來的備機檢測到VIP「飄」到本機後,會將本身的角色置爲主:
使用HA主要有幾個問題:
另一個問題在於這種機制沒法保證數據不丟失, 某些極端狀況下須要停機恢復,若是有機器永久損失,則可能會形成數據的丟失,在某些業務上可能沒法接受。
而Updateserver是OceanBase中相當重要的節點,其數據丟失直接影響用戶,也不能經過其它類型節點來重建,因此Updateserver最先拋棄HA模式,而改成經過Rootserver來選主:
Updateserver每次寫入都會生成一條日誌,每條日誌有一個唯一且單調遞增的日誌號, 各Updateserver向Rootserver彙報本身的日誌號, Rootserver選取日誌號最大的Updateserver爲主併發放租約,備Updateserver同時須要向主Updateserver註冊,由主Updateserver發放租約。Updateserver使用一主多備的形式, 每次寫入必需要寫入多數派個節點成功才能應答客戶,寫入請求首先發送到主Updateserver,主Updateserver生成日誌並同步到備機,收到多數派個成功迴應之後應答客戶。若是收不到足夠多的迴應,則不會應答客戶端,該條寫入可能生效,也可能不生效。
因爲要求寫入多數派個節點纔算成功,因此主備間的網絡延遲不能過高,目前OceanBase要求updateserver主備分佈在同城的不一樣IDC, 若是採起一主兩備的模式, 最大能夠容忍一個同城IDC故障。
當某一臺機器同步日誌失敗時,主機會將其剔除在恢復以前再也不向其同步日誌, 這對網絡要求很高,若是網絡連續出現抖動,則會形成可用性問題。在最新版本OceanBase, 將同步日誌的方式也改成Paxos方式,一條日誌只須要寫到多數派個結點上成功便爲成功,不須要各臺備機順序迴應,進一步容忍短暫的網絡問題。
雖然Updateserver去掉了對HA的依賴,但Rootserver仍然須要HA來選主,因爲HA沒法部署在兩個IDC,因此咱們對IDC之間的容災使用的策略是在另一個IDC部署一個備集羣,在主集羣出現故障時,經過人肉的方式將備集羣切換爲主來提供服務。
基於這個緣由,OceanBase 在0.5裏完全取消了基於HA的主備機制,而是經過使用相似paxos的算法來進行選舉:
讓程序自身投票來決出主備, 當一臺機器獲得多數派的承認,它便可以成爲主,這樣系統能容忍必定數量節點的不可用,好比,若是是2臺,則不能容忍有機器宕機,3臺則能夠容忍一臺機器宕機, 3臺機器能夠部署在不一樣的機房以容忍機房故障。
Updateserver仍然經過Rootserver來選主,但這樣也存在一個問題,當Updateserver和Rootserver同時故障的時候,Updateserver必需要等Rootserver恢復完成後才能恢復,增長了故障恢復的時間 。在後續的OceanBase版本中,將去除Updateserver這個單寫入節點,並將其選主的權力下放到自身,擺脫由Rootserver選主的局面。屆時Rootserver的工做會更爲簡單,單點不會成爲OceanBase的瓶頸。
Rootserver/Updateserver是經過冗餘節點來進行容災,備節點通常不提供服務或只提供有限的服務,基線數據則是經過冗餘數據來實現高可用與擴展服務能力。經過冗餘3~6份數據來提供更多的服務能力。冗餘的數據不能存儲在相同的機器上,以免機器宕機後損失可用性。同時在可能的狀況下,數據須要分佈在不一樣的機架上,以抵禦整機架斷電或斷網,OceanBase在早期的實現中,爲了簡化實現與對機器分佈的要求,未考慮數據分佈在不一樣的機櫃,曾出現過整機架斷網而形成服務不可用。
基線數據的副本數決定了一個集羣同時有多少臺機器能夠宕機,若是使用三副本,則同時能夠有兩臺機器宕機,每一個基線數據結點都和Rootserver保持心跳,當該結點宕機之後,rootserver會檢測到並根據目前系統中所擁有的副本數量啓動複製,爲了不因網絡抖動所帶來的沒必要要的副本複製,咱們設定在安全的狀況下(好比剩餘副本數大於1) 能夠容忍副本丟失一段時間(好比8小時),當副本丟失超出該時長後才啓動複製。
副本數的選擇和集羣中機器的數量、單機數據量以及數據恢復速度相關,通常狀況下會選擇至少3個副本,由於2副本狀況下,若是出現一個副本丟失,集羣須要當即啓動複製,而此時集羣可能正處於請求高峯期。陽老師有一個關於副本數選擇的計算方法:
「假設總共有N個節點計算機,它們的平均無端障時間都是M,雲計算系統對一個數據副本丟失並進行復制的時間爲T,則一臺計算機在T時間內出故障的機率是T/M,不出故障的機率是(1-T/M):
N臺機器在該時間內都不出故障的機率是(1-T/M)的N次方;
N臺機器在該時間內剛好有1臺出故障的機率是:(1-T/M)的(N-1)次方T/MN;
N臺機器在該時間內剛好有2臺出故障的機率是:
(1-T/M)的(N-2)次方T/MT/MN(N-1)/(2*1)
所以,N臺機器在該時間段內至少有兩臺機器故障的機率是:
P2(N, M, T)=1-都不出故障的機率-剛好1臺出故障的機率
所以,N臺機器在該時間段內至少有兩臺機器故障的機率是:
P3(N, M, T)=1-都不出故障的機率-剛好1臺出故障的機率--剛好2臺出故障的機率
所以假如N=1000,M=50,000小時,T=600秒,則
P2 (N=10臺,M=50,000小時,T=600秒) = 5.0*10的-10次方;
P2 (N=1000臺,M=50,000小時,T=600秒) = 6.1*10的-9次方;
P2 (N=5000臺,M=50,000小時,T=600秒) = 1.4*10的-4次方;
P3 (N=10臺,M=50,000小時,T=600秒) = 4.5*10的-15次方;
P3 (N=1000臺,M=50,000小時,T=600秒) = 6.2*10的-9次方;
P3 (N=5000臺,M=50,000小時,T=600秒) = 7.6*10的-7次方;
能夠看出,當機器數量達到5000臺時,至少3臺機器出故障的機率低於百萬分之一,而至少兩臺機器出故障的機率高於萬分之一。所以採用3個數據副本時數據有比較高的可靠性。」
並計算出一個表格,假設故障時其它服務器以25MB/s的速度恢復丟失數據:
MTBF爲機器的平均無端障時間,從表中能夠看出三副本同時喪失的機率是極低的。
基線數據的另外一個較爲廣泛的異常爲磁盤損壞, OceanBase存儲基線數據的角色爲ChunkServer, ChunkServer並未使用RAID方式來使用磁盤,一塊磁盤損壞就意味着永久損失該盤上的全部數據,須要Rootserver從另外的機器上進行復制。 當ChunkServer檢測到該磁盤出錯(讀取或寫入失敗)時,會主動將該盤剔除並上報, 讓Rootserver啓動複製程序補足副本。
基線數據須要和增量數據合併而產生新的基線數據,這個過程是由每臺ChunkServer各自完成本身所負責的數據分區,即相同數據的幾個副本會各本身完成這個合併過程,爲了保證各臺ChunkServer合併出來的新基線數據是一致的,每臺Chunkserver在彙報副本信息的時候須要同時彙報校驗值,以檢查副本是否一致,若是出現不一致的狀況,則是軟件有bug或數據有問題,ChunkServer保留兩個版本,解決問題後回退到上一個版本進行從新合併。這種問題出現通常都是軟件Bug, 根據以前的經驗,出現這種狀況的時候,用戶有可能已經讀到不正確的數據,而形成這種問題的主要緣由是Updateserver節點的數據不一致,咱們經過改造Updateserver的日誌同步方式(由主備改成一主多備且要求多數派成功)和增強校驗後,這個問題已經獲得杜絕。
到目前爲止,OceanBase能夠部署在同城的不一樣IDC並容忍少數個IDC故障。OceanBase通常會在同城選擇三個不一樣的IDC進行部署。 目前還沒法作到跨數據中心的容災。 主要緣由是因爲通訊距離的增長,異地數據中心之間的網絡延時較高,沒法作到同步複製數據,而經過異步的形式進行復制則沒法作到無損容災,咱們目前經過一些手段,好比實時拷貝數據庫的redo log到異地數據中心,能夠作到最壞狀況只丟失幾秒的數據。
相較於傳統的主備模式,OceanBase能夠容忍少數派的節點損壞不中斷服務且不丟失數據,爲不少須要高可用且不能丟數據的業務提供了共享存儲之外的解決方案。
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。