關於OLAP數倉,這大概是史上最全面的總結!(萬字乾貨)

關於數據倉庫,早期分享過不少基礎類文章,偶然間看到知乎上這篇關於OLAP的深度解讀,從技術發展,產品選型,執行優化等方面做了詳細的剖析,分享來給大家看看!

全文10000字,讀完需要30分鐘!

我也覺得有點長,要不先收藏?

 

文 | 溫正湖

源 | 知乎

有哪些類型的OLAP數倉?

按數據量劃分

對一件事物或一個東西基於不同角度,可以進行多種分類方式。對數倉產品也一樣。比如我們可以基於數據量來選擇不同類型的數量,如下圖所示:

本系列文章主要關注的是數據量處於百萬到百億級別的偏實時的分析型數倉,Cloudera的Impala、Facebook的Presto和Pivotal的GreenPlum均屬於這類系統;如果超過百億級別數據量,那麼一般選擇離線數倉,如使用Hive或Spark等(SparkSQL3.0看起來性能提升很明顯);對於數據量很小的情況,雖然是分析類應用,也可以直接選擇普通的關係型數據庫,比如MySQL等,“殺雞焉用牛刀”。

按建模類型劃分

下面我們主要關注數據量中等的分析型數倉,聚焦OLAP系統。根據維基百科對OLAP的介紹,一般來說OLAP根據建模方式可分爲MOLAP、ROLAP和HOLAP 3種類型,下面分別進行介紹並分析優缺點。

1、MOLAP

這應該算是最傳統的數倉了,1993年Edgar F. Codd提出OLAP概念時,指的就是MOLAP數倉,M即表示多維(Multidimensional)。大多數MOLAP產品均對原始數據進行預計算得到用戶可能需要的所有結果,將其存儲到優化過的多維數組存儲中,可以認爲這就是上一篇所提到的“數據立方體”。

由於所有可能結果均已計算出來並持久化存儲,查詢時無需進行復雜計算,且以數組形式可以進行高效的免索引數據訪問,因此用戶發起的查詢均能夠穩定地快速響應。這些結果集是高度結構化的,可以進行壓縮/編碼來減少存儲佔用空間。

但高性能並不是沒有代價的。首先,MOLAP需要進行預計算,這會花去很多時間。如果每次寫入增量數據後均要進行全量預計算,顯然是低效率的,因此支持僅對增量數據進行迭代計算非常重要。其次,如果業務發生需求變更,需要進行預定模型之外新的查詢操作,現有的MOLAP實例就無能爲力了,只能重新進行建模和預計算。

因此,MOLAP適合業務需求比較固定,數據量較大的場景。在開源軟件中,由eBay開發並貢獻給Apache基金會的Kylin即屬於這類OLAP引擎,支持在百億規模的數據集上進行亞秒級查詢。

其架構圖較直觀得反映了基於cube的預計算模型(build),如下所示:

2、ROLAP

與MOLAP相反,ROLAP無需預計算,直接在構成多維數據模型的事實表和維度表上進行計算。R即表示關係型(Relational)。顯然,這種方式相比MOLAP更具可擴展性,增量數據導入後,無需進行重新計算,用戶有新的查詢需求時只需寫好正確的SQL語句既能完成獲取所需的結果。

但ROLAP的不足也很明顯,尤其是在數據體量巨大的場景下,用戶提交SQL後,獲取查詢結果所需的時間無法準確預知,可能秒回,也可能需要花費數十分鐘甚至數小時。本質上,ROLAP是把MOLAP預計算所需的時間分攤到了用戶的每次查詢上,肯定會影響用戶的查詢體驗。

當然ROLAP的性能是否能夠接受,取決於用戶查詢的SQL類型,數據規模以及用戶對性能的預期。對於相對簡單的SQL,比如TPCH中的Query響應時間較快。但如果是複雜SQL,比如TPC-DS中的數據分析和挖掘類的Query,可能需要數分鐘。

