MPP 分析型數據庫架構變遷


 從架構特點到功能缺陷,重新認識分析型分布式數據庫 (juejin.cn)

 

 

 

 

 

###################################

MPP on HDFS

 

MPP架構

這是MPP架構分布式數據庫的簡單示意圖。MPP數據庫通過將數據切片分布到各個計算節點后並行處理來解決海量數據分析的難題。每個MPP數據庫集群由一個主節點(為了提供高可用性,通常還會有一個從主節點)和多個計算節點組成。主節點和每個計算節點都有自己獨立的CPU,內存和外部存儲。主節點負責接收客戶端的請求,生成查詢計划,並將計划下發到每個計算節點,協調查詢計划的完成,最后匯總查詢結果返回給客戶端。計算節點負責數據的存儲以及查詢計划的執行。計算節點之間是沒有任何共享依賴的(shared nothing)。查詢在每個計算節點上面並行執行,大大提升了查詢的效率。

我們接下來要講的開源分布式數據庫Greenplum Database就是基於PostgreSQL的MPP數據庫。對應到這個架構圖,每個節點上面的數據庫實例可以簡單的認為是一個PostgreSQL實例。

並行查詢計划

我們首先通過一條簡單的查詢,感性地認識一下Greenplum Database是如何執行一條查詢的。

下略

。。。

。。。

 

 

 

高可用

介紹完Greenplum Database的查詢組件和系統狀態組件后,我們再看看它是如何提供高可用性的。首先是管理節點的高可用。我們采取的方式是,啟動一個稱為Standby的從主節點作為主節點的備份,通過同步進程同步主節點和Standby節點兩者的事務日志,在Standby節點上重做系統表的更新操作,從而實現兩者在全局系統表上面的信息同步。當主節點出故障的時候,我們能夠切換到Standby節點,系統繼續正常工作,從而實現管理節點的高可用。

計算節點高可用性的實現類似於管理節點,但是細節上有些小不同。每個Segment實例都會有另外一個Segment實例作為備份。處於正常工作狀態的Segment實例我們稱為Primary,它的備份稱為Mirror。不同於管理節點日志重放方式,計算節點的高可用是通過文件復制來實現的。對於每一個Segment實例,它的狀態以文件的形式保存在本地存儲介質中。這些本地狀態可以分成三大類:本地系統表、本地事務日志和本地表分區數據。通過以文件復制的方式保證Primary和Mirror之間的狀態一致,我們能夠實現計算節點的高可用。

GoH

Hadoop出現之前,MPP數據庫是為數不多的大數據處理技術之一。隨着Hadoop的興起,特別是HDFS的成熟,越來越多的數據被保存在HDFS上面。一個自然的問題出現了:我們怎樣才能高效地分析保存在HDFS上面的數據,挖掘其中的價值。4,5年前,SQL-on-Hadoop遠沒有現在這么火,市場上的解決方案也只有耶魯大學團隊做的Hadapt和Facebook做的Hive,像Impala,Drill,Presto,SparkSQL等都是后來才出現的。而Hadapt和Hive兩個產品,在當時無論是易用性還是查詢性能方面都差強人意。

我們當時的想法是將Greenplum Database跟HDFS結合起來。與其它基於connector連接器的方式不同,我們希望讓HDFS,而不是本地存儲,成為MPP數據庫的數據持久層。這就是后來的Apache HAWQ項目。但在當時,我們把它叫做Greenplum on Hadoop,其實更准確的說法應該是,Greenplum on HDFS。當時的想法非常簡單,就是將Greenplum Database和HDFS部署在同一個物理機器集群中,同時將Greenplum Database中的Append-only表的數據放到HDFS上面。Append-only表指的是只能追加,不能更新和刪除的表。這是由於HDFS本身只能Append的屬性決定的。

