分布式系統工程實現:GFS&Bigtable設計的優勢
目前,知名度比較高的通用存儲系統包括:Google GFS&Bigtable,Amazon Dynamo,Microsoft Azure存儲系統及Yahoo PNUTS。其中,GFS&Bigtable,Azure存儲系統及Yahoo PNUTS都有總控節點,Amazon Dynamo采用去中心化的P2P設計。
Amazon Dynamo看起來很優美,比如Dynamo論文中提到的技術比較酷,Dynamo沒有中心節點,可以支持更大的系統規模。然而,Dynamo不是我心目中的理想架構,因為Dynamo有一致性的問題,系統設計復雜但解決的問題有限。如果需要保證一致性,就必須要求同一時刻對同一份數據只有一個更新節點,Dynamo顯然不符合要求,可能出現數據丟失等不一致的情況。雖然對于很多場景能夠通過沖突合并來解決,另外,Dynamo由于采用一致性Hash的方法進行數據分布,數據不是連續存儲的,不能支持高效的掃描操作,所以數據模型只能是簡單的<Key, Value>模型,不能支持類似數據倉庫這種需要掃描某個用戶且單個用戶數據量可能特別大的應用場景。總之,去中心化的系統一般有兩個問題:1,一致性問題;2,順序掃描效率低下。
Microsoft Azure和普通NOSQL系統設計差別挺大的。普通的NOSQL系統一般是從業務出發,支持某一類業務必要的特性,而Microsoft Azure針對的主要用戶為企業級用戶,設計從SQL全集出發,盡量支持能夠支持的SQL特性。和Yahoo PNUTS一樣,Microsoft Azure采用單層設計,不同的是,Yahoo PNUTS通過將操作日志寫入到可靠的消息中間件來簡化系統其它部分的設計,Microsoft Azure將操作日志Replication功能做為子表服務節點的一個模塊(用戶使用的Azure數據庫實例相當于一個子表),保證操作日志至少同步到兩臺機器才返回給客戶端。拋開Microsoft Azure由于兼顧過多的SQL特性導致的工程復雜度及性能損耗,Microsoft Azure架構的一個問題是:由于每個子表的操作日志分開,多個子表之間的操作日志無法聚合,所以,單機支持的子表個數有限,比如Microsoft Azure限制單機的Azure數據庫實例最多為650個。如果單個子表太大,負載平衡效果必然不夠好;如果單個子表較小,比如常見的256MB一個子表,單機服務的數據有限。Microsoft Azure的設計可參考論文。
Yahoo PNUTS采用消息中間件Yahoo Message Broker來進行操作日志的可靠存儲。雖然多個子表將操作日志寫入到不同的Queue,不過在消息中間件中,每個Message Broker可以服務很多的Queue,多個子表寫入的操作日志仍然可以因為寫入一臺機器而進行聚合。Yahoo PNUTS的主要問題是消息中間件本身的擴展性,由于消息中間件為了避免復雜性設計成一個同構的系統,消息中間件本身存儲的數據量不能太大。線下的計算,比如MapReduce批處理,計算過程中更新量很大,消息中間件不能勝任。(同構系統的問題參考系統可擴展性文章)
GFS和Bigtable兩層的設計是一個幾乎完美的組合。GFS本質上是一個弱一致性系統,可能出現重復記錄、記錄亂序等各種問題(后續有文章專門分析原因),Bigtable是GFS之上的一個索引層,為了服務百PB級別的應用,采用兩級的B+樹索引結構。GFS保證成功的記錄至少寫入一次并由Bigtable記錄索引,由于Bigtable是一個強一致性系統,整個系統對外表現為強一致性系統。為了保證Bigtable的強一致性,同一時刻同一份數據只能被一臺機器服務,且Bigtable論文中的Tablet Server對每個Tablet是沒有備份的。當Tablet Server宕機時,由于只需要排序很少的操作日志并且加載服務的Tablet的索引,宕機恢復可以做到一分鐘以內。Bigtable分裂和遷移到只需要修改或者加載索引數據,因此效率很高,整個系統的擴展性很好。GFS&Bigtable架構廣受質疑之處主要體現在兩個方面:
1. GFS&Bigtable架構實時性不好。
2. Bigtable Tablet Server的單點問題。
第一個對Bigtable實時性的質疑,大體有兩個原因:第一點是由于Bigtable的Tablet和GFS的Chunk可能不在一臺機器上,讀取操作可能要走網絡;第二點是由于Bigtable每次隨機讀取都需要讀取一塊數據,比如16K, 32K或者64K。第一點可以通過本地化策略來解決,第二點由于磁盤的尋道時間一般為8~10ms,讀取一整塊的overhead不會太高,且Bigtable系統內部的Block Cache和Key-Value Cache可以解決很多問題。開源的HBase和Hypertable由于缺少大規模應用環境還不夠穩定,實時性確實做得不好,不過這不是架構本身的問題,而是架構的復雜性導致的實現問題。
第二個對Bigtable的質疑,我們可以通過多數據中心的Replication來解決:同一個數據中心內部的Bigtable系統保證強一致性,機房之間通過回放操作日志進行數據同步,保證最終一致性。同一時刻只有一個集群提供寫服務,其它集群提供讀服務。當然,對應用方來說仍然是一整套系統,當某臺Tablet Server宕機時,只影響短時間部分數據的寫服務,讀服務如果不要求強一致性不受影響。
描述CAP理論時我們經常會說,Dynamo是AP的系統,Bigtable是CA的系統。然而,Bigtable的分區可容忍性做得也還不錯:Bigtable在機房斷電,機房之間網絡故障時仍然可以對外提供服務。假設在三個機房部署了三套Bigtable集群,且采用三機房五節點的方式部署了Chubby服務,任何一個機房斷電或者某兩個機房之間網絡故障系統仍然能夠對外服務。多個機房同時故障或者三個機房被分成三個區的情況理論上有可能,工程上可以認為不可能。所以,不要為了滿足CAP理論上的特性而設計系統,業務需求才是本質。
總之,GFS&Bigtable設計在可擴展性,容錯,負載平衡等各方面都有很大的優勢,并且集群越大優勢越明顯,問題是整套系統過于復雜,對工程師,應用環境,管理層忍耐力都是一個考驗。