Apache Kylin 從零開始構建Cube(含優(yōu)化策略)

前言

Apache Kylin采用“預計算”的模式,用戶只需要提前定義好查詢維度,Kylin將幫助我們進行計算,并將結果存儲到HBase中,為海量數據的查詢和分析提供亞秒級返回,是一種典型的“空間換時間”的解決方案。

Kylin架構
  • Hadoop/Hive:Kylin是一個MOLAP系統(tǒng),將hive中的數據進行預計算,利用MR或者SPARK來進行實現
  • HBase:kylin用來存儲OLAP分析的cube數據的地方,實現多維數據集的交互式查詢
  • Rest Server:提供restful接口
  • Query Engine:使用開源的calcite框架實現sql的解析,是sql引擎層
  • Routing:負責將解析生成的執(zhí)行計劃轉換層cube緩存的查詢
  • Metadata:Kylin中大部分元數據信息的存儲
  • Cube Build Engine:負責kylin預計算中創(chuàng)建cube

一.概念

數據倉庫
Data Warehouse,簡稱DW,中文名數據倉庫,是商業(yè)智能(BI)中的核心部分。數據倉庫中存儲的則主要是歷史數據,主要是將不同數據源的數據整合到一起,目的是為企業(yè)決策提供支持,所以可能存在大量數據冗余,但利于多個維度查詢,為決策者提供更多觀察視角。

OLAP
OLAP(Online Analytical Process),聯機分析處理,以多維度的方式分析數據,一般帶有主觀的查詢需求,多應用在數據倉庫,側重于提供決策支持。與之對應的是OLTP(Online Transaction Process),聯機事務處理,側重于數據庫的增刪查改等常用業(yè)務操作。

OLAP以多維度的方式分析數據,而且能夠彈性地提供以下幾種操作

  • 鉆取:在維的不同層次間的變化,從上層降到下一層,或者說將匯總數據拆分到更細節(jié)的數據
  • 上卷:鉆取的逆操作,即從細粒度數據向更高匯總層的聚合
  • 切片:選擇維中特定的值進行分析
  • 切塊:選擇維中特定區(qū)間的數據或者某批特定值進行分析
  • 旋轉:維的位置互換,就像是二維表的行列轉換
OLAP操作.jpg

維度和度量

  • 維度是指審視數據的角度,它通常是數據記錄的一個屬性,例如時間、地點等。
  • 度量是基于數據所計算出來的考量值;它通常是一個數值,如總銷售額、不同的用戶數等。

事實表和維度表

  • 事實表(Fact Table)是指存儲有事實記錄的表,如系統(tǒng)日志、銷售記錄、傳感器數值等;
  • 維度表(Dimension Table)或維表,也叫做查找表(Lookup Table),是與事實表相對應的一種表;它保存了維度的屬性值,可以跟事實表做關聯;相當于將事實表上經常重復的屬性抽取、規(guī)范出來用一張表進行管理。如日期表,地區(qū)表

模型概念

  • 星形模型:特點是只有一張事實表,以及零到多個維度表,事實表與維度表通過主外鍵相關聯,維度表之間沒有關聯;
  • 雪花模型:就是將星形模型中的某些維表抽取成更細粒度的維表,然后讓維表之間也進行關聯;
  • 星座模型:具有多個事實表,維表可以在不同事實表之間共用,這種模型被稱為星座模型;

二.構建準備

1.在Hive中準備數據

需要被分析的數據必須先保存為Hive表的形式,然后Kylin才能從Hive中導入數據,創(chuàng)建Cube。Cube支持從Hive視圖中構建,基于這個特點,可以將原始數據做一定的處理,如增加維度或者做一些預處理,生成相應的視圖,基于視圖來構建Cube。

2.維度表設計
  • 維度的基數不宜過大
  • 主鍵唯一
  • 維度表最好不是Hive的視圖

維度的基數,維度的基數體現了Cube的復雜程度,維度基數過大,會增加Cube的膨脹程度,使用Count-Distinct來對一個維度的基數做一個統(tǒng)計,可以保證能夠設計合理的Cube。

Kylin支持增量Cube構建,通常是按事件屬性來增量的從Hive表中抽取數據。因此Hive表最好按時間屬性分區(qū),這樣可以避免全量數據的掃描,減少讀寫操作對集群的壓力,節(jié)省Cube構建的時間。

UHC 代表 Ultra High Cardinality,即超高基數?;鶖当硎揪S度不同值的數量。通常,維度的基數從數十到數百萬。如果超過百萬,我們將其稱為超高基維度,Kylin 支持超高基維度,但是在 Cube 設計中額外注意超高基維度,它們可能會使 Cube 體積非常大、查詢變慢。