相比MOLAP,ROLAP的使用門檻更低,在完成星型或雪花型模型的構建,創建對應schema的事實表和維度表並導入數據後,用戶只需會寫出符合需求的SQL,就可以得到想要的結果。相比創建“數據立方體”,顯然更加方便。

有分析表明,雖然ROLAP的性能比如MOLAP,但由於其靈活性、擴展性,ROLAP的使用者是MOLAP的數倍。

3、HOLAP

MOLAP和ROLAP各有優缺點,而且是互斥的。如果能夠將兩者的優點進行互補,那麼是個更好的選擇。而HOLAP的出現就是這個目的,H表示混合型(Hybrid),這個想法很樸素直接。對於查詢頻繁而穩定但又耗時的那些SQL,通過預計算來提速;對於較快的查詢、發生次數較少或新的查詢需求,像ROLAP一樣直接通過SQL操作事實表和維度表。

目前似乎沒有開源的OLAP系統屬於這個類型,一些大數據服務公司或互聯網廠商,比如HULU有類似的產品。相信未來HOLAP可能會得到進一步發展,並獲得更大規模的使用。

4、HTAP

從另一個維度看,HTAP也算是一種OLAP類型的系統,是ROLAP的一個擴展,具備了OLAP的能力。最新發展顯示,有云廠商在HTAP的基礎上做了某種妥協,將T(transaction)弱化爲S(Serving),朝HSAP方向演進。關於HTAP/HSAP,本文不做進一步展開,可自主查詢其他資料。

主流的OLAP數倉系統很多,包含上面所述的各種類型,下圖是Gartner 2019 年發佈的數據分析市場排名:

可以發現,傳統的商業廠商和閉源的雲服務廠商佔據了絕大部分市場。大部分系統筆者只聽過而沒有研究過。作爲屁股在互聯網公司的數據庫/數據倉庫開發者,本文後續主要聚焦在基於Hadoop生態發展的開源OLAP系統(SQL on Hadoop)。

 

有哪些常用的開源ROLAP產品?

目前生產環境使用較多的開源ROLAP主要可以分爲兩大類,一個是寬表模型,另一個是多表組合模型(就是前述的星型或雪花型)。

寬表模型

寬表模型能夠提供比多表組合模型更好的查詢性能,不足的是支持的SQL操作類型比較有限,比如對Join等複雜操作支持較弱或不支持。

目前該類OLAP系統包括Druid和ClickHouse等,兩者各有優勢,Druid支持更大的數據規模,具備一定的預聚合能力,通過倒排索引和位圖索引進一步優化查詢性能,在廣告分析場景、監控報警等時序類應用均有廣泛使用;ClickHouse部署架構簡單,易用,保存明細數據,依託其向量化查詢、減枝等優化能力,具備強勁的查詢性能。兩者均具備較高的數據實時性,在互聯網企業均有廣泛使用。

除了上面介紹的Druid和ClickHouse外,ElasticSearch和Solar也可以歸爲寬表模型。但其系統設計架構有較大不同,這兩個一般稱爲搜索引擎,通過倒排索引,應用Scatter-Gather計算模型提高查詢性能。對於搜索類的查詢效果較好,但當數據量較大或進行掃描聚合類查詢時,查詢性能會有較大影響。

多表組合模型

採用星型或雪花型建模是最通用的一種ROLAP系統,常見的包括GreenPlum、Presto和Impala等,他們均基於MPP架構,採用該模型和架構的系統具有支持的數據量大、擴展性較好、靈活易用和支持的SQL類型多樣等優點。

相比其他類型ROLAP和MOLAP,該類系統性能不具有優勢,實時性較一般。通用系統往往比專用系統更難實現和進行優化,這是因爲通用系統需要考慮的場景更多,支持的查詢類型更豐富。而專用系統只需要針對所服務的某個特定場景進行優化即可,相對複雜度會有所降低。

對於ROLAP系統,尤其是星型或雪花型的系統,如果能夠儘可能得縮短響應時間非常重要,這將是該系統的核心競爭力。這塊內容,我們放在下一節着重進行介紹。

有哪些黑科技用於優化ROLAP系統性能?

