kylin高級設置

更新設置 refresh settings

這一步驟是爲增量構建 cube 而設計的。

Auto Merge Thresholds: 自動合併小的 segments 到中等甚至更大的 segment。如果不想自動合併,刪除默認2個選項。

Volatile Range: 默認爲0,會自動合併所有可能的 cube segments,或者用 ‘Auto Merge’ 將不會合並最新的 [Volatile Range] 天的 cube segments。

Retention Threshold: 只會保存 cube 過去幾天的 segment,舊的 segment 將會自動從頭部刪除;0表示不啓用這個功能。

Partition Start Date: cube 的開始日期.

高級設置 advanced settings

說明:

Aggregation Groups: Cube 中的維度可以劃分到多個聚合組中。默認 kylin 會把所有維度放在一個聚合組,當維度較多時,產生的組合數可能是巨大的,會造成 Cube 爆炸;如果你很好的瞭解你的查詢模式,那麼你可以創建多個聚合組。在每個聚合組內,使用 “Mandatory Dimensions”, “Hierarchy Dimensions” 和 “Joint Dimensions” 來進一步優化維度組合。

Mandatory Dimensions: 必要維度,用於總是出現的維度。例如,如果你的查詢中總是會帶有 “ORDER_DATE” 做爲 group by 或 過濾條件, 那麼它可以被聲明爲必要維度。這樣一來,所有不含此維度的 cuboid 就可以被跳過計算。(比如,Mandatory Dimensions設置爲p1,所有不包含該維度p1的cuboid會被跳過計算,當我們查詢select channeled, count(*) from soda_report where datetime=’20180919’ group by channeled時,沒有現成的完全匹配的 Cuboid,Kylin 會通過在線計算的方式,從現有的 Cuboid 中計算出最終結果)

Hierarchy Dimensions: 層級維度,例如 “國家” -> “省” -> “市” 是一個層級;不符合此層級關係的 cuboid 可以被跳過計算,例如 [“省”], [“市”]. 定義層級維度時,將父級別維度放在子維度的左邊。

Joint Dimensions: 聯合維度,有些維度往往一起出現,或者它們的基數非常接近(有1:1映射關係)。例如 “user_id” 和 “email”。把多個維度定義爲組合關係後,所有不符合此關係的 cuboids 會被跳過計算。

ROWKEYS

是由維度編碼值組成。”Dictionary” (字典)是默認的編碼方式; 字典只能處理中低基數(少於一千萬)的維度;如果維度基數很高(如大於1千萬), 選擇 “false” 然後爲維度輸入合適的長度,通常是那列的最大長度值; 如果超過最大值,會被截斷。請注意,如果沒有字典編碼,cube 的大小可能會非常大。

你可以拖拽維度列去調整其在 rowkey 中位置; 位於rowkey前面的列,將可以用來大幅縮小查詢的範圍。通常建議將 mandantory 維度放在開頭, 然後是在過濾 ( where 條件)中起到很大作用的維度;如果多個列都會被用於過濾,將高基數的維度(如 user_id)放在低基數的維度(如 age)的前面。

Mandatory Cuboids: 

維度組合白名單。確保你想要構建的 cuboid 能被構建。

Cube Engine: 

cube 構建引擎。有兩種:MapReduce 和 Spark。如果你的 cube 只有簡單度量(SUM, MIN, MAX),建議使用 Spark。如果 cube 中有複雜類型度量(COUNT DISTINCT, TOP_N),建議使用 MapReduce。

Advanced Dictionaries:

“Global Dictionary” 是用於精確計算 COUNT DISTINCT 的字典, 它會將一個非 integer的值轉成 integer,以便於 bitmap 進行去重。如果你要計算 COUNT DISTINCT 的列本身已經是 integer 類型,那麼不需要定義 Global Dictionary。 Global Dictionary 會被所有 segment 共享,因此支持在跨 segments 之間做上捲去重操作。請注意,Global Dictionary 隨着數據的加載,可能會不斷變大。

“Segment Dictionary” 是另一個用於精確計算 COUNT DISTINCT 的字典,與 Global Dictionary 不同的是,它是基於一個 segment 的值構建的,因此不支持跨 segments 的彙總計算。如果你的 cube 不是分區的或者能保證你的所有 SQL 按照 partition_column 進行 group by, 那麼你應該使用 “Segment Dictionary” 而不是 “Global Dictionary”,這樣可以避免單個字典過大的問題。

請注意:”Global Dictionary” 和 “Segment Dictionary” 都是單向編碼的字典,僅用於 COUNT DISTINCT 計算(將非 integer 類型轉成 integer 用於 bitmap計算),他們不支持解碼,因此不能爲普通維度編碼。

