持續可用與CAP理論 – 一個系統開發者的觀點
持續可用
本文主要針對金融數據庫,認為金融數據庫的持續可用包含兩點:一個是強一致性;另外一個是高可用性。
數據庫系統必須是強一致性的系統,這是因為數據庫系統有事務ACID的基本要求,而弱一致系統無法做到。業內也有一些流行的NOSQL系統,例如各 種類Dynamo系統,如開源的Cassandra,對同一個最小數據單位(同一行數據)允許多臺服務器同時寫入,雖然采用NWR機制處理沖突,但是由于 不可能解決多臺服務器之間的時序問題,而只能支持弱一致語義。弱一致語義的問題很多,例如無法支持復雜功能,無法構建嚴謹的測試體系,無法應用到核心場 景。雖然弱一致性系統也有一定的應用場景,但本文認為其不符合核心業務持續可用的要求,不予討論。
高可用性可以有很多種解釋,實踐中最常見的解釋為:在一臺服務器,一個交換機,一個機房,或者一個地區整體故障后,系統能夠在多長時間內恢復服務。 當然,這里的恢復服務是以保證強一致性作為前提條件的。如果能夠在秒級(10秒左右)恢復服務,本文認為這個系統是高可用的,絕大部分應用系統都能夠容忍 硬件故障導致的秒級不可用。
CAP理論
CAP理論網上傳了很多版本,大致的意思是:一致性,可用性和分區可容忍性三者只能取其二,不可兼得。由于分區可容忍性是不可選擇的,因此,系統設計時只能在一致性和可用性之間權衡。這就帶來了一個很悲觀的結論:持續可用無法實現。然而,事實是這樣嗎?
首先,我們回到CAP理論的原始定義:
- C(Consistency):A read is guaranteed to return the most recent write for a given client
- A(Availability):A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout)
- P(Partition Tolerance):The system will continue to function when network partitions occur.
CAP理論的證明也比較直觀,如下:
左圖中,假設有兩個節點N1和N2,N1和N2之間發生了網絡分區(P),N1寫入新值y,N2一直是老值x,為了保證一致性(C),讀取N2總是 返回失敗,違反了可用性(A)要求:任何一個沒有發生故障的節點必須在有限時間內返回結果,不允許為Error或者Timeout,系統只能保證CP。
右圖中,從另外一個角度看,假設總是要保證可用性(A),那么,讀到N2中的老值x,由于x和最新寫入的y不同,違反了一致性(C)的要求,系統只能保證AP。
CAP理論本身毋庸置疑,證明可以參考Gilbert和Lynch合著的論文。
CAP中的A與高可用的HA
請讀者會到CAP理論中關于A的定義:CAP中的A要求任何一個沒有發生故障的節點必須在有限的時間內返回結果。然而,如果系統能夠做到當某個節點 發生網絡分區后,將它從系統中剔除,由其它節點繼續提供服務。雖然沒有滿足CAP中A的要求,但是,只要恢復時間足夠快,也符合高可用的要求。而高可用才 是系統設計的本質需求,CAP中的A只是個理論上的需求。
CAP理論的作者Eric Brewer后來確實也寫過一篇文章來說明這個問題:<<CAP twelve years later>>:當發生網絡分區時,系統可以進入分區模式,將網絡不通的節點從系統中剔除后分區恢復,系統繼續運行。
Paxos與持續可用
Paxos是圖靈獎獲得者Lamport的經典之作,第一個版本的論文叫做:<<The Part-time Parliament>>。Lamport奠定了很多分布式系統的理論基礎,比如:<<Time, Clocks and the Ordering of Events in a Distributed System>>。 據傳(八卦,不確信)Lamport通過講故事的方法講”拜占庭將軍”問題,嘗到了甜頭,于是在最初的Paxos論文中也講了一個考古的故事,不過論文提 交上去沒人能看懂,后來不知道從哪個犄角旮旯里面被人翻了出來。Lamport后來也意識到講的故事太難懂,于是又整理了第二個版本叫 做:<<Paxos Made Simple>>。這個版本的初始協議很容易理解,不過如果想深入理解,例如協議中最難理解的Multi-Paxos,難度相比第一個版本一點都沒有降低。與Lamport同時期還有一篇類似的論文,叫做<<Viewstamped Replication>>,最近還有一篇<<Raft>>。建議理解Paxos遇到困難的看后面這兩篇論文,尤其是Raft,在犧牲很少可用性的情況下,對Paxos做了極大的簡化,稱得上業界良心。
八卦完了Paxos,下面進入正題。Lamport和Jim Gray分別是分布式系統和數據庫領域的代表任務,同屬微軟研究院,不過也是共事多年才坐在一起聊兩個領域的問題。高可用是分布式系統的長項,為了實現高 可用,首先必須至少寫三份數據(一主兩備)。這是因為,如果只寫兩份數據,當一份數據出現故障的時候,另外一份數據永遠無法證明自己是對,也無法證明自己 是錯。這就是選舉的價值,類Paxos選舉協議允許在超過半數(Majority)節點正常的情況下提供服務。因此,當某臺服務器,某個交換機,某個 IDC甚至某個地區整體故障的時候,只要不超過整個系統的半數,系統都能夠很快從錯誤中恢復過來,而且完全自動,無需人工干預。
強一致性是數據庫的長項,做法就是強同步,Oracle,MySQL 5.7,國內的MySQL定制版本,例如阿里、網易的MySQL版本都支持強一致性。強同步的問題在于性能損耗,例如傳統數據庫的執行模型(非線程池模 型)一般為一個連接對應一個工作線程/進程,采用強同步模式后事務的延時必然延長,從而導致工作線程/進程數增多,高并發情況下日志線程喚醒工作線程導致 的上下文切換開銷也非常大。另外,為了實現高可用,必須同步至少兩個備庫,使得情況進一步惡化。
采用Paxos協議的持續可用系統有兩種常見的部署方式:
第一種部署方式比較簡單,也最為常見。有一個全局Paxos服務,例如Zookeeper,它和其它機器之間保持租約。Master和兩個 Slave之間保持強同步,事務至少要寫入到Master和其中一個Slave才可以返回成功。同一時刻對于同一份數據只有一個Master,全局 Paxos服務負責選舉,當Master出現故障時,選舉日志號最大的Slave接替原來的Master繼續提供服務。
第二種部署方式比較純粹,只出現在少量的分布式數據庫中,例如Google Spanner,OceanBase 1.0。Leader(相當于Master)和Follower(相當于Slave)之間直接采用Paxos協議進行數據同步和選舉,相比第一種方案,這 種方式實現復雜度要高很多,換來的好處是宕機恢復時間更短,系統更優雅。
共享存儲與硬件解決方案
數據庫領域經常采用共享存儲來解決強一致性問題,主庫將redo日志持久化到共享存儲,如果主庫故障,假設共享存儲是持續可用的,備庫可以從共享存 儲中讀取日志恢復系統。共享存儲與share-nothing架構的強同步有何區別呢?共享存儲模式下只需要部署一個主庫和一個備庫,而share- nothing架構下強同步至少需要一個主庫加兩個備庫。為什么呢?假設share-nothing架構只部署了一個主庫和一個備庫,只要任何一臺機器, 即使是備庫宕機,為了保證強一致性,整個系統都無法提供服務。顯然,這樣的系統在互聯網業務中幾乎沒有應用場景。
共享存儲本質上是硬件解決方案,相比Paxos解決方案,優勢是簡單成熟,在商用數據庫中廣泛使用。問題在于成本高,且依賴硬件本身高可靠和高性能,也無法跨IDC部署,只能容忍單臺服務器故障,無法容忍單個IDC故障。
強同步性能
數據庫的性能分為兩個方面:
- 單個事務的延時:由于多了一次同步操作,單個事務提交的延時加長了。設計系統時能夠做的事情是將同步兩個備庫和主庫寫磁盤這三個操作完全并行起來,使得增加的額外延時只是三個操作的最大值,而不是三個操作之和。
- 系統的吞吐量:本質上看,強同步是否影響吞吐量取決于主備之間的網絡帶寬是否成為瓶頸。在采用萬兆網卡或者兩塊千兆網卡的情況下,吞吐量基本沒有影響。
理想的系統應該是一個全異步的系統,避免強同步占用線程/進程等執行資源,且不應該帶來額外的上下文切換。日志同步的優化有一些關鍵點,例如:組提 交(Group Commit),減少日志緩沖區的鎖沖突,異步化,避免不必要的上下文切換,數據庫提前解行鎖避免熱點。具體可以參考論文:<<Aether:A Scalable Approach to Logging>>。 我參與實現的OceanBase系統強同步對單個事務帶來的額外延時只是一次網絡同步,同一個機房內在0.5ms左右,同城的多個機房之間只有1ms左 右,對系統吞吐量的影響也只有5% ~ 10%左右。也就是說,如果實現做到極致,強同步的性能不會是問題。當然,這就要求將持續可用看成數據庫架構的核心目標,針對這個需求重構數據庫的執行引 擎。
與性能相關聯的一個問題是成本。前面已經提到,基于Paxos的持續可用方案至少需要一主兩備,如果數據總是有三份,確實比較浪費。一個做到極致的系統應該能夠只需要兩個副本,第三個副本只存儲redo日志即可。
引入選舉的難點
假設在關系數據庫的基礎上引入全局Paxos服務,是否能夠解決高可用問題呢?理論上確實是可以的,不過實施起來難度也不小。這是因為,即使是 Zookeeper這樣成熟的選舉服務,使用過程中總是會遇到各種各樣的問題,如果期望應用到核心業務,需要對Zookeeper系統完全的掌控力。也就 是說,假設Zookeeper這樣的服務出現問題,需要能夠Fix Bug,而不是簡單重啟解決。另外,也需要做一套模擬各種異常的測試系統,確保不會在異常的情況下出現一些嚴重的問題,例如Zookeeper選出雙主導 致數據不一致。總而言之,做一個持續可用的選舉服務并不是簡單地使用開源軟件,這是一個全局服務,要么不做,要么就深入下去做到完全掌控。
跨機房問題
跨機房問題分為兩類:同城以及異地。前面已經提到,無論如何實現,強同步方案中單個事務至少增加一次網絡同步延時。對于同城場景,如果網絡環境比較 好,例如公司的數據庫服務有專用的光纖或者帶寬比較高,那么,增加的延時在1~2ms(光折射傳播的時間 + 交換機處理時間),業務是完全可以接受的。因此,可以做到同城持續可用,單個IDC故障時,能夠在保證強一致的前提下很快恢復服務。
對于異地場景,由于網絡延時較大,例如100ms左右,業務往往不可接受。因此,無法做到跨地域持續可用,整個地區故障時,要么犧牲一致性,要么犧 牲可用性,如果選擇可用性時可能會丟失最后幾秒內的數據。當然,實際上業務上往往會組合使用各種柔性解決方案,例如涉及到錢的業務停服務,其它業務容忍極 端情況下的數據丟失;或者在外部系統中記錄一些信息,例如記錄哪些用戶的數據不一致,出現問題是禁止這些用戶的寫服務,其它用戶正常提供服務;或者DBA 采用各種辦法補數據,等等。
小結
總而言之,在金融數據庫中,由于強一致性是必選項,因此,要做到持續可用比較困難,但也并不是不可能,CAP和持續可用并不矛盾。成熟的商業數據庫 都是基于共享存儲的,不過基于Paxos的持續可用方案開始越來越多地應用到核心場景,例如Google Spanner,Microsoft SQL Server云版本,Amazon DynamoDB,而Aliababa OceanBase也在金融核心場景得到了驗證。同時,筆者認為,采用Paxos協議,雖然工程難度很高,但是,只要在實現上做到極致,在同城的情況下, 可以容忍單個IDC故障,且性能損耗非常小;而在異地的場景,考慮到光速不可突破,往往由業務在一致性和可用性之間權衡。越來越多的云數據庫將會采用 Paxos來實現持續可用。
來自:http://www.nosqlnotes.net/archives/333