目前生產環境使用的ROLAP系統,均實現了大部分的該領域性能優化技術,包括採用MPP架構、支持基於代價的查詢優化(CBO)、向量化執行引擎、動態代碼生成機制、存儲空間和訪問效率優化、其他cpu和內存相關的計算層優化等。下面逐一進行介紹。

什麼是MPP架構?

首先來聊聊系統架構,這是設計OLAP系統的第一次分野,目前生產環境中系統採用的架構包括基於傳統的MapReduce架構加上SQL層組裝的系統;主流的基於MPP的系統;其他非MPP系統等。

1、MR架構及其侷限

在Hadoop生態下,最早在Hive上提供了基於MapReduce框架的SQL查詢服務。

但基於MR框架侷限性明顯,比如:

  • 每個MapReduce 操作都是相互獨立的,Hadoop不知道接下來會有哪些MapReduce。

  • 每一步的輸出結果,都會持久化到硬盤或者HDFS 上。

第一個問題導致無法進行跨MR操作間的優化,第二個問題導致MR間數據交互需要大量的IO操作。兩個問題均對執行效率產生很大影響,性能較差。

2、MPP優缺點分析

MPP是massively parallel processing的簡稱,即大規模並行計算框架。相比MR等架構,MPP查詢速度快,通常在秒計甚至毫秒級以內就可以返回查詢結果,這也是爲何很多強調低延遲的系統,比如OLAP系統大多采用MPP架構的原因。

下面以Impala爲例,簡單介紹下MPP系統架構。

上圖即爲Impala架構圖,展示了Impala各個組件及一個查詢的執行流程。

  1. 用戶通過Impala提供的impala-shell或beeline等客戶端/UI工具向Impala節點下發查詢SQL;接收該SQL的Impala節點即爲Coordinator節點,該節點負責進行SQL解析;

  2. 首先產生基於單節點的執行計劃;再對執行計劃進行分佈式處理,比如將Join、聚合(aggregation)等並行化到各Impala Executor節點上。執行計劃被切分爲多個Plan Fragment(PF),每個PF又由一到多個Operator組成;

  3. 接着,下發經過優化後的執行計劃的PF到對應的Executor節點,多個執行節點並行處理任務,縮短整個任務所需時間;

  4. 執行節點掃描HDFS/Hbase等存儲上的數據,並逐層進行處理,比如進行跨節點的數據shuffe,Join等操作;

  5. 執行節點完成任務並將輸出結果統一發送到Coordinator節點;

  6. Coordinator節點彙總各個執行節點數據,做最後處理,最終返回給用戶想要的結果集。

3、MPP架構之所以性能比MR好,原因包括:

  • PF之間的數據交互(即中間處理結果)駐留在內存Buffer中不落盤(假設內存夠大);

  • Operator和PF間基於流水線處理,不需要等上一個Operator/PF都完成後才進行下一個處理。上下游之間的關係和數據交互式預先明確的。

這樣可以充分利用CPU資源,減少IO資源消耗。但事情往往是兩面的,MPP並不完美,主要問題包括:

  • 中間結果不落盤,在正常情況下是利好,但在異常情況下就是利空,這意味着出現節點宕機等場景下,需要重新計算產生中間結果,拖慢任務完成時間;

  • 擴展性沒有MR等架構好,或者說隨着MPP系統節點增多到一定規模,性能無法線性提升。有個原因是“木桶效應”,系統性能瓶頸取決於性能最差的那個節點。另一個原因是規模越大,出現節點宕機、壞盤等異常情況就會越頻繁,故障率提高會導致SQL重試概率提升;

基於上述分析,MPP比較適合執行時間不會太久的業務場景,比如數小時。因爲時間越久,故障概率越大。

4、其他非MPP架構

基於MR系統侷限性考慮,除了採用MPP架構外,Hive和Spark均使用不同方式進行了優化,包括Hive的Tez,SparkSQL基於DAG(Directed Acyclic Graph)等。

不同架構有不同優缺點,重要的是找到其適用的場景,並進行靠譜地優化,充分發揮其優勢。

 

