kylin --Kylin Cube優化

Cuboid剪枝優化

爲什麼要進行Cuboid剪枝優化

將以減少Cuboid數量爲目的的Cuboid優化統稱爲Cuboid剪枝。在沒有采取任何優化措施的情況下,Kylin會對每一種維度的組合進行預計算,每種維度的組合的預計算結果被稱爲Cuboid。

  • 如果有4個維度,可能最終會有2^4 =16個Cuboid需要計算。但在實際開發中,用戶的維度數量一般遠遠大於4個。
  • 如果有10個維度,那麼沒有經過任何優化的Cube就會存在2^10 =1024個Cuboid
  • 如果有20個維度,那麼Cube中總共會存在2^20 =104 8576個Cuboid

這樣的Cuboid的數量就足以讓人想象到這樣的Cube對構建引擎、存儲引擎壓力非常巨大。因此,在構建維度數量較多的Cube時,尤其要注意Cube的剪枝優化。

Cube的剪枝優化是一種試圖減少額外空間佔用的方法,這種方法的前提是不會明顯影響查詢時間。在做剪枝優化的時候,

  • 需要選擇跳過那些“多餘”的Cuboid --》結合業務來判斷哪些cuboid是多餘
  • 有的Cuboid因爲查詢樣式的原因永遠不會被查詢到,因此顯得多餘--》層級維度,省市區,年月日
  • 有的Cuboid的能力和其他Cuboid接近,因此顯得多餘 --》衍生維度
  •  

檢查Cuboid數量

Apache Kylin提供了一個簡單的工具,檢查Cube中哪些Cuboid最終被預計算了,稱這些Cuboid爲被物化的Cuboid,該工具還能給出每個Cuboid所佔空間的估計值。由於該工具需要在對數據進行一定階段的處理之後才能估算Cuboid的大小,因此一般來說只能在Cube構建完畢之後再使用該工具。

使用如下的命令行工具去檢查這個Cube中的Cuboid狀態:

bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader CUBE_NAME 
# CUBE_NAME 想要查看的Cube的名字

示例:

bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader cube_order

============================================================================

Statistics of cube_order[20191011000000_20191015000000]

Cube statistics hll precision: 14

Total cuboids: 3

Total estimated rows: 20

Total estimated size(MB): 1.02996826171875E-4

Sampling percentage:  100

Mapper overlap ratio: 0.0

Mapper number: 0

Length of dimension ITCAST_KYLIN_DW.FACT_ORDER.DT is 1

Length of dimension ITCAST_KYLIN_DW.FACT_ORDER.USER_ID is 1

|---- Cuboid 11, est row: 12, est MB: 0

    |---- Cuboid 01, est row: 4, est MB: 0, shrink: 33.33%

    |---- Cuboid 10, est row: 4, est MB: 0, shrink: 33.33%

----------------------------------------------------------------------------

輸出結果分析:

Cube statistics hll precision: 14

Total cuboids: 3

Total estimated rows: 20

Total estimated size(MB): 1.02996826171875E-4

Sampling percentage:  100

Mapper overlap ratio: 0.0

Mapper number: 0

  • 估計Cuboid大小的精度(Hll Precision)
  • 總共的Cuboid數量
  • Segment的總行數估計
  • Segment的大小估計,Segment的大小決定mapper、reducer的數量、數據分片數量等

|---- Cuboid 11, est row: 12, est MB: 0

    |---- Cuboid 01, est row: 4, est MB: 0, shrink: 33.33%

    |---- Cuboid 10, est row: 4, est MB: 0, shrink: 33.33%

  • 所有的Cuboid及它的分析結果都以樹狀的形式打印了出來
  • 在這棵樹中,每個節點代表一個Cuboid,每個Cuboid都由一連串1或0的數字組成
  • 數字串的長度等於有效維度的數量,從左到右的每個數字依次代表Rowkeys設置中的各個維度。如果數字爲0,則代表這個Cuboid中不存在相應的維度;如果數字爲1,則代表這個Cuboid中存在相應的維度
  • 除了最頂端的Cuboid之外,每個Cuboid都有一個父親Cuboid,且都比父親Cuboid少了一個“1”。其意義是這個Cuboid就是由它的父親節點減少一個維度聚合而來的(上卷)
  • 最頂端的Cuboid稱爲Base Cuboid,它直接由源數據計算而來。Base Cuboid中包含所有的維度,因此它的數字串中所有的數字均爲1
  • 每行Cuboid的輸出中除了0和1的數字串以外,後面還有每個Cuboid的具體信息,包括該Cuboid行數的估計值、該Cuboid大小的估計值,以及這個Cuboid的行數與父親節點的對比(Shrink值)
  • 所有Cuboid行數的估計值之和應該等於Segment的行數估計值,所有Cuboid的大小估計值應該等於該Segment的大小估計值。每個Cuboid都是在它的父親節點的基礎上進一步聚合而成的

 

檢查Cube大小

在Web GUI的Model頁面選擇一個READY狀態的Cube,當我們把光標移到該Cube的Cube Size列時,Web GUI會提示Cube的源數據大小,以及當前Cube的大小除以源數據大小的比例,稱爲膨脹率(Expansion Rate)