Cube 的最大物理維度數量 (不包括衍生維度) 是 63,但是不推薦使用大于 30 個維度的 Cube,會引起維度災難。

三.設計Cube的全過程

1.導入Hive表

創(chuàng)建或者選擇一個已有的Project,將Hive中表的定義導入到Kylin中,Web界面的操作如下,Mode->DataSource->Load Hive Table。

LoadTable
導入Hive表

之后Kylin會觸發(fā)一個MR或者Spark任務,計算此表基于每個列的基數,這里Kylin對基數的計算方法采用的是HyperLogLog近似算法,與精確值有誤差,但是作為參考值已經足夠了。

2.創(chuàng)建數據模型Data Model

數據模型是構建Cube的基礎,該數據模型可以描述為一個星型模型或者一個雪花模型,有了模型定義Cube的時候,可以在此模型定義的表和列中進行選擇,基于一個模型可以創(chuàng)建多個Cube,減少了用戶的重復性工作。

在Web界面,點擊New->New Model,開始創(chuàng)建數據模型。

創(chuàng)建數據模型

填寫好基本信息之后,開始構建模型。

首先選擇事實表,然后添加維度表,添加維度表需要選擇連接的類型,是Inner還是Left,然后選擇連接的主鍵和外鍵。


添加維度表

接下來會選擇用作維度或者度量的列,這里只是選擇一個范圍,不代表這些列將來一定會用作Cube的構建,在這里可以把可能會用到的列都添加進來,創(chuàng)建Cube的時候,將只能從這些列中選擇。

選擇維度

度量列只能來自事實表,維度列可以來自維度表和事實表。

最后一步是,為模型補充分割時間的列和過濾條件,如果此模型中的事實表的記錄是按照時間來增加的,可以指定一個日期或者時間列作為模型的分割時間列,從而可以讓Cube按此列做增量構建。

除此之外,可以指定過濾條件。Kylin在向Hive請求數據的時候,會帶上此過濾條件。

3.設計Cube

1)首先選擇要使用的數據模型,并為此Cube輸入一個唯一的名稱,添加一些描述信息。

2)然后選擇Cube的維度

Add Dimension逐個添加維度,可以是普通維度,可以是衍生(Derived)維度。
需要為每一個維度起個名字,然后選擇表和列,如果是衍生維度,則必須是來自某個維度表,一次可以選擇多個列,這些列值都可以從該維度表的主鍵衍生出來。

添加維度

3)創(chuàng)建度量
Kylin默認會創(chuàng)建一個Count(1)的度量??梢詥螕簟?Measure”按鈕來添加新的度量。Kylin支持的度量有:SUM、MIN、MAX、COUNT、COUNT DISTINCT、TOP_N、RAW等。Kylin可以支持在一個Cube中添加多達上百個的度量。

4)關于Cube數據刷新的設置。在這里可以設置自動合并的閾值、數據保留的最短時間,以及第一個Segment的起點時間(如果Cube有分割時間列的話)

Cube數據刷新的設置

設置Auto Merge Thresholds:合并的閾值可以設置多個層級,當最大閾值不能滿足時,嘗試下一個稍小的閾值。

設置Volatile Range:如何你不想Kylin自動合并最近某個時間段的Segment,可以設置改屬性。

設置Retention Threshold:如果你想只保留最近1年的Segment中的數據,可以設置該值為365。

5)高級設置。在此頁面上可以設置聚合組和Rowkey
Kylin默認會把所有維度都放在同一個聚合組中;如果維度數較多(例如>10),那么建議用戶根據查詢的習慣和模式,單擊“New Aggregation Group+”,將維度分為多個聚合組。

設置聚合組

聚合組的優(yōu)化細節(jié)還會在本篇文章的后續(xù)講解。

在HBase中Key的存儲方式?
Kylin以Key-Value的方式將Cube存儲到HBase中。HBase的key,也就是Rowkey,是由各維度的值拼接而成的;為了更高效地存儲這些值,Kylin會對它們進行編碼和壓縮;每個維度均可以選擇合適的編碼(Encoding)方式,默認采用的是字典(Dictionary)編碼技術;除了字典以外,還有整數(Int)和固定長度(Fixed Length)的編碼等。

字典編碼是將此維度下的所有值構建成一個從string到int的映射表;Kylin會將字典序列化保存,在Cube中存儲int值,從而大大減小存儲的大小。

字典編碼的優(yōu)勢是產生的編碼非常緊湊,尤其在維度值的基數較小且長度較大的情況下,特別節(jié)約空間。由于產生的字典是在查詢時加載入構建引擎和查詢引擎的,所以在維度的基數大、長度也大的情況下,容易造成構建引擎或查詢引擎的內存溢出。