什麼是基於代價的查詢優化?

有了適合的系統架構並不一定能夠帶來正向收益,“好馬配好鞍”,執行計劃的好壞對最終系統的性能也有着決定性作用。執行計劃及其優化,就筆者的理解來說,其來源於關係型數據庫領域。這又是一門大學問,這裏僅簡單介紹。

分佈式架構使得執行計劃能夠進行跨節點的並行優化,通過任務粒度拆分、串行變並行等方式大大縮短執行時間。除此之外,還有2個更重要的優化方式,就是傳統的基於規則優化以及更高級的基於代價優化。

基於規則優化

通俗來說,基於規則的優化(rule based optimization,RBO)指的是不需要額外的信息,通過用戶下發的SQL語句進行的優化,主要通過改下SQL,比如SQL子句的前後執行順序等。比較常見的優化包括謂語下推、字段過濾下推、常量摺疊、索引選擇、Join優化等等。

謂語下推,即PredicatePushDown,最常見的就是where條件等,舉MySQL爲例,MySQL Server層在獲取InnoDB表數據時,將Where條件下推到InnoDB存儲引擎,InnoDB過濾where條件,僅返回符合條件的數據。在有數據分區場景下,謂語下推更有效;

字段過濾下推,即ProjectionPushDown,比如某個SQL僅需返回表記錄中某個列的值,那麼在列存模式下,只需讀取對應列的數據,在行存模式下,可以選擇某個索引進行索引覆蓋查詢,這也是索引選擇優化的一種場景;

常量或函數摺疊也是一種常見的優化方式,將SQL語句中的某些常量計算(加減乘除、取整等)在執行計劃優化階段就做掉;

Join優化有很多方法,這裏說的基於規則優化,主要指的是Join的實現方式,比如最傻瓜式的Join實現就是老老實實得讀取參與Join的2張表的每條記錄進行Join條件比對。而最普遍的優化方式就是Hash Join,顯然效率很高。不要認爲這是想當然應該有的功能,其實MySQL直到8.0版本才具備。另外Join的順序及合併,有部分也可以直接通過SQL來進行判斷和選擇。

基於代價優化

基於規則的優化器簡單,易於實現,通過內置的一組規則來決定如何執行查詢計劃。與之相對的是基於代價優化(cost based optimization,CBO)。

CBO的實現依賴於詳細可靠的統計信息,比如每個列的最大值、最小值、平均值、區分度、記錄數、列總和,表大小分區信息,以及列的直方圖等元數據信息。

CBO的一大用途是在Join場景,決定Join的執行方式和Join的順序。這裏所說的Join我們主要是討論Hash Join。

Join執行方式

根據參與Join的驅動表(Build Table)和被驅動表(Probe Table)的大小,Hash Join一般可分爲broadcast和partition兩種。

廣播方式適用於大表與小表進行Join,在並行Join時,將小表廣播到大表分區數據所在的各個執行節點,分別與大表分區數據進行Join,最後返回Join結果並彙總。

而分區方式是最爲一般的模式,適用於大表間Join或表大小未知場景。分別將兩表進行分區,每個分區分別進行Join。

顯然,判斷大小表的關鍵就看是否能夠通過某種方式獲取表的記錄數,如果存儲層保存了記錄數,那麼可從元數據中直接獲取。

如果Join的兩表都是大表,但至少有個表是帶Where過濾條件的,那麼在決定走分區方式前還可進一步看滿足條件的記錄數,這時候,物理上進行分區的表存儲方式可發揮作用,可以看每個分區的最大值和最小值及其記錄數來估算過濾後的總記錄數。當然,還有種更精確的方式是列直方圖,能夠直接而直觀得獲取總記錄數。

如果上述的統計信息都沒有,要使用CBO還有另一種方式就是進行記錄的動態採樣來決定走那種Join方式。

Join順序

如果一個查詢的SQL中存在多層Join操作,如何決定Join的順序對性能有很大影響。這塊也已是被數據庫大佬們充分研究過的技術。