Advanced Snapshot Table: 

爲全局 lookup 表而設計,提供不同的存儲類型。

Advanced ColumnFamily:

 如果有超過一個的COUNT DISTINCT 或 TopN 度量, 你可以將它們放在更多列簇中,以優化與HBase 的I/O。

配置重寫 configuration Overwrites

說明:Kylin允許在Cube級別覆蓋部分kylin.properties中的配置,你可以在這裏定義覆蓋的屬性,如果不需要,則Next

管理cube碎片

增量構建的Cube每天都可能會有新的增量。日積月累,這樣的Cube中最終可能包含上百個Segment,這將會導致查詢性能受到嚴重的影響,因爲運行時的查詢引擎需要聚合多個Segment的結果才能返回正確的查詢結果。從存儲引擎的角度來說,大量的Segment會帶來大量的文件,這些文件會充斥所提供的命名空間,給存儲空間的多個模塊帶來巨大的壓力,例如Zookeeper、HDFS Namenode等。因此,有必要採取措施控制Cube中Segment的數量。

另外,有時候用戶場景並不能完美地符合增量構建的要求,由於ETL過程存在延遲,數據可能一直在持續地更新,有時候用戶不得不在增量更新已經完成後又回過頭來刷新過去已經構建好了的增量Segment,對於這些問題,需要在設計Cube的時候提前進行考慮。

3.4.1 合併Segment

Kylin提供了一種簡單的機制用於控制Cube中Segment的數量:合併Segments。在Web GUI中選中需要進行Segments合併的Cube,單擊Action→Merge,然後在對話框中選中需要合併的Segment,可以同時合併多個Segment,但是這些Segment必須是連續的。單擊提交後系統會提交一個類型爲“MERGE”的構建任務,它以選中的Segment中的數據作爲輸入,將這些Segment的數據合併封裝成爲一個新的Segment(如圖3-5所示)。這個新的Segment的起始時間爲選中的最早的Segment的起始時間,它的結束時間爲選中的最晚的Segment的結束時間。

 

圖3-5 合併Segment

在MERGE類型的構建完成之前,系統將不允許提交這個Cube上任何類型的其他構建任務。但是在MERGE構建結束之前,所有選中用來合併的Segment仍然處於可用的狀態。當MERGE構建結束的時候,系統將選中合併的Segment替換爲新的Segment,而被替換下的Segment等待將被垃圾回收和清理,以節省系統資源。

用戶也可以使用Rest接口觸發合併Segments,該API在之前的觸發增量構建中也已經提到過:

PUT https://hostname:port/kylin/api/Cubes/{CubeName}/rebuild

 

Path Variable

CubeName – 必須的,Cube名字

Request Body

startTime – 必須的,長整數類型的起始時間,例如使用1388563200000代表起始時間爲2014-01-01

endTime – 必須的,長整數類型的結束時間

buildType – 必須的,構建類型,可能的值爲‘BUILD’‘MERGE’和‘REFRESH’,分別對應於新建Segment、合併多個Segment,以及刷新某個Segment

我們需要將buildType設置爲MERGE,並且將startTime設置爲選中的需要合併的最早的Segment的起始時間,將endTime設置爲選中的需要合併的最晚的Segment的結束時間。

合併Segment非常簡單,但是需要Cube管理員不定期地手動觸發合併,尤其是當生產環境中存在大量的Cube時,對每一個Cube單獨觸發合併操作會變得非常繁瑣,因此,Kylin也提供了其他的方式來管理Segment碎片。

3.4.2 自動合併

在3.2.2節中曾提到過,在Cube Designer的“Refresh Settings”的頁面中有“Auto Merge Thresholds”和“Retention Threshold”兩個設置項可以用來幫助管理Segment碎片。雖然這兩項設置還不能完美地解決所有業務場景的需求,但是靈活地搭配使用這兩項設置可以大大減少對Segment進行管理的麻煩。

“Auto Merge Thresholds”允許用戶設置幾個層級的時間閾值,層級越靠後,時間閾值就越大。舉例來說,用戶可以爲一個Cube指定(7天、28天)這樣的層級。每當Cube中有新的Segment狀態變爲READY的時候,就會觸發一次系統試圖自動合併的嘗試。系統首先會嘗試最大一級的時間閾值,結合上面的(7天、28天)層級的例子,首先查看是否能將連續的若干個Segment合併成爲一個超過28天的大Segment,在挑選連續Segment的過程中,如果遇到已經有個別Segment的時間長度本身已經超過了28天,那麼系統會跳過該Segment,從它之後的所有Segment中挑選連續的累積超過28天的Segment。如果滿足條件的連續Segment還不能夠累積超過28天,那麼系統會使用下一個層級的時間閾值重複尋找的過程。每當找到了能夠滿足條件的連續Segment,系統就會觸發一次自動合併Segment的構建任務,在構建任務完成之後,新的Segment被設置爲READY狀態,自動合併的整套嘗試又需要重新再來一遍。