Kylin支持的編碼方式還有以下幾種:

  • Date編碼:日期編碼,使用三個字節(jié)進行編碼
  • Time編碼:Time編碼僅僅支持到秒,每個維度僅僅使用4個字節(jié)
  • Integer編碼:需要提供一個額外的參數“Length”來代表需要多少個字節(jié)
  • Fixed_length編碼:采用一段固定長度的字節(jié)來存儲代表維度值的字節(jié)數組。

各維度在Rowkeys中的順序如何設置?
各維度在Rowkeys中的順序,對于查詢的性能會產生較明顯的影響。通常建議將 mandantory 維度放在開頭, 然后是在過濾 ( where 條件)中起到很大作用的維度;如果多個列都會被用于過濾,將高基數的維度(如 user_id)放在低基數的維度(如 age)的前面。這樣做的好處是,充分利用過濾條件來縮小在HBase中掃描的范圍,從而提高查詢的效率。

其余需要主要的設置?

  • Mandatory Cuboids: 維度組合白名單。確保你想要構建的 cuboid 能被構建。
  • Cube Engine: cube 構建引擎。有兩種:MapReduce 和 Spark。如果你的 cube 只有簡單度量(SUM, MIN, MAX),建議使用 Spark。如果 cube 中有復雜類型度量(COUNT DISTINCT, TOP_N),建議使用 MapReduce。
  • Advanced ColumnFamily: 如果有超過一個的COUNT DISTINCT 或 TopN 度量, 可以將它們放在更多列簇中,以優(yōu)化與HBase 的I/O。
Advanced ColumnFamily

6)高級設置
為Cube配置參數。和其他Hadoop工具一樣,Kylin使用了很多配置參數以提高靈活性,用戶可以根據具體的環(huán)境、場景等配置不同的參數進行調優(yōu)。

單擊“+Property”按鈕,然后輸入參數名和參數值,如指定kylin.hbase.region.cut=2,這樣此Cube在存儲的時候,Kylin將會為每個HTable Region分配2GB來創(chuàng)建一個HTable Region。當Segment中一些Cuboid的大小總和超出一定的閾值時,系統(tǒng)會將這些Cuboid的數據分片到多個分區(qū)中以實現Cuboid數據讀取的并行化,從而優(yōu)化Cube的查詢速度。

類型的配置還有:kylin.hbase.region.count.minkylin.hbase.region.count.max 決定每個Segment最少或最多被劃分成多少個分區(qū)。

最后再單擊“Save”按鈕進行保存,一個Cube就設計完成了。

四.Cube的構建

Cube的構建方式通常有兩種:全量構建和增量構建;兩者的構建步驟是完全一樣的,區(qū)別只在于構建時讀取的數據源是全集還是子集

Cube的構建是如何由任務引擎來調度執(zhí)行的?

  • 創(chuàng)建臨時的Hive平表(將數據從源Hive表提取出來,和所有join的表一起,并插入到一個中間平表)
  • 重新分配平面表(解決不平衡的文件分布導致之后的MR任務出現數據傾斜的問題)
  • 創(chuàng)建事實表的dictinct columns文件:計算每一個出現在事實表中的維度和度量的dictinct值
  • 構建維度字典。
  • 保存Cuboid的統(tǒng)計數據
  • 創(chuàng)建HTable
  • 構建Basic Cuboid
  • 構建N維Cuboid
  • 基于內存構建Cube
  • 將Cube的計算結果轉成HFile
  • 加載HFile到HBase
  • 更新Cube元數據
  • 垃圾回收,清理構建過程中生成的臨時文件等垃圾,釋放集群資源。

構建N維Cuboid的詳細說明

構建N維Cuboid的過程,每一步以前一步的輸出作為輸入,然后去掉一個維度以聚合得到一個子Cuboid。舉個例子,Cuboid ABCD去掉A得到BCD,去掉B得到ACD。

有些Cuboid可以從一個以上的父Cuboid聚合得到,這種情況下,Kylin會選擇最小的一個父Cuboid。舉例,AB可以從ABC(id:1110)和ABD(id:1101)生成,則ABD會被選中,因為它的比ABC要小。在這基礎上,如果D的基數較小,聚合運算的成本就會比較低。所以,當設計rowkey序列的時候,請記得將基數較小的維度放在末尾。這樣不僅有利于cube構建,而且有助于cube查詢,因為預聚合也遵循相同的規(guī)則。

通常來說,從N維到(N/2)維的構建比較慢,因為這是Cuboid數量爆炸性增長的階段:N維有1個cuboid,(N-1)維有N個cuboid,(N-2)維有N*(N-1)個cuboid,以此類推。經過(N/2)維構建的步驟,整個構建任務會逐漸變快。

五.Cube的剪枝優(yōu)化