一個好的CBO應該能夠根據SQL 語句的特點,來自動選擇使用Left-deep tree(LDT,左圖)還是 bushy tree(BYT,右圖)執行join。

兩種Join順序沒有好壞之分,關鍵看進行Join的表數據即Join的字段特點。

對於LDT,如果每次Join均能夠過濾掉大量數據,那麼從資源消耗來看,顯然是更優的。對於給每個列都構建了索引的某些系統,使用LDT相比BYT更好。

一般來說,選擇BYT是效率更高的模式,通過串行多層Join改爲並行的更少層次Join,可以發揮MPP架構的優勢,儘快得到結果,在多表模式ROLAP場景常採用。

爲什麼需要向量化執行引擎?其與動態代碼生成有何關係?

查詢執行引擎 (query execution engine) 是數據庫中的一個核心組件,用於將查詢計劃轉換爲物理計劃,並對其求值返回結果。查詢執行引擎對系統性能影響很大,在一項針對Impala和Hive的對比時發現,Hive在某些簡單查詢上(TPC-H Query 1)也比Impala慢主要是因爲Hive運行時完全處於CPU bound的狀態中,磁盤IO只有20%,而Impala的IO至少在85%。

什麼原因導致這麼大的差別呢?首先得簡單說下火山模型的執行引擎。

火山模型及其缺點

火山模型(Volcano-style execution)是最早的查詢執行引擎,也叫做迭代模型 (iterator model),或 one-tuple-at-a-time。在這種模型中,查詢計劃是一個由operator組成的DAG,其中每一個operator 包含三個函數:open,next,close。Open 用於申請資源,比如分配內存,打開文件,close 用於釋放資源,next方法遞歸的調用子operator的 next方法生成一個元組(tuple,即行row在物理上的表示)。

下圖描述了“select sum(C1) from T1 where C2 > 15”的查詢計劃,該查詢計劃包含Project,HashAgg,Scan等operator,每個 operator的next方法遞歸調用子節點的 next,一直遞歸調用到葉子節點Scan operator,Scan operator的next 從文件中返回一個元組。

其缺點主要在於:

  • 大量虛函數調用:火山模型的next方法通常實現爲一個虛函數,在編譯器中,虛函數調用需要查找虛函數表, 並且虛函數調用是一個非直接跳轉 (indirect jump), 會導致一次錯誤的CPU分支預測 (brance misprediction), 一次錯誤的分支預測需要十幾個週期的開銷。火山模型爲了返回一個元組,需要調用多次next 方法,導致昂貴的函數調用開銷

  • 類型裝箱:對於a + 2 * b之類表達式,由於需要對不同數據類型的變量做解釋,所以在Java中需要把這些本來是primitive(如int等類型)的變量包裝成Object,但執行時又需要調用具體類型的實現函數,這本質上也是虛函數調用的效率問題;

  • CPU Cache利用效率低:next方法一次只返回一個元組,元組通常採用行存儲,如果僅需訪問第一列而每次均將一整行填入CPU Cache,將導致Cache Miss;

  • 條件分支預測失敗:現在的CPU都是有並行流水線的,但是如果出現條件判斷會導致無法並行。比如判斷數據的類型(是string還是int),或判斷某一列是否因爲其他字段的過濾條件導致本行不需要被讀取等場景;

  • CPU與IO性能不匹配:每次從磁盤讀取一個行數據,經過多次調用交給CPU進行處理,顯然,大部分時間都是CPU等待數據就緒,導致CPU空轉。

通過上述描述,可以得出解決問題的基本方法。可以將問題分爲2大類,分別用下述的向量化引擎和動態代碼生成技術來解決。

向量化執行引擎

向量化執行以列存爲前提,主要思想是每次從磁盤上讀取一批列,這些列以數組形式組織。每次next都通過for循環處理列數組。這麼做可以大幅減少next的調用次數。相應的CPU的利用率得到了提高,另外數據被組織在一起。可以進一步利用CPU硬件的特性,如SIMD,將所有數據加載到CPU的緩存當中去,提高緩存命中率,提升效率。在列存儲與向量化執行引擎的雙重優化下,查詢執行的速度會有一個非常巨大的飛躍。