除了Append-only表之外,Greenplum Database還支持Heap表,這是一類能夠支持增刪改查的表。結合前面提到的Segment實例的本地狀態,我們可以將本地存儲分成四大類:系統表、日志、Append-only表分區數據和非Append-only表分區數據。我們將其中的Append-only表分區數據放到了HDFS上面。每個Segment實例對應一個HDFS的目錄,非常直觀。其它三類數據還是保存在本地的磁盤中。

總體上說,相比於傳統的Greenplum Database, Greenplum on HDFS架構上並沒有太多的改動,只是將一部分數據從本地存儲放到了HDFS上面,但是每個Segment實例還是需要通過本地存儲保存本地狀態數據。所以,從高可用性的角度看,我們還是需要為每個實例提供備份,只是需要備份的數據少了,因為Append-only表數據的高可用性現在是由HDFS數據的高可用性來保證。

Greenplum on HDFS作為一個原型系統,驗證了MPP數據庫和HDFS是可以很好地整合起來工作的。基於這個原型系統,我們開始將它當成一個真正的產品來打造,也就是后來的HAWQ。

從Greenplum on HDFS到HAWQ,我們主要針對本地存儲做了系統架構上的調整。我們希望將計算節點的本地狀態徹底去掉。本地狀態除了前面提到的系統表(系統表又可以細分成只讀系統表(系統完成初始化后不會再發生更改的元數據,主要是數據庫內置的數據類型和函數)和可寫系統表(主要是通過DDL語句對元數據的修改,如創建新的數據庫和表))、事務日志、Append-only表分區數據和非Append-only表分區數據,同時還有系統在查詢執行過程中產生的臨時數據,如外部排序時用到的臨時文件。其中臨時數據和本地只讀系統表的數據都是不需要持久化的。我們需要考慮的是如何在Segment節點上面移除另外四類狀態數據。

Append-only表分區數據前面已經提到過,交給HDFS處理。為了提高訪問HDFS的效率,我們沒有采用Hadoop官方提供的HDFS訪問接口,而是用C++實現了原生的HDFS訪問庫,libhdfs3。針對非Append-only表數據的問題,我們的解決方案就比較簡單粗暴了:通過修改DDL,我們徹底禁止用戶創建Heap表,因為Heap表支持更新和刪除。所以,從那時起到現在最新的Apache HAWQ,都只支持表數據的追加,不支持更新和刪除。沒有了表數據的更新和刪除,分布式事務就變得非常簡單。通過為每個Append-only表文件對應的元數據增加一列,邏輯EoF,即有效的文件結尾,只要能夠保證EoF的正確性,我們就能夠保證事務的正確性。而且Append-only表文件的邏輯EoF信息是保存在主節點的全局系統表中的,它的正確性通過主節點的本地事務保證。為了清理Append-only表文件在追加新數據時事務abort造成的臟數據,我們實現了HDFS Truncate功能。

對於本地可寫系統表,我們的做法是將Segment實例上面的本地可寫系統表放到主節點的全局系統表中。這樣主節點就擁有了全局唯一的一份系統表數據。查詢執行過程中需要用到的系統元數據,我們通過Metadata Dispatch的方式和查詢計划一起分發給每個Segment實例。

無狀態Segment

通過上述的一系列策略,我們徹底擺脫了Segment節點的本地狀態,也就是實現了無狀態Segment。整個系統的高可用性策略就簡單很多,而且也不再需要為Segment節點提供Mirror,系統的利用率大大提升。

數據的高可用交給了HDFS來保證。當一個Segment節點出故障后,我們可以在任意一台有空閑資源的機器上重新創始化一個新的Segment節點,加入到集群中替代原來出故障的節點,整個集群就能夠恢復正常工作。

我們也做到了計算和存儲物理上的解耦合,往徹底擺脫傳統MPP數據庫(例如Greenplum Database)計算和存儲緊耦合的目標邁出了有着實質意義的一步。

邏輯集成