一般來說,Cube的膨脹率應該在0%~1000%之間,通常,膨脹率高有以下幾個方面的原因:

  • Cube中的維度數量較多,且沒有進行很好的Cuboid剪枝優(yōu)化,導致Cuboid數量極多
  • Cube中存在較高基數的維度,導致包含這類維度的每一個Cuboid占用的空間都很大,這些Cuboid累積造成整體Cube體積變大。
  • 存在比較占用空間的度量,如Count Distinct,因此需要在Cuboid的每一行中都為其保存一個較大的寄存器

剪枝優(yōu)化策略如下所示:

1.使用衍生維度

衍生維度用于在有效維度內將維度表上的非主鍵維度排除掉,并使用維度表的主鍵(其實是事實表上相應的外鍵)來替代它們。Kylin會在底層記錄維度表主鍵與維度表其他維度之間的映射關系,以便在查詢時能夠動
態(tài)地將維度表的主鍵“翻譯”成這些非主鍵維度,并進行實時聚合。

例如:
原始組合:ABC,AB,AC,BC,A,B,C
當定義B維度從A維度衍生時的組合:AC,A,C

可見從7種組合變成了3種組合。

假設原始的維度表這樣定義

A B C
1 a ?
2 b ?
3 c ?
4 b ?

如果我們想根據B維度來進行查詢,如select count(*) from tbl inner join lookup_tbl group by lookup_tbl.B
則Kylin會對該查詢進行優(yōu)化,使其由A維度進行分組。

A COUNT(*)
1 1
2 1
3 1
4 1

之后根據B維度從A維度衍生出來的映射關系,將A替換為B,則如下所示

B COUNT(*)
a 1
b 1
c 1
b 1

最后會對以上結果進行聚合操作,如下所示

B COUNT(*)
a 1
b 2
c 1

因此,如果從維度表主鍵到某個維度表維度所需要的聚合工作量非常大,那么定義一個普通的維度可能是一種更好的選擇。

2.使用聚合組

聚合組假設一個Cube的所有維度均可以根據業(yè)務需求劃分成若干組。每個分組的維度集合均是Cube所有維度的一個子集,不同的分組各自擁有一套維度集合,它們可能與其他分組有相同的維度,也可能沒有相同的維度。構建引擎會保證每一個Cuboid無論在多少個分組中出現,它都只會被物化一次。

通過使用多個聚合組,可以大大降低Cube中的Cuboid數量。下面來舉例說明,如果一個Cube有(M+N)個維度,那么默認它會有2^(m + n) 個 Cuboid;如果把這些維度分為兩個不相交的聚合組,那么Cuboid的數量將被減少為2^m + 2^n。

在單個聚合組中,可以對維度設置高級屬性,如Mandatory、Hierarchy、Joint等。這幾種屬性都是為優(yōu)化Cube的計算而設計的。

Mandatory 必要維度,總是出現的維度。指的是那些總是會出現在Where條件或Group By語句里的維度;通過將某個維度指定為Mandatory,此聚合組產生的所有Cuboid中每一個Cuboid都會包含該維度,Kylin就可以不用預計算那些不包含此維度的Cuboid,從而減少計算量。

Hierarchy 層級維度,例如 “國家” -> “省” -> “市” 是一個層級;不符合此層級關系的 cuboid 可以被跳過計算,例如 [“省”], [“市”]. 定義層級維度時,將父級別維度放在子維度的左邊。通過指定Hierarchy,Kylin可以省略不滿足此模式的Cuboid。假設一個層級中包含D1,D2…Dn這n個維度,那么在該分組產生的任何Cuboid中,這n個維度只會以(),(D1),(D1,D2)…(D1,D2…Dn)這n+1種形式中的一種出現。

Joint 聯合維度,其通常適用于如下兩種情形。總是會在一起查詢的維度,基數非常接近(有1:1映射關系)。如果某些列形成一個聯合,那么在該分組產生的任何Cuboid中,這些聯合維度要么一起出現,要么都不出現。

高基數維度使用聚合組控制Cube的膨脹率的思想?
高基數維度的Cuboid在行數和體積上往往非常龐大,這會導致整個Cube的膨脹率變大。如果根據業(yè)務需求知道這個高基數的維度只會與若干個維度(而不是所有維度)同時被查詢到,那么就可以通過聚合組對這個高基數維度做一定的“隔離”。

把這個高基數的維度放入一個單獨的聚合組,再把所有可能會與這個高基數維度一起被查詢到的其他維度也放進來。

這樣,這個高基數的維度就被“隔離”在一個聚合組中了,所有不會與它一起被查詢到的維度都沒有和它一起出現在任何一個分組中,因此也就不會有多余的Cuboid產生。這點也大大減少了包含該高基數維度的Cuboid的數量,可以有效地控制Cube的膨脹率。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容