動態代碼生成

向量化執行減少CPU等待時間,提高CPU Cache命中率,通過減少next調用次數來緩解虛函數調用效率問題。而動態代碼生成,則是進一步解決了虛函數調用問題。

動態代碼生成技術不使用解釋性的統一代碼,而是直接生成對應的執行語言的代碼並直接用primitive type。對於判斷數據類型造成的分支判斷,動態代碼的效果可以消除這些類型判斷,使用硬件指令來進一步提高循環處理效率。

具體實現來說,JVM系如Spark SQL,Presto可以用反射,C++系的Impala則使用了llvm生成中間碼。相對來說,C++的效率更高。

向量化和動態代碼生成技術往往是一起工作達到更好的效果。

都有哪些存儲空間和訪問效率優化方法?

存儲和IO模塊的優化方法很多,這裏我們還是在Hadoop生態下來考慮,當然,很多優化方法不是Hadoop特有的,而是通用的。OLAP場景下,數據存儲最基礎而有效的優化是該行存儲爲列存儲,下面討論的優化措施均基於列存。

數據壓縮和編碼

數據壓縮是存儲領域常用的優化手段,以可控的CPU開銷來大幅縮小數據在磁盤上的存儲空間,一來可以節省成本,二來可以減小IO和數據在內存中跨線程和跨節點網絡傳輸的開銷。目前在用的主流壓縮算法包括zlib、snappy和lz4等。壓縮算法並不是壓縮比越高越好,壓縮率越高的算法壓縮和解壓縮速度往往就越慢,需要根據硬件配置和使用場景在cpu 和io之間進行權衡。

數據編碼可以理解爲輕量級壓縮,包括RLE和數據字典編碼等。

上圖截至Presto論文,展示了RLE編碼和數據字典編碼的使用方式。RLE用在各列都是重複字符的情況,比如page0中6行記錄的returnflag都是"F"。數據字典可高效使用在區分度較低的列上,比如列中只有幾種字符串的場景。考慮到同個表的列的值相關性,數據字典可以跨page使用。

與數據壓縮相比,數據編碼方式在某些聚合類查詢場景下,無需對數據進行解碼,直接返回所需結果。比如假設T1表的C1列爲某個字符,RLE算法將16個C1列的值“aaaaaabbccccaaaa”編碼爲6a2b4c4a,其中6a表示有連續6個字符a。當執行 select count(*) from T1 where C1=’a’時,不需要解壓6a2b4c4a,就能夠知道這16行記錄對應列值爲a有10行。

在列存模式下,數據壓縮和編碼的效率均遠高於行存。

數據精細化存儲

所謂數據精細化存儲,是通過儘可能多得提供元數據信息來減少不必要的數據掃描和計算,常用的方法包括但不限於如下幾種:

  • 數據分區:數據分區可用於將表中數據基於hash或range打散到多個存儲節點上,配合多副本存儲。可以提高數據容災和遷移效率。除此之外,在查詢時可以快速過濾掉不符合where條件要求的數據分區,無需逐列讀取數據進行判斷。

  • 行組:與數據分區類似,Hadoop中常用的parquet和orcfile還將表數據分爲多個行組(row group),每個行組內的記錄按列存儲。這樣即達到列存提高OLAP查詢效率,同時能夠兼顧查詢多行的需求;

  • 局部索引:在數據分區或行組上創建索引,可以提高查詢效率。如下圖所示,orcfile在每個行組的頭部維護了Index Data來,保存最大值和最小值等元數據,基於這些信息可以快速決定是否需掃描該行組。某些OLAP系統進一步豐富了元數據信息,比如建立該行組記錄的倒排索引或B+樹索引,進一步提高掃描和查詢效率。

  • 富元數據:除了提供最大值和最小值信息外,還可進一步提供平均值、區分度、記錄數、列總和,表大小分區信息,以及列的直方圖等元數據信息。

