我們知道的HDFS、Gluster、Ceph、Swift等互聯(lián)網常用的大規(guī)模集群文件系統(tǒng)無一例外都屬于分布式集群文件系統(tǒng)。分布式集群文件系統(tǒng)可擴展性更強,目前已知最大可擴展至10K節(jié)點。對于分布式集群,其對文件元數(shù)據(jù)的管理方式又可以分為single path image和single filesystem image兩種方式。
異常分類
分布式存儲系統(tǒng)所關注的異常類型和單體系統(tǒng)不一樣,有如下幾種:
服務器宕機:設計存儲系統(tǒng)時需要考慮如何通過讀取持久化介質(如機械硬盤,固態(tài)硬盤)中的數(shù)據(jù)來恢復內存信息。
網絡異常:設計容錯系統(tǒng)的一個基本原則是:網絡永遠是不可靠的,任何一個消息只有收到對方的回復后才可以認為發(fā)送成功,系統(tǒng)設計時總是假設網絡將會出現(xiàn)異常并采取相應的處理措施。
磁盤故障:對于磁盤數(shù)據(jù)錯誤,往往可以采用校驗和( checksum)機制來解決。
除了異常之外,還存在“超時”狀態(tài),RPC執(zhí)行的結果有三種狀態(tài):“成功”、“失敗”、“超時”(未知狀態(tài)),也稱為分布式存儲系統(tǒng)的三態(tài)。
一致性保證
副本是分布式存儲系統(tǒng)容錯技術的唯一手段。由于多個副本的存在,如何保證副本之間的一致性是整個分布式系統(tǒng)的理論核心。從客戶端的角度來看,一致性包含如下三種情況:
1、強一致性:
2、弱一致性:
3、最終一致性:最終一致性是弱一致性的一種特例?!白罱K”一致性有一個“不一致窗口”(時間延遲),最終一致性描述比較粗略,其常見的變體如下:
會話( Session)-致性
單調讀( Monotonic read)-致性
單調寫( Monotonic write)-致性
從存儲系統(tǒng)的角度看,一致性主要包含如下幾個方面:
1) 副本一致性:存儲系統(tǒng)的多個副本之間的數(shù)據(jù)是否一致,不一致的時間窗口等;
2) 更新順序一致性:存儲系統(tǒng)的多個副本之間是否按照相同的順序執(zhí)行更新操作。
衡量指標
評價分布式存儲系統(tǒng)有一些常用的指標:
性能:吞吐能力(QPS、TPS)、響應延遲。
可用性:系統(tǒng)的可用性可以用系統(tǒng)停服務的時間與正常服務的時間的比例來衡量。
一致性:越是強的一致性模型,用戶使用起來越簡單。如果系統(tǒng)部署在同一個數(shù)據(jù)中心,只要系統(tǒng)設計合理,在保證強一致性的前提下,不會對性能和可用性造成太大的影響。
可擴展性:系統(tǒng)的可擴展性( scalability)指分布式存儲系統(tǒng)通過擴展集群服務器規(guī)模來提高系統(tǒng)存儲容量、計算量和性能的能力。
性能分析
一般來說,對分布式系統(tǒng)的性能分析的結果是不精確的,然而,至少可以保證,估算的結果與實際值不會相差一個數(shù)量級。舉個例子,Google的BigTable中隨機寫和順序寫的性能是差不多的,寫入操作需要首先將操作日志寫入到GFS,接著修改本地內存。為了提高性能,BigTable實現(xiàn)了成組提示技術。
只有理解存儲系統(tǒng)的底層設計和實現(xiàn),并在實踐中不斷地練習,性能估算才會越來越準。
數(shù)據(jù)分布
1、哈希分布(代表:Dynomo):如果哈希函數(shù)的散列特性很好,哈希方式可以將數(shù)據(jù)比較均勻地分布到集群中去。然而,找出一個散列特性很好的哈希函數(shù)是很難的。這是因為,如果按照主鍵散列,那么同一個用戶id下的數(shù)據(jù)可能被分散到多臺服務器,這會使得一次操作同一個用戶id下的多條記錄變得困難;如果按照用戶id散列,容易出現(xiàn)“數(shù)據(jù)傾斜”(data skew)問題,即某些大用戶的數(shù)據(jù)量很大,無論集群的規(guī)模有多大,這些用戶始終由一臺服務器處理。另一種思路就是采用一致性哈希( Distributed Hash Table,DHT)算法(順時針查找)。一致性哈希的優(yōu)點在于節(jié)點加入/刪除時只會影響到在哈希環(huán)中相鄰的節(jié)點,而對其他節(jié)點沒影響。一致性哈希算法在很大程度上避免了數(shù)據(jù)遷移。Dynamo系統(tǒng)通過犧牲空間換時間,在每臺服務器維護整個集群中所有服務器的位置信息,將查找服務器的時間復雜度降為O(l)。一致性哈希還需要考慮負載均衡,比較好的做法是引入“虛擬節(jié)點”的概念。
2、順序分布(代表:BigTable):哈希散列破壞了數(shù)據(jù)的有序性,只支持隨機讀取操作,不能夠支持順序掃描。順序分布在分布式表格系統(tǒng)中比較常見,一般的做法是將大表順序劃分為連續(xù)的范圍,每個范圍稱為一個子表。Bigtable將一張大表根據(jù)主鍵切分為有序的范圍,每個有序范圍是一個子表。為了支持更大的集群規(guī)模,Bigtable這樣的系統(tǒng)將索引分為兩級:根表以及元數(shù)據(jù)表(Meta表),由Meta表維護User表的位置信息。順序分布與B+樹數(shù)據(jù)結構比較類似,每個子表相當于葉子節(jié)點,隨著數(shù)據(jù)的插入和刪除,某些子表可能變得很大,某些變得很小,數(shù)據(jù)分布不均勻。如果采用順序分布,系統(tǒng)設計時需要考慮子表的分裂與合并。子表合并的目的是為了防止系統(tǒng)中出現(xiàn)過多太小的子表,減少系統(tǒng)中的元數(shù)據(jù)。
3、負載均衡:工作節(jié)點通過心跳包(Heartbeat,定時發(fā)送)將節(jié)點負載相關的信息,如CPU,內存,磁盤,網絡等資源使用率,讀寫次數(shù)及讀寫數(shù)據(jù)量等發(fā)送給主控節(jié)點。負載均衡操作需要控制節(jié)奏,負載均衡操作需要做到比較平滑,一般來說,從新機器加入,到集群負載達到比較均衡的狀態(tài)需要較長一段時間,比如30分鐘到一個小時。
復制
復制協(xié)議分為兩種:強同步復制和異步復制,如圖1。
圖1 主備復制協(xié)議示范
強同步復制和異步復制都是將主副本的數(shù)據(jù)以某種形式發(fā)送到其他副本,這種復制協(xié)議稱為基于主副本的復制協(xié)議( Primary-based protocol)。這種方法要求在任何時刻只能有一個副本為主副本,由它來確定寫操作之間的順序。如果主副本出現(xiàn)故障,需要選舉一個備副本成為新的主副本,這步操作稱為選舉,經典的選舉協(xié)議為Paxos協(xié)議。
主備副本之間的復制一般通過操作日志來實現(xiàn)。操作日志的原理很簡單:為了利用好磁盤的順序讀寫特性,將客戶端的寫操作先順序寫入到磁盤中,然后應用到內存中,由于內存是隨機讀寫設備,可以很容易通過各種數(shù)據(jù)結構,比如B+樹將數(shù)據(jù)有效地組織起來。當服務器宕機重啟時,只需要回放操作日志就可以恢復內存狀態(tài)。為了提高系統(tǒng)的并發(fā)能力,系統(tǒng)會積攢一定的操作日志再批量寫入到磁盤中,這種技術一般稱為成組提交。
如果每次服務器出現(xiàn)故障都需要回放所有的操作日志,效率是無法忍受的,檢查點( CheckPoint)正是為了解決這個問題。系統(tǒng)定期將內存狀態(tài)以檢查點文件的形式dump到磁盤中,并記錄檢查點時刻對應的操作日志回放點。檢查點文件成功創(chuàng)建后,回放點之前的日志可以被垃圾回收,以后如果服務器出現(xiàn)故障,只需要回放檢查點之后的操作日志。(內存中只有“檢查點”之后的數(shù)據(jù))
分布式存儲系統(tǒng)要求能夠自動容錯,也就是說,CAP理論中的“分區(qū)可容忍性”總是需要滿足的,因此,一致性和寫操作的可用性不能同時滿足。例如,Oracle教據(jù)庫的DataGuard復制組件包含三種模式:
最大保護模式( Maximum Protection):即強同步復制模式,寫操作要求主庫先將操作日志(數(shù)據(jù)庫的redo/undo日志)同步到至少一個備庫才可以返回客戶端成功。
最大性能模式( Maximum Performance):即異步復制模式,寫操作只需要在主庫上執(zhí)行成功就可以返回客戶端成功。
最大可用性模式( Maximum Availability):上述兩種模式的折衷。
容錯
常見故障中,單機故障和磁盤故障發(fā)生概率最高。在分布式系統(tǒng)中,可以通過租約(Lease)機制進行故障檢測。
租約機制就是帶有超時時間的一種授權。假設機器A需要檢測機器B是否發(fā)生故障,機器A可以給機器B發(fā)放租約,機器B持有的租約在有效期內才允許提供服務,否則主動停止服務。需要注意的是,實現(xiàn)租約機制時需要考慮一個提前量。
故障恢復中,總控節(jié)點一般需要等待一段時間,比如1個小時,如果之前下線的節(jié)點重新上線,可以認為是臨時性故障,否則,認為是永久性故障。停服務時間包含兩個部分,故障檢測時間以及故障恢復時間。故障檢測時間一般在幾秒到十幾秒,和集群規(guī)模密切相關,集群規(guī)模越大,故障檢測對總控節(jié)點造成的壓力就越大,故障檢測時間就越長。
圖2 故障恢復
可擴展性
分布式存儲系統(tǒng)大多都帶有總控節(jié)點,基于這點,很多人會自然地認為總控節(jié)點存在瓶頸問題,認為去中心化的P2P架構更有優(yōu)勢。然而,事實卻并非如此,主流的分布式存儲系統(tǒng)大多帶有總控節(jié)點,且能夠支持成千上萬臺的集群規(guī)模。可擴展性應該綜合考慮節(jié)點故障后的恢復時間,擴容的自動化程度,擴容的靈活性等。
分布式存儲系統(tǒng)中往往有一個總控節(jié)點用于維護數(shù)據(jù)分布信息,執(zhí)行工作機管理,數(shù)據(jù)定位,故障檢測和恢復,負載均衡等全局調度工作。通過引入總控節(jié)點,可以使得系統(tǒng)的設計更加簡單,并且更加容易做到強一致性,對用戶友好。那么,總控節(jié)點是否會成為性能瓶頸呢?如果總控節(jié)點成為瓶頸,例如需要支持超過一萬臺的集群規(guī)模,或者需要支持海量的小文件,那么,可以采用兩級結構,如圖3所示。
圖3 兩級元數(shù)據(jù)結構
在數(shù)據(jù)庫的擴容中,如果系統(tǒng)的讀取能力不足,可以通過增加副本的方式解決,如果系統(tǒng)的寫入能力不足,可以根據(jù)業(yè)務的特點重新拆分數(shù)據(jù),常見的做法為雙倍擴容,即將每個分片的數(shù)據(jù)拆分為兩個分片,擴容的過程中需要遷移一半的數(shù)據(jù)到新加入的存儲節(jié)點。傳統(tǒng)的數(shù)據(jù)庫架構在可擴展性上面臨如下問題:
1. 擴容不夠靈活。
2. 擴容不夠自動化。
3. 增加副本時間長。
同一個組內的節(jié)點服務相同的數(shù)據(jù),這樣的系統(tǒng)稱為同構系統(tǒng)。同構系統(tǒng)的問題在于增加副本需要遷移的數(shù)據(jù)量太大,由于拷貝數(shù)據(jù)的過程中存儲節(jié)點再次發(fā)生故障的概率很高,所以這樣的架構很難做到自動化,不適用大規(guī)模分布式存儲系統(tǒng)。而異構系統(tǒng)將數(shù)據(jù)劃分為很多大小接近的分片,每個分片的多個副本可以分布到集群中的任何一個存儲節(jié)點。由于整個集群都參與到節(jié)點的故障恢復過程,故障恢復時間很短,而且集群規(guī)模越大,優(yōu)勢就會越明顯。
圖4 同構系統(tǒng)和異構系統(tǒng)的區(qū)別
分布式協(xié)議
在計算機世界里,為了解決一件事情,另外的問題就會接踵而至,從另一個層面印證了IT架構永遠是一種平衡的藝術。
“BASE”其核心思想是根據(jù)業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性(Eventual consistency);在互聯(lián)網領域,通常需要犧牲強一致性來換取系統(tǒng)的高可用性,只需要保證數(shù)據(jù)的“最終一致”,只是這個最終時間需要在用戶可以接受的范圍內;但在金融相關的交易領域,仍然需要采用強一致性的方式來保障交易的準確性與可靠性。
業(yè)界常見的事務處理模式很多,包括兩階段提交、三階段提交、Sagas長事務、補償模式、可靠事件模式(本地事件表、外部事件表)、可靠事件模式(非事務消息、事務消息)、TCC、Paxos及其相關變種等等。不同的事務模型支持不同的數(shù)據(jù)一致性,這里我們不對每種協(xié)議都展開詳細討論,在分布式存儲方面,用的最多的是兩階段提交協(xié)議及Paxos協(xié)議,以下重點介紹這兩種協(xié)議。
1、兩階段提交協(xié)議( Two-phase Commit,2PC):經常用來實現(xiàn)分布式事務,在兩階段協(xié)議中,系統(tǒng)一般包含兩類節(jié)點:一類為協(xié)調者( coordinator),通常一個系統(tǒng)中只有一個;另一類為事務參與者(participants,cohorts或workers),一般包含多個。
協(xié)議中假設每個節(jié)點都會記錄操作日志并持久化到非易失性存儲介質,即使節(jié)點發(fā)生故障日志也不會丟失。在提交階段,協(xié)調者將基于第一個階段的投票結果進行決策:提交或者取消。并通過引入事務的超時機制防止資源一直不能釋放的情況。
兩階段提交協(xié)議可能面臨兩種故障:
事務參與者發(fā)生故障。給每個事務設置一個超時時間,如果某個事務參與者一直不響應,到達超時時間后整個事務失敗。
協(xié)調者發(fā)生故障。協(xié)調者需要將事務相關信息記錄到操作日志并同步到備用協(xié)調者,假如協(xié)調者發(fā)生故障,備用協(xié)調者可以接替它完成后續(xù)的工作。如果沒有備用協(xié)調者,協(xié)調者又發(fā)生了永久性故障,事務參與者將無法完成事務而一直等待下去。
總而言之,兩階段提交協(xié)議是阻塞協(xié)議。
2、Paxos協(xié)議:用于解決多個節(jié)點之間的一致性問題。只要保證了多個節(jié)點之間操作日志的一致性,就能夠在這些節(jié)點上構建高可用的全局服務,例如分布式鎖服務,全局命名和配置服務等。為了實現(xiàn)高可用性,主節(jié)點往往將數(shù)據(jù)以操作日志的形式同步到備節(jié)點。如果主節(jié)點發(fā)生故障,備節(jié)點會提議自己成為主節(jié)點。網絡分區(qū)的時候,可能會存在多個備節(jié)點提議(Proposer,提議者)自己成為主節(jié)點。Paxos協(xié)議保證,即使同時存在多個proposer,也能夠保證所有節(jié)點最終達成一致,即選舉出唯一的主節(jié)點。
(3)Paxos與2PC的區(qū)別:Paxos協(xié)議和2PC協(xié)議在分布式系統(tǒng)中所起的作用并不相同。Paxos協(xié)議用于保證同一個數(shù)據(jù)分片的多個副本之間的數(shù)據(jù)一致性。當這些副本分布到不同的數(shù)據(jù)中心時,這個需求尤其強烈。2PC協(xié)議用于保證屬于多個數(shù)據(jù)分片上的操作的原子性。這些數(shù)據(jù)分片可能分布在不同的服務器上,2PC協(xié)議保證多臺眼務器上的操作要么全部成功,要么全部失敗。
Paxos協(xié)議有兩種用法:一種用法是用它來實現(xiàn)全局的鎖服務或者命名和配置服務,例如Google Chubby以及Apache Zookeeper。另外一種用法是用它來將用戶數(shù)據(jù)復制到多個數(shù)據(jù)中心,例如Google Megastore以及Google Spanner。
2PC協(xié)議最大的缺陷在于無法處理協(xié)調者宕機問題。如果協(xié)調者宕機,那么,2PC協(xié)議中的每個參與者可能都不知道事務應該提交還是回滾,整個協(xié)議被阻塞,執(zhí)行過程中申請的資源都無法釋放。因此,常見的做法是將2PC和Paxos協(xié)議結合起來,通過2PC保證多個數(shù)據(jù)分片上的操作的原子性,通過Paxos協(xié)議實現(xiàn)同一個數(shù)據(jù)分片的多個副本之間的一致性。另外,通過Paxos協(xié)議解決2PC協(xié)議中協(xié)調者宕機問題。當2PC協(xié)議中的協(xié)調者出現(xiàn)故障時,通過Paxos協(xié)議選舉出新的協(xié)調者繼續(xù)提供服務。
跨機房部署
機房之間的數(shù)據(jù)同步方式可能為強同步或者異步。如果采用異步模式,那么,備機房的數(shù)據(jù)總是落后于主機房;如果采用強同步模式,那么,備機房的數(shù)據(jù)和主機房保持一致。當主機房出現(xiàn)故障時,除了手工切換,還可以采用自動切換的方式,即通過分布式鎖服務檢測主機房的服務,當主機房出現(xiàn)故障時,自動將備機房切換為主機房。
評論