雖然在HAWQ 1.x的階段,我們做到了計算和存儲物理上的分離,但是邏輯上兩者還是集成的。原因是,在將本地表分區數據往HDFS上面遷移的時候,為了不改變原來Segment實例的執行邏輯流程,我們為每個Segment指定了一個其專有的HDFS目錄,以便跟原來本地數據目錄一一對應。每個Segment負責存儲和管理的數據都放在其對應的目錄的底下,而且該目錄底下的文件,也只有它自身能夠訪問。這種HDFS數據跟計算節點邏輯上的集成關系,使得HAWQ 1.x版本依然沒有擺脫傳統MPP數據庫剛性的並發執行策略:無論查詢的復雜度如何,所有計算節點都需要參與每條查詢的執行。這意味着,系統執行一條單行插入語句所使用的計算資源,和執行一條對幾TB數據進行復雜多表連接和聚合的語句所使用的資源是一樣的。這種剛性的並行執行策略,極大地約束了系統的擴展性和吞吐量,同時也與Hadoop基於查詢復雜度來調度計算資源的彈性策略相違背。

邏輯分離

我們決心對HAWQ的系統架構做一次大的調整,使其更加地Hadoop Native,Hadoop原生,而不僅僅是簡單地將數據放到HDFS上面。當時,我們內部稱這個新版本為HAWQ 2.0,也就是大家現在在github上面看到的Apache HAWQ。

其中最重要的一步是,我們希望計算和存儲不僅物理上分離,邏輯上也是分離。數據庫中的用戶表數據在HDFS上不再按照每個Segment單獨來組織,而是按照全局的數據庫對象來組織。舉個例子,我們將一張用戶表對應的多個數據文件(因為往該表插入數據的時候,為了提高數據插入的效率,系統會啟動了多個QE進程同時往HDFS寫數據,每個QE寫一個單獨文件)放到同一個目錄底下,而不是像原來那樣,每個QE進程將文件寫到自己對應的Segment目錄底下。這種改變帶來的一個直觀結果就是,由於所有的數據文件都放在一起,查詢執行的時候,根據需要掃描的數據量不同,我們既可以使用一個Segment實例去完成表掃描操作,也可以使用多個Segment實例去做,徹底擺脫了原來只能使用固定數量個Segment實例來執行查詢的剛性並行執行策略。

當然,HDFS數據目錄組織的改變只是實現HAWQ 2.0彈性執行引擎的一步,但卻是最重要的一步。計算和存儲的徹底分離,使得HAWQ可以像MapReduce一樣根據查詢的復雜度靈活地調度計算資源,極大地提升了系統的擴展性和吞吐量。

資源調度

我們簡單比較一下HAWQ 1.x和HAWQ 2.0的資源調度。

左邊展現的是HAWQ 1.x在同時處理三個查詢(分別來自三個不同的會話)時的資源調度情況。和傳統MPP數據庫一樣,無論查詢的復雜度如何,每個Segment實例都會參與每條查詢的執行。換句話說,每個Segment實例都會啟動一個QE進程處理分配給它的任務。在這種情況下,系統能夠支持的並發查詢數量,跟集群的計算節點數沒有任何關系,完全由一個計算節點上面的資源量決定(這里,我們先不考慮主節點成為瓶頸的問題)。一個4個節點的HAWQ集群能夠支持的並發查詢數量和一個400個節點的集群是一樣的。

右邊展現的是HAWQ 2.0在同樣並發查詢下的資源調度情況。和Hadoop的MapReduce一樣,我們能夠根據查詢的復雜度決定需要調度多少計算資源參與查詢的執行。為了方便闡述,這里假設每條查詢只需要兩個計算資源單元。而且,執行單元可以根據資源管理器的調度算法分配到不同的物理計算節點上面。這兩點靈活性:計算資源的數量可變和計算資源的位置可變,正是HAWQ 2.0彈性執行引擎的核心。在這種情況下,系統能夠支持的並發查詢數量,跟集群的計算節點數量呈線性關系:計算節點越多,系統能夠支持的並發查詢數量越多(再次提醒,這里,我們先不考慮主節點成為瓶頸的問題)。

