kylin簡單優化cube


優化Cube

層次結構

      理論上,對於N維,你最終會得到2 ^ N維組合。但是對於某些維度組,不需要創建這么多組合。例如,如果您有三個維度:洲,國家,城市(在層次結構中,“更大”維度首先出現)。在深入分析時,您只需要以下三種組合組合:

按大陸分組

按大陸,國家分組

按大陸,國家,城市分組

在這種情況下,組合計數從2 ^ 3 = 8減少到3,這是一個很好的優化。 YEAR,QUATER,MONTH,DATE案例也是如此。

派生列

派生列用於一個或多個維度(它們必須是查找表上的維度,這些列稱為“派生”)可以從另一個維度推導出來(通常它是相應的FK,這稱為“主機列”)

例如,假設我們有一個查找表,我們將其連接到事實表,並將其與“其中DimA = DimX”。請注意,在Kylin中,如果您選擇FK為維度,相應的PK將自動排隊,無需任何額外費用。秘訣是,由於FK和PK總是相同的,Kylin可以先在FK上應用過濾器/ groupby,然后將它們透明地替換為PK。這表明如果我們想在我們的立方體中使用DimA(FK),DimX(PK),DimB,DimC,我們可以安全地選擇DimA,DimB,DimC。

 

事實表(連接)查找表

column1,column2 ,,,,,, DimA(FK)DimX(PK),, DimB,DimC

假設DimA(代表FK / PK的維度)具有到DimB的特殊映射:

dimA    dimB     dimC

 1       a       ?

 2       b      ?

 3       c       ?

 4       a       ?

在這種情況下,給定DimA中的值,確定DimB的值,因此我們說dimB可以從DimA導出。當我們構建一個包含DimA和DimB的多維數據集時,我們簡單地包含DimA,並將DimB標記為派生。派生列(DimB)不參與長方體生成:

原創組合:

ABC,AB,AC,BC,A,B,C

從A到B時的組合:

AC,A,C

在運行時,如果查詢類似於“select count(*) from fact_table inner join looup1 group by looup1 .dimB”,則期望包含DimB的長方體來回答查詢。但是,由於派生優化,DimB將出現在NONE的長方體中。在這種情況下,我們首先修改執行計划以使其由DimA(其主機列)進行分組,我們將得到如下的中間答案:

 DIMA   COUNT(*)

1         1

2         1

3          1

4          1

之后,Kylin將用DimB值替換DimA值(因為它們的值都在查找表中,Kylin可以將整個查找表加載到內存中並為它們構建映射),並且中間結果變為:

  DimB     count(*)

a                1

b                1

c                1

a                1

在此之后,運行時SQL引擎將進一步將中間結果聚合為:

 DimB    count(*)

a          2

b          1

c          1

這一步發生在查詢運行時,這意味着“以額外的運行時聚合為代價”

 

 

性能優化

分區列優化

    如果cube的分區列與Hive表的分區列相同,那么根據它過濾數據能讓Hive聰明地跳過不匹配的分區。因此強烈建議用Hive的分區列(如果它是日期列)作為cube的分區列。這對於那些數據量很大的表來說幾乎是必須的,否則Hive不得不每次在這步掃描全部文件,消耗非常長的時間。

文件合並

    如果啟用了Hive的文件合並,你可以在conf/kylin_hive_conf.xml里關閉它,因為Kylin有自己合並文件的方法(下一節):

<property>

    <name>hive.merge.mapfiles</name>

    <value>false</value>

    <description>Disable Hive's auto merge</description>

</property>

重新分發中間表

    Hive在HDFS上的目錄里生成了數據文件:有些是大文件,有些是小文件甚至空文件。這種不平衡的文件分布會導致之后的MR任務出現數據傾斜的問題:有些mapper完成得很快,但其他的就很慢。針對這個問題,Kylin增加了這一個步驟來“重新分發”數據,這是示例輸出:

total input rows = 159869711

expected input rows per mapper = 1000000

num reducers for RedistributeFlatHiveTableStep = 160

重新分發表的命令:

hive -e "USE default;

SET dfs.replication=2;

SET hive.exec.compress.output=true;

SET hive.auto.convert.join.noconditionaltask=true;

SET hive.auto.convert.join.noconditionaltask.size=100000000;

SET mapreduce.job.split.metainfo.maxsize=-1;

set mapreduce.job.reduces=160;

set hive.merge.mapredfiles=false;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT * FROM kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 DISTRIBUTE BY RAND();"

首先,Kylin計算出中間表的行數,然后基於行數的大小算出重新分發數據需要的文件數。默認情況下,Kylin為每一百萬行分配一個文件。在這個例子中,有1.6億行和160個reducer,每個reducer會寫一個文件。在接下來對這張表進行的MR步驟里,Hadoop會啟動和文件相同數量的mapper來處理數據(通常一百萬行數據比一個HDFS數據塊要小)。如果你的日常數據量沒有這么大或者Hadoop集群有足夠的資源,你或許想要更多的並發數,這時可以將conf/kylin.properties里以下配置設為小一點的數值,比如:

kylin.job.mapreduce.mapper.input.rows=500000

其次,Kylin會運行 “INSERT OVERWRITE TABLE … DISTRIBUTE BY “ 形式的HiveQL來分發數據到指定數量的reducer上。在很多情況下,Kylin請求Hive隨機分發數據到reducer,然后得到大小相近的文件,分發的語句是”DISTRIBUTE BY RAND()”。

如果你的cube指定了一個高基數的列,比如”USER_ID”,作為”分片”維度(在cube的“高級設置”頁面),Kylin會讓Hive根據該列的值重新分發數據,那么在該列有着相同值的行將被分發到同一個文件。這比隨機要分發要好得多,因為不僅重新分布了數據,並且在沒有額外代價的情況下對數據進行了預先分類,如此一來接下來的cube build處理會從中受益。在典型的場景下,這樣優化可以減少40%的build時長。在這個案例中分發的語句是”DISTRIBUTE BY USER_ID”:

請注意: 1)“分片”列應該是高基數的維度列,並且它會出現在很多的cuboid中(不只是出現在少數的cuboid)。 使用它來合理進行分發可以在每個時間范圍內的數據均勻分布,否則會造成數據傾斜,從而降低build效率。典型的正面例子是:“USER_ID”、“SELLER_ID”、“PRODUCT”、“CELL_NUMBER”等等,這些列的基數應該大於一千(遠大於reducer的數量)。 2)”分片”對cube的存儲同樣有好處,不過這超出了本文的范圍。

將cuboid數據轉換為HFile

    這一步啟動一個MR任務來講cuboid文件(序列文件格式)轉換為HBase的HFile格式。Kylin通過cube統計數據計算HBase的region數目,默認情況下每5GB數據對應一個region。Region越多,MR使用的reducer也會越多。如果你觀察到reducer數目較小且性能較差,你可以將“conf/kylin.properties”里的以下參數設小一點,比如:

kylin.hbase.region.cut=2
kylin.hbase.hfile.size.gb=1

rowkey構建

    對rowkey的構建也有一定的要求,一般而言,需要把基數大的字段放在前面,這樣可以在scan的過程中盡可能的跳過更多的rowkey。

    另一方面將基數小的列放在rowkey的后面,可以減少構建的重復計算,有些cuboid可以通過一個以上的父cuboid聚合而成,在這種情況下,Kylin將會選擇最小的父cuboid。例如,AB能夠通過ABC(id:1110)和ABD(id:1101)聚合生成,因此ABD會被作為父cuboid使用,因為它的id比ABC要小。基於以上處理,如果D的基數很小,那么此次聚合操作就會花費很小的代價。因此,當設計cube的rowkey順序的時候,請記住,將低基數的維度列放在尾部。這不僅對cube的構建過程有好處,而且對cube查詢也有好處,因為后聚合(應該是指在HBase查找對應cuboid的過程)也遵循這個規則。

數據轉換為HFile

kylin將生成的cube通過生成HFile的方式導入到hbase,這個優化點可以配置hbase的相關參數。

  1. region數量默認是1,如果數據量大的話可以提高region數量
  2. region大小默認是5GB,也就是hbae官方建議的大小;如果cube大小比這個值小太多,可以減小單region的大小
  3. hfile文件大小,默認是1GB,由於是通過mapreduce寫入的,小文件意味着寫入快,但是讀取慢,大文件意味着寫入慢,讀取快

經驗

  1. 盡量將需要展現的字段作為維度,沒必要所有的一股腦加進去。
  2. 每次查詢或者要經常group by的字段作為Mandatory維度。且該維度放在        rowkey的最前面。
  3. 將數量相近也就是說某兩個字段通過select count("字段名")獲取的結果近似1:1,設置為joint維度。
  4. rowkey的順序按查詢頻率從高到低,從前往后排。
  5. 將經常出現在同一SQL中的不同維度放置在一個維度組中,將從不出現在一個SQL查詢中的不同維度設置在不同的維度組中。
  6. Dictionary默認為dict類型,如果某個字段中的值非常大(小幽遇到過的一個字段中的值保存成文本足足有23Kb!!!),大到以至或者可能使得Cube在build過程中出現OOM的錯誤,則需要將該字段的值設置為fixed_length類型,取可以展現這個維度的前length個字節,比如對於之前那個23kb的字段值,經和業務人員協商,發現取前4000個字節就可以表示這個字段了。所以fixed_length的值設置為4000.值得一提的是,Dictionary默認為false,是不給該字段在內存中建立詞典樹的,而更改為true則表示給該字段建立詞典樹。有詞典樹,則會優化帶有該字段的SQL查詢,提升查詢速度,但相應地也會消耗一些內存。

總結

基於kylin的ui,可以看到kylin在構建cube時各個流程的耗時,可以依據這些耗時做相應的優化,常見的,可以從耗時最長的步驟開始優化,比如:

  1. 遇到創建hive中間表時間很長,考慮對hive表進行分區處理,對表中的文件格式更改,使用orc,parquet等高性能的文件格式
  2. 遇到cube構建時間過長,查看cube設計是否合理,維度的組合關系是否可以再減少,構建引擎是否可以優化

分享一個其他得cube優化設計的推薦:https://www.cnblogs.com/wenBlog/p/10255467.html


免責聲明!

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



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