詳談數據時代構建高可用數據庫
近幾年,隨著移動互聯網的發展、云計算的普及和各種新業務的出現,數據呈現爆發式增長,給整個業務系統帶來了越來越大的挑戰,特別是對于底層數據存儲系統。完美的高可用系統,是所有公司最理想的追求。如果只從應用層和緩存層看高可用問題,是比較容易解決的。對于應用層來說,根據業務特點可以很方便地設計成無狀態的服務,在大多數互聯網公司中,在業務層的最上層使用動態DNS、LVS、HAProxy等負載均衡組件,配合Docker和Kubernetes實現彈性伸縮,能夠很容易實現應用服務的高可用。對于緩存層來說,也有很多可選的開源方案來幫助解決,比如Codis、Twemproxy、Redis Cluster等等,如果對緩存數據的一致性和實時性要求不高,這些方案就可以很好解決緩存層面的問題。但對存儲層來說,支持高可用非常困難。
在互聯網架構中,最底層的核心數據存儲一般都會選擇關系型數據庫,最流行的當屬MySQL。大數據時代,大家漸漸發現傳統的關系型數據庫開始出現一些瓶頸:單機容量不能支撐快速增長的業務需求;高并發的頻繁訪問經常造成服務的響應超時;主從數據同步帶來的數據不一致問題;大數據場景下查詢性能大幅波動等等。
當前,數據庫方案有了很多不一樣的變化。首先,不同于早期的單機型數據庫,在當下數據呈現爆發式增長,數據總量也從GB級別跨越到了TB甚至PB級別,遠超單機數據庫的存儲上限,所以只能選擇分布式的數據存儲方案。其次,隨著存儲節點的增加,存儲節點出問題的可能性也大大提高,光靠人工完全不現實,所以需要數據庫層面保證自己高效快速地實現故障遷移。另外,隨著存儲節點的增加,運維成本也大大增加,對自動化工具也提出了更高要求。最后,新分布式數據庫的出現,用戶在OLTP數據庫基本需求的基礎上,對大數據分析查詢的業務要求更高,在某種程度上OLTP和OLAP融合的新型數據庫會是未來極具潛力的發展方向之一。
什么是高可用
Wikipedia的解釋中,高可用即High Availability,一般通過SLA(Service Level Agrement)來衡量。這里從CAP角度來看待高可用問題。CAP是分布式系統領域一個非常著名的理論,由Berkerly的Brewer提出。該理論認為任何基于網絡的分布式系統都具有以下三要素:
數據一致性(Consistence):等同于所有節點訪問同一份最新的數據副本;
可用性(Availability):對數據更新具備高可用性;
分區容忍性(Partition tolerance):以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在C和A間做出選擇。
三要素不能同時滿足。但后來很多人將CAP解讀為數據一致性、可用性和分區容忍性最多只能滿足兩個,這種解讀本身存在一定的誤導性,原因就在于忽略了特定條件。假想兩個節點N1和N2,在某些場景下發生了分區(P)問題,即N1和N2分處分區的兩側。這時對于外部的寫操作來說,如果允許任一節點可寫的話就相當于選擇了A,喪失了C。同樣,如果為了滿足C,那么寫入操作就會失敗,A就無法保證,所以存在分區問題時,無法同時保證A和C。雖然分區在局域網中出現的概率相對很低,但卻無法避免,所以系統只能在CP和AP之間做出權衡。
當前有很多的NoSQL數據庫,在CAP之間選擇了AP,比如Amazon Dynamo和Cassandra,追求可用性,適當犧牲一致性,只實現最終一致性。這種選擇允許短時間的數據不一致,并且可以交由用戶自己來處理寫入沖突,但是可以隨時接受用戶的讀寫請求。在這種場景下就需要特別注意數據不一致引起的各種奇怪問題,對于比較嚴肅的業務場景,比如訂單、支付等,對事務和一致性要求比較高,這種AP類型的系統就不適用了。而且該系統放棄了SQL和ACID事務,給開發人員帶來了更多的開發工作和額外的心智負擔,很容易出現問題,所以NoSQL數據庫犧牲一致性來獲取服務的可用性,并沒有徹底解決大數據時代數據庫的高可用問題。
大數據時代,傳統的關系型數據庫必然會由單機擴展到分布式,追求數據一致性,所以必然會是一個CP類型的系統,像這種新型的、下一代的分布式關系型數據庫,既具有傳統單機數據庫的SQL支持和ACID事務保證,又有NoSQL數據庫的Scale特點,稱為NewSQL數據庫,包括Google的Spanner/F1、PingCAP的TiDB等等。但從CAP的角度看,選擇CP并不意味著完全放棄了A,CP系統只是在某些產生分區的場景下不能實現100%的A,但完全可以通過有效的辦法來實現高可用(HA)。由此可見,并不是CP系統就完全放棄了A,只不過在產生分區的場景下無法從理論上保證A,這是一個常見的誤解。
澄清了CAP的問題,下面討論如何打造高可用的數據庫。數據庫是一個非常大的概念,從傳統單機SQL,到NoSQL,再到現在流行的NewSQL,這里面不同的實現方案實在太多,本文聚焦在關系型數據庫,主要探討最流行的MySQL數據庫及其生態。最近幾年,隨著大家在分布式數據庫領域的探索,出現了很多不同類型的解決方案,比如中間件/Proxy的方案,典型的比如TDDL、Cobar、Altlas、DRDS、TDSQL、MyCAT、KingShard、Vitess、PhxSQL等,還有一種新型的NewSQL數據庫,比如Google Spanner/F1、Oceanbase、TiDB等。下面看下業界在打造高可用數據庫方面新的技術進展,以及和傳統方案選型的對比。
消除單點問題
為了實現數據庫層面的高可用,必須要消除單點問題(SPOF)。存在單點服務的情況下,一旦單點服務掛掉,整個服務就不可用。消除單點問題最常用的方案就是復制(Replication),通過數據冗余的方式來實現高可用。
為什么必須要冗余?數據庫本身是有狀態的,不會像無狀態的服務那樣掛掉就可以重啟,而數據庫本身能夠保證數據持久化,所以如果沒有冗余副本,一旦數據庫掛掉,只能等待數據庫重啟,在這段恢復時間服務完全不可用,高可用就無法保證。但如果有了額外的數據副本,高可用就變得可能了,主要能保證在檢測到服務發生問題之后及時做服務切換。
對于MySQL來說,默認復制方式是異步的主從復制方式,雖然這種方案被很多的互聯網公司所采用,但實際上這種方案存在一個致命問題——存在丟失數據的風險。數據傳輸經過網絡,這也就意味著存在傳輸時延,那么對于異步復制來說,主從數據庫的數據本身是最終一致性的,所以主庫一旦出現了問題,切換從庫極有可能會帶來數據不一致的風險。
因為異步復制方式存在更大的問題,很多時候大家都會考慮用半同步復制方式Semi-Sync,這種數據復制方式在默認情況下會使用同步的數據復制方式,不過在數據復制壓力較大的情況下,就會退化成異步的數據復制方式,所以依然會存在高可用問題。當然,也有人會選用完全同步的方式,但是這種復制方式在并發壓力下會有明顯的性能問題,所以也不常用。
那有沒有一種數據復制方式,能同時保證數據的可靠性和性能?答案是有的,那就是最近業界討論較多的分布式一致性算法,典型的是Paxos和Raft。簡單來說,它們是高度自動化、強一致的復制算法。以Raft為例,Raft中基數個節點組成一個Raft Group,在一個Raft Group內,只要滿足大多數節點寫成功,就認為可以寫成功了,比如一個3節點的Raft Group,只要保證Raft Leader和任意一個Raft Follower寫成功就可以了,所以同步寫Leader,異步寫兩個Follower,只要其中一個返回就可以,相比完全的同步方式,性能要好很多。所以從復制層面來看,Raft更像是一個自適應的同步+異步復制方案,同步和異步的最優選擇通過Raft算法來保證。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%