舉例來說,如果現在有A~H 8個連續的Segment,它們的時間長度分別爲28天(A)、7天(B)、1天(C)、1天(D)、1天(E)、1天(F)、1天(G)、1天(H)。此時第9個Segment I加入,它的時間長度爲1天,那麼現在Cube中總共存在9個Segment。系統首先嚐試能否將連續的Segment合併到28天這個閾值上,由於Segment A已經超過28天,它會被排除。接下來的B到H加起來也不足28天,因此第一級的時間閾值無法滿足,退一步系統嘗試第二級的時間閾值,也就是7天。系統重新掃描所有的Segment,發現A和B已經超過7天,因此跳過它們,接下來發現將Segment C到I合併起來可以達到7天的閾值,因此係統會提交一個合併Segment的構建請求,將Segment C到I合併爲一個新的Segment X。X的構建完成之後,Cube中只剩下三個Segment,分別是原來的A(28天),B(7天)和新的X(7天)。由於X的加入,觸發了系統重新開始整個合併嘗試,但是發現已經沒有滿足自動合併的條件,既沒有連續的、滿足條件的、累積超過28天的Segment,也沒有連續的、滿足條件的、累積超過7天的Segment,嘗試終止。

再舉一個例子,如果現在有A~J 10個連續的Segment,它們的時間長度分別爲28天(A)、7天(B)、7天(C)、7天(D)、1天(E)、1天(F)、1天(G)、1天(H)、1天(I)、1天(J)。此時第11個Segment K加入,它的時間長度爲1天,那麼現在Cube中總共存在11個Segment。系統首先嚐試能否將連續的Segment合併到28天這個閾值上,由於Segment A已經超過28天,它會被排除。系統接着從Segment B開始觀察,發現若把Segment B至K這10個連續的Segment合併在一起正好可以達到第一級的閾值28天,因此係統提交一個合併構建任務把B至K合併爲一個新的Segment X,最終Cube中存在兩個長度均爲28天的Segment,依次對應原來的A和新的X。由於X的加入,觸發了系統重新開始整個合併嘗試,但是發現已經沒有滿足自動合併的條件,嘗試終止。

“Auto Merge Thresholds”的設置非常簡單,在Cube Designer的“Refresh Setting”中,單擊“Auto Merge Thresholds”右側的“New Thresholds”按鈕,即可在層級的時間閾值中添加一個新的層級,層級一般按照升序進行排列(如圖3-6所示)。從前面的介紹中不難得出結論,除非人爲地增量構建一個非常大的Segment,自動合併的Cube中,最大的Segment的時間長度等於層級時間閾值中最大的層級。也就是說,如果層級被設置爲(7天、28天),那麼Cube中最長的Segment也不過是28天,不會出現橫跨半年甚至一年的大Segment。

在一些場景中,用戶可能更希望系統能以自然日的星期、月、年作爲單位進行自動合併,這樣在只需要查詢個別月份的數據時,就能夠只訪問該月的Segment,而非兩個毗鄰的28天長度的Segment。對此,https://issues.apache.org/jira/browse/KYLIN-1865 記錄了這個問題。

 

圖3-6 設置自動合併閾值

3.4.3 保留Segment

從碎片管理的角度來說,自動合併是將多個Segment合併爲一個Segment,以達到清理碎片的目的。保留Segment則是從另外一個角度幫助實現碎片管理,那就是及時清理不再使用的Segment。在很多業務場景中,只會對過去一段時間內的數據進行查詢,例如對於某個只顯示過去1年數據的報表,支撐它的Cube事實上只需要保留過去一年內的Segment即可。由於數據在Hive中往往已經存在備份,因此無需再在Kylin中備份超過一年的歷史數據。

在這種情況下,我們可以將“Retention Threshold”設置爲365。每當有新的Segment狀態變爲READY的時候,系統會檢查每一個Segment:如果它的結束時間距離最晚的一個Segment的結束時間已經大於“Retention Threshold”,那麼這個Segment將被視爲無需保留。系統會自動地從Cube中刪除這個Segment。

如果啓用了“Auto Merge Thresholds”,那麼在使用“Retention Threshold”的時候需要注意,不能將“Auto Merge Thresholds”的最大層級設置得太高。假設我們將“Auto Merge Thresholds”的最大一級設置爲1000天,而將“Retention Threshold”設置爲365天,那麼受到自動合併的影響,新加入的Segment會不斷地被自動合併到一個越來越大的Segment之中,糟糕的是,這會不斷地更新這個大Segment的結束時間,從而導致這個大Segment永遠不會得到釋放。因此,推薦自動合併的最大一級的時間不要超過1年。