一般來說,Cube的膨脹率應該在0%~1000%之間,如果一個Cube的膨脹率超過1000%,那麼應當開始挖掘其中的原因。通常,膨脹率高有以下幾個方面的原因:

  • Cube中的維度數量較多,且沒有進行很好的Cuboid剪枝優化,導致Cuboid數量極多
  • Cube中存在較高基數的維度,導致包含這類維度的每一個Cuboid佔用的空間都很大,這些Cuboid累積造成整體Cube體積變大
  • 存在比較佔用空間的度量,例如Count Distinct,因此需要在Cuboid的每一行中都爲其保存一個較大度量數據,最壞的情況將會導致Cuboid中每一行都有數十KB,從而造成整個Cube的體積變大。

對於Cube膨脹率居高不下的情況,管理員需要結合實際數據進行分析,優化。

 

使用衍生維度

使用衍生維度用於在有效維度內將維度表上的非主鍵維度排除掉並使用維度表的主鍵(其實是事實表上相應的外鍵)來替代它們

創建Cube的時候,這些維度如果指定爲衍生維度,Kylin將會排除這些維度,而是使用維度表的主鍵來代替它們創建Cuboid。後續查詢的時候,再基於主鍵的聚合結果,再進行一次聚合。

優化效果:維度表的N個維度組合成的cuboid個數會從2的N次方降爲2。

不適用的場景

  • 如果從維度表主鍵到某個維度表維度所需要的聚合工作量非常大,此時作爲一個普通的維度聚合更合適,否則會影響Kylin的查詢性能

 

聚合組

聚合組(Aggregation Group)是一種強大的剪枝工具。聚合組假設一個 Cube 的所有維度均可以根據業務需求劃分成若干組(當然也可以是一個組),由於同一個組內的維度更可能同時被同一個查詢用到,因此會表現出更加緊密的內在關聯。每個分組的維度集合均是Cube 所有維度的一個子集,不同的分組各自擁有一套維度集合,它們可能與其他分組有相同的維度,也可能沒有相同的維度。每個分組各自獨立地根據自身的規則貢獻出一批需要被物化的 Cuboid,所有分組貢獻的 Cuboid 的並集就成爲了當前 Cube 中所有需要物化的 Cuboid的集合。不同的分組有可能會貢獻出相同的 Cuboid,構建引擎會察覺到這點,並且保證每
一個 Cuboid 無論在多少個分組中出現,它都只會被物化一次。
對於每個分組內部的維度,用戶可以使用如下三種可選的方式定義,它們之間的關係, 具體如下。
 
1)強制維度(Mandatory,如果一個維度被定義爲強制維度,那麼這個分組產生的所有 Cuboid 中每一個 Cuboid 都會包含該維度。每個分組中都可以有 0 個、1 個或多個強制維度。如果根據這個分組的業務邏輯,則相關的查詢一定會在過濾條件或分組條件中,因此可以在該分組中把該維度設置爲強制維度。
2)層級維度(Hierarchy,每個層級包含兩個或更多個維度。假設一個層級中包含 D1,D2…Dn 這 n 個維度,那麼在該分組產生的任何 Cuboid 中, 這 n 個維度只會以(),(D1),(D1D2D1D2…Dn)這 n+1 種形式中的一種出現。每個分組中可以有 0 個、1 個或多個層級,不同的層級之間不應當有共享的維度。如果根據這個分組的業務邏輯,則多個維度直接存在層級關係,因此可以在該分組中把這些維度設置爲層級維度。
3)聯合維度(Joint,每個聯合中包含兩個或更多個維度,如果某些列形成一個聯合,那麼在該分組產生的任何 Cuboid 中,這些聯合維度要麼一起出現,要麼都不出現。每個分組中可以有 0 個或多個聯合,但是不同的聯合之間不應當有共享的維度(否則它們可以合併成一個聯合)。如果根據這個分組的業務邏輯,多個維度在查詢中總是同時出現,則可以在該分組中把這些維度設置爲聯合維度。
 
這些操作可以在 Cube Designer Advanced Setting 中的 Aggregation Groups 區域完成,如下圖所示。

 

 

併發粒度優化

Segment 中某一個 Cuboid 的大小超出一定的閾值時,系統會將該 Cuboid 的數據分片到多個分區中,以實現 Cuboid 數據讀取的並行化,從而優化 Cube 的查詢速度。具體的實現方式如下:
構建引擎根據 Segment 估計的大小,以及參數“kylin.hbase.region.cut”的設置決定Segment 在存儲引擎中總共需要幾個分區來存儲,如果存儲引擎是 HBase,那麼分區的數量就對應於 HBase 中的 Region 數量。kylin.hbase.region.cut 的默認值是 5.0,單位是 GB,也就是說對於一個大小估計是 50GB Segment,構建引擎會給它分配 10 個分區。用戶還可以通過設置 kylin.hbase.region.count.min(默認爲 1)和 kylin.hbase.region.count.max(默認爲 500
兩個配置來決定每個 Segment 最少或最多被劃分成多少個分區。
由於每個 Cube 的併發粒度控制不盡相同,因此建議在 Cube Designer Configuration Overwrites(上圖所示)中爲每個 Cube 量身定製控制併發粒度的參數。假設將把當前 Cube kylin.hbase.region.count.min 設置爲 2,kylin.hbase.region.count.max
設置爲 100。這樣無論 Segment 的大小如何變化,它的分區數量最小都不會低於 2,最大都不會超過 100。相應地,這個 Segment 背後的存儲引擎(HBase)爲了存儲這個 Segment,也不會使用小於兩個或超過 100 個的分區。我們還調整了默認的 kylin.hbase.region.cut,這樣 50GB Segment 基本上會被分配到 50 個分區,相比默認設置,我們的 Cuboid 可能最多會獲得 5 倍的併發量。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章