數據本地化訪問

數據本地化讀寫是常見的優化方法,在Hadoop下也提供了相應的方式。

一般來說,讀HDFS上的數據首先需要經過NameNode獲取數據存放的DataNode信息,在去DataNode節點讀取所需數據。

對於Impala等OLAP系統,可以通過HDFS本地訪問模式進行優化,直接讀取磁盤上的HDFS文件數據。HDFS這個特性稱爲"Short Circuit Local Reads",其相關的配置項(在hdfs-site.xml中)如下:

<property>    <name>dfs.client.read.shortcircuit</name>    <value>true</value>  </property>  <property>    <name>dfs.domain.socket.path</name>    <value>/var/lib/hadoop-hdfs/dn_socket</value>  </property>


其中:dfs.client.read.shortcircuit是打開這個功能的開關,dfs.domain.socket.path是Datanode和DFSClient之間溝通的Socket的本地路徑。

運行時數據過濾

這是少部分OLAP系統才具有的高級功能,比如Impala的RunTime Filter(RF)運行時過濾,和SparkSQL 3.0的 Dynamic Partition Pruning動態分區裁剪,可以將驅動表的bloomfilter(BF)或過濾條件作用在被驅動表的數據掃描階段,從而極大減少需掃描/返回的數據量。下面分別用一個圖進行簡述,在後續分析具體OLAP系統時再詳述。

上圖直觀得展示了Impala runtime filter的實現。流程如下:

  1. 同時下發兩個表的SCAN操作。左邊是大表,右邊是小表(相對而言,也有可能是同等級別的),但是左表會等待一段時間(默認是1s),因此右表的SCAN會先執行;

  2. 右表的掃描的結果根據join鍵哈希傳遞掃不同的Join節點,由Join節點執行哈希表的構建和RF的構建;

  3. Join節點讀取完全部的右表輸入之後也完成了RF的構建,它會將RF交給Coordinator節點(如果是Broadcast Join則會直接交給左表的Scan節點);

  4. Coordinator節點將不同的RF進行merge,也就是把Bloom Filter進行merge,merge之後的Bloom Filter就是一個GLOBAL RF,它將這個RF分發給每一個左表Scan;

  5. 左表會等待一段時間(默認1s)再開啓數據掃描,爲了是儘可能的等待RF的到達,但是無論RF什麼時候到達,RF都會在到達那一刻之後被應用;

  6. 左表使用RF完成掃描之後同樣以Hash方式交給Join節點,由Join節點進行apply操作,以完成整個Join過程。

sparksql圖1(官方這個圖有誤,右邊應該是Scan Date)

sparksql圖2

上面2幅圖是SparkSQL 3.0的動態分區裁剪示意圖。將右表的掃描結果(hashtable of table Date after filter)廣播給左表的Join節點,在進行左表掃描時即使用右表的hashtable進行條件數據過濾。

 

除了上面這些,還有其他優化方法嗎?

還有個極爲重要的技術是集羣資源管理和調度。Hadoop使用YARN進行資源調度,雖然帶來了很大遍歷,但對性能要求較高的OLAP系統卻有些不適合。

如啓動AppMaster和申請container會佔用不少時間,尤其是前者,而且container的供應如果時斷時續,會極大的影響時效性。

目前的優化方法主要包括讓AppMaster啓動後長期駐守,container複用等方式。讓資源在需要用時已經就位,查詢無需等待即可馬上開始。

 

最後做個總結

本文主要是想闡述下自己對數倉和OLAP系統的理解,之所以採用問答形式,是因爲筆者就是帶着這些問題去google網上或公司內部的資料,或者直接請教在這個領域的大佬。

由於水平有限,難免有所錯誤,非常歡迎大家看後能夠指出。

往期推薦
▬
Spark 3.0.0正式版發佈,開發近兩年新增了哪些特性?

乾貨 | Kafka 內核知識梳理,附思維導圖

數據倉庫、數據湖、流批一體,終於有大神講清楚了!

Flink在快手實時多維分析場景的應用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章