3.4.4 數據持續更新

在實際應用場景中,我們常常會遇到這樣的問題:由於ETL過程的延遲,業務每天都需要刷新過去N天的Cube數據。舉例來說,客戶有一個報表每天都需要更新,但是每天的源數據更新不僅包含了當天的新數據,還包括了過去7天內數據的補充。一種比較簡單的方法是,每天在Cube中增量構建一個長度爲一天的Segment,這樣過去7天的數據就會以7個Segment的形式存在於Cube之中。Cube的管理員除了每天要創建一個新的Segment代表當天的新數據(BUILD操作)以外,還需要對代表過去7天的7個Segment進行刷新(REFRESH操作,Web GUI上的操作及Rest API參數與BUILD類似,這裏不再詳細展開)。這樣的方法固然可以奏效,但是每天爲每個Cube觸發的構建數量太多,容易造成Kylin的任務隊列堆積大量未能完成的任務。

上述簡單方案的另外一個弊端是,每天一個Segment也會讓Cube中迅速地累積大量的Segment,需要Cube管理員手動地對歷史已經超過7天的Segment進行合併,期間還必須小心翼翼地,不能錯將7天內的Segment一起合併了。舉例來說,假設現在有100個Segment,每個Segment代表過去的一天的數據,Segment按照起始時間排序。在合併時,我們只能挑選前面93個Segment進行合併,如果不小心把第94個Segment也一起合併了,那麼當我們試圖刷新過去7天(94~100)的Segment的時候,會發現爲了刷新第94天的數據,不得不將1~93的數據一併重新計算,因爲此時第94天的數據已經和1~93這93天的數據糅合在一個Segment之中了。這對於刷新來說是一種極大的浪費。糟糕的是,即使使用之前所介紹的自動合併的功能,類似的問題也仍然存在,目前爲止,還沒有一種機制能夠有效阻止自動合併試圖合併近期N天的Segment,因此使用自動合併仍然有可能將最近N天內的某些Segment與更早的其他Segment合併成一個大的Segment,這個問題將在https://issues.apache.org/jira/browse/KYLIN-1864中獲得解決。

目前來說,比較折中的一種方案是不以日爲單位創建新的Segment,而是以N天爲單位創建新的Segment。舉例來說,假設用戶每天更新Cube的時候,前面7天的數據都需要更新一下,也就是說,如果今天是01-08,那麼用戶不僅要添加01-08的新數據,還要同時更新01-01到01-07的數據。在這種情況下,可設置N=7作爲最小Segment的長度。在第一天01-01,創建一個新的Segment A,它的時間是從01-01到01-08,我們知道Segment是起始時間閉,結束時間開,因此Segment A的真實長度爲7天,也就是01-01到01-07。即使在01-01當天,還沒有後面幾天的數據,Segment A也能正常地構建,只不過構建出來的Segment其實只有01-01一天的數據而已。從01-02到01-07的每一天,我們都要刷新Segment A,以保證1日到7日的數據保持更新。由於01-01已經是最早的日期,所以不需要對更早的數據進行更新。

到01-08的時候,創建一個新的Segment B,它的時間是從01-08到01-15。此時我們不僅需要構建Segment B,還需要去刷新Segment A。因爲01-01到01-07中的數據在01-08當天仍然可能處於更新狀態。在接下來的01-09到01-14,每天刷新A、B兩個Segment。等到了01-15這天的時候,首先創建一個新的Segment C,它的時間是從01-15到01-22。在01-15當天,Segment A的數據應當已經被視作最終狀態,因爲Segment A中的最後一天(01-07)已經不再過去N天的範圍之內了。因此此時接下來只需要照顧Segment B和Segment C即可。

由此可以看到,在任意一天內,我們只需要同時照顧兩個Segment,第一個Segment主要以刷新近期數據爲主,第二個Segment則兼顧了加入新數據與刷新近期數據。這個過程中可能存在少量的多餘計算,但是每天多餘計算的數據量不會超過N天的數據量。這對於Kylin整體的計算量來說是可以接受的。根據業務場景的不同,N可能是7天,也有可能是30天,我們可以適度地把最小的Segment設置成比N稍微大一點的數字,例如N爲7的時候,我們可以設置爲10天,這樣即使ETL有時候沒有能夠遵守N=7的約定,也仍然能夠刷新足夠的數據。值得一提的是,在https://issues.apache.org/jira/browse/KYLIN-1864得到解決之前,我們不要重疊使用自動合併和本節中所描述的處理數據陸續更新的策略。


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