所以,可以說,HAWQ 2.0成功解決了傳統MPP數據倉庫中計算節點首先成為吞吐量瓶頸的問題。同時,由於並不是所有計算節點都需要參與到每條查詢的執行中,HAWQ 2.0同時也解決了傳統MPP數據庫由於單個計算節點性能下降直接影響整個集群性能的問題(這導致MPP集群不能包含太多的計算節點,因為根據概率,集群節點到達一定值后,出現單個計算節點性能下降的概率將會非常高),從而也很大程度上解決了擴展性問題。

雲端數據倉庫

通過將計算和存儲徹底分離成功解決了計算節點成為系統吞吐量瓶頸的問題后,現在系統的唯一瓶頸就剩下主節點。

如前面提到,主節點的功能主要分成兩類:元數據管理,包括系統表存儲和管理、鎖管理和分布式事務等等,和計算資源調度管理和執行。前者我們可以看成是狀態管理,后者是沒有狀態的組件。通過將狀態管理提取出來成為單獨一個功能層,我們讓主節點跟計算節點一樣變得沒有狀態。這樣,我們能夠根據系統並發查詢的變化,動態增加或者減少主節點的數量。這個設計借鑒了Hadoop YARN的設計。YARN的框架通過將原來的JobTracker的功能分成了Resource Manager和Application Manager,從而解決Hadoop集群吞吐量的問題。

這是一個雲端數據倉庫的架構圖。實際上,我們在HashData希望通過雲端數據倉庫解決企業用戶使用數據倉庫時碰到的多種難題,包括商業上的和技術上的。在這里,我們只關注技術上的。

在這個系統架構中,我們將管理即元數據、計算和存儲三者分離,每一層都能單獨動態伸縮,在解決系統吞吐量和擴展性問題的同時,提供了多維度的彈性。

我們利用雲平台的對象存儲服務,如AWS的S3和青雲QingCloud的QingStor,作為系統數據的持久層。除了按需付費的經濟特性外,雲平台的對象存儲服務在可擴展性、穩定性和高可用性等方面遠勝於我們自己維護的分布式文件系統(如HDFS)。雖然對象存儲的訪問延遲遠高於本地磁盤訪問,但是我們可以通過本地緩存的策略很大程度減輕延遲問題。

同樣的,我們利用雲平台提供的虛擬機作為我們的計算資源,也能夠一定程度上實現資源的隔離,從而保證不同的工作負載之間沒有相互影響。

雲平台提供的近乎無限的計算和存儲資源(相對於數據倉庫應用來說),使得雲端數據倉庫能夠存儲和處理的數據達到一個全新的高度。

總結

最后,我們做一個簡單的總結。從PostgreSQL到Greenplum Database,我們通過大規模並行處理(MPP)技術,實現了處理海量數據時的低延遲目標。從Greenplum Database到Apache HAWQ,通過計算和存儲分析的策略,我們提升了系統的並發處理能力和擴展性。從Apache HAWQ到Cloud Data Warehouse,我們借助雲平台近乎無限的計算資源和存儲資源,以及管理、計算和數據三者分離,還有計算資源嚴格隔離,我們能夠取得近乎無限的並發處理能力和擴展性。

MPP數據庫采取的是流水式的執行引擎,中間的每個階段是不帶檢查點的。這意味着,只有有一個參與到查詢執行的QE進程出錯,整條查詢將會失敗,只能從頭開始重新執行這條查詢。而我們知道,當參與到查詢執行的QE進程達到一定數量的時候,QE進程出錯將是必然的,特別是在一個資源共享的環境中。這時候,即使是重新提交查詢重跑,失敗還是必然的。換句話說,我們幾乎無法成功執行需要調度大量計算資源的查詢。

展望未來,我們希望實現帶檢查點的流水式執行引擎,從而使得系統能夠處理任意大的查詢(單個查詢需要同時調度成千上萬的計算資源)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM