kylin構建cube優化


前言

下面通過對kylin構建cube流程的分析來介紹cube優化思路。

 

創建hive中間表

kylin會在cube構建的第一步先構建一張hive的中間表,該表關聯了所有的事實表和維度表,也就是一張寬表。

優化點:

1. hive表分區優化,在構建寬表的時候,kylin需要遍歷hive表,事實表和維度表如果是分區表,那么會減少遍歷時間

2. hive相關配置調整,join相關配置,mapreduce相關配置等

 

創建完成后,為了防止文件大小不一致的情況,kylin又基於hive做了一次重均衡操作,

`kylin.engine.mr.mapper-input-rows=1000000`,默認每個文件包含100w的數據量

 

代碼 `CreateFlatHiveTableStep`

找出所有維度的基數

通過HyperLogLog 算法找出去重后的維度列,如果某個維度的基數很大,那么這種維度為被稱為ultra high cardinality column(UHC),也就是超高基數維度。那么如何處理這類維度呢?

業務層處理UHC

比如時間戳維度基數可能是億級的,可以轉成為日期,基數降到幾十萬.

 

技術層處理UHC

kylin通過mapreduce進行此步驟,在reduce端,一個維度用一個reduce去重,因此當某個維度的基數很大時,會導致該維度所在的reduce運行很慢,甚至內存溢出,為了應對這種場景,kylin提供了兩種解決方案

1. 全局唯一維度,也就是在count_dintinct中選擇0錯誤率的統計分析。

2. 需要被shard by的維度,在rowkey構建時配置的維度。

接着可以通過配置`kylin.engine.mr.uhc-reducer-count=1`來聲明這些列需要被分割成多少個reducer執行

 

當然,kylin也支持基於cuboid個數來進行reducer個數的分配,`kylin.engine.mr.hll-max-reducer-number=1`,默認情況下kylin不開啟此功能,可以修改配置來提高最小個數;然后通過配置`kylin.engine.mr.per-reducer-hll-cuboid-number`來調整具體的reduce數量

int nCuboids = cube.getCuboidScheduler().getAllCuboidIds().size();
int shardBase = (nCuboids - 1) / cube.getConfig().getHadoopJobPerReducerHLLCuboidNumber() + 1;

int hllMaxReducerNumber = cube.getConfig().getHadoopJobHLLMaxReducerNumber();
if (shardBase > hllMaxReducerNumber) {
    shardBase = hllMaxReducerNumber;
}

 

最終的reducer數量由UHC和cuboids兩個部分相加得到,具體代碼參考

`FactDistinctColumnsReducerMapping`構造函數

 

# 配置UHC增加另外步驟,需要配置zk的地址(作為全局分布式鎖使用)

# 因為在跑mapreduce的過程中,kylin沒有將hbase-site.xml等配置上傳到yarn,所以只能在kylin.properties中額外配置一遍

kylin.engine.mr.build-uhc-dict-in-additional-step=true

kylin.env.zookeeper-connect-string=host:port,host:port

 

代碼 `FactDistinctColumnsJob`, `UHCDictionaryJob`

構建維度字典

找出所有維度的基數后,kyin為每個維度構建一個數據字典,字典的metadata存儲在hdfs上,實際數據存儲在hbase

字典在hdfs的路徑規則為

kylin/kylin_meta_data/kylin-$jobid/%cubeid/metadata/dict/$catalog.$table/$dimension/$uuid.dict

 

字典數據在hbase的rowkey規則為

/dict/$catalog.$table/$dimension/$uuid.dict

 

rowkey長度

過長的rowkey會占用很大的存儲空間,所以需要對rowkey長度進行控制。

當前kylin直接在當前進程內做了字典編碼,也就是把string映射成int,如果維度列的基數很大,那么可能會出現內存溢出的情況(當列的基礎大於1kw),這時候就需要考慮更改維度列的編碼方式,改用`fixed_length`等。如果一個維度的長度超過`fixed_length`,那么超過的部分會被截斷。

 

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的過程)也遵循這個規則。

 

維度分片

在構建rowkey過程中,有一個選項,可以聲明哪個維度用於shard。
這個shard的作用是,將該shard維度和總shard數hash,得到的hash結果插入到encoding后的rowkey中,這樣就可以讓該維度下相同的數據盡可能的分配到一個shard中,而在hbase存儲里,一個shard對應的是一個region,這樣處理另一個好處是,在聚合的時候可以很好的把相同數據合並一起,減少網絡傳輸io。參考類`RowKeyEncoder`。一個encoding的rowkey的結構是這樣的

head+shard+dim1+dim2+…+dimn

一個segment的總shard數計算方式如下,參考類`CreateHTableJob`,其中,estimatedSize參數類`CubeStatsReader.estimateCuboidStorageSize`

int shardNum = (int) (estimatedSize * magic / mbPerRegion + 1);

因此,聲明的shard維度最好是被頻繁group by的維度或者是基數很大的維度,這樣在coprocess處理的時候可以加速

 

構建cube

構建引擎

可以選擇spark或者mapreduce來構建cube,通常來說,構建引擎的選擇方式是這樣的

  1. 內存消耗型的cube選擇mapreduce,例如Count Distinct, Top-N
  2. 簡單的cube選擇spark,例如SUM/MIN/MAX/COUNT

 

spark引擎

spark構建引擎采用` by-layer`算法,也就是分層計算

比如有3個維度ABC,cube會構建A,B,C,AB,AC,ABC6種組合,這里就有3層,

第1層:A,B,C

第2層:AB,AC

第3層:ABC

每一層在計算對於spark而言都是一個action,並且該層計算的rdd會依賴其上一層的結果繼續計算,這樣避免了很大重復性計算工作。

 

代碼` SparkCubingByLayer`

設計模式

參考《kylin介紹》中的cube設計模式

 

數據轉換為HFile

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

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

 

代碼`CubeHFileJob`

cleanup

  1. 清理hive中的中間表,
  2. 清理hbase表
  3. 清理hdfs數據

 

清理命令

# 查看需要清理的數據

./bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete false

# 清理

./bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete true

 

// clean參考

http://kylin.apache.org/docs20/howto/howto_cleanup_storage.html

 

總結

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

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

 

優化的思路還是以cube為中心,優化cube的整個生命周期,其中涉及到的所有組件都是優化點,具體情況還是要和實際的數據維度和業務結合起來。

 

參考

// 官方文檔

http://kylin.apache.org/docs20/howto/howto_optimize_build.html

 

// 官方文檔,cube性能優化

http://kylin.apache.org/docs23/tutorial/cube_build_performance.html

 


免責聲明!

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



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