當前位置:
首頁 > 最新 > Apache頂級項目Kylin麒麟

Apache頂級項目Kylin麒麟

Apache Kylin

Kylin是ebay開發的一套OLAP系統,主要是對hive中的數據進行預計算,利用hadoop的mapreduce框架實現。通過設計維度、度量,我們可以構建星型模型或雪花模型,生成數據多維立方體Cube,基於Cube可以做鑽取、切片、旋轉等多維分析操作。

Apache頂級項目Kylin是中國自己的開源,來自本土eBay的頂級項目Kylin。Kylin(麒麟),由eBay研發並貢獻並於2014年10月開源,並於當年11月成為

Apache孵化器項目,是第一個主要由中國團隊完整貢獻給Apache的項目。去年2015年12月,Apache基金會ASF正式批准Kylin為頂級項目。其發展之快可謂迅猛,搭上了基於大數據的OLAP快車,同時也感慨開源之偉大與貢獻。

Apache Kylin核心思想

簡單來說,Kylin的核心思想是預計算,用空間換時間,即對多維分析可能用到的度量進行預計算,將計算好的結果保存成Cube,供查詢時直接訪問。把高複雜度的聚合運算、多表連接等操作轉換成對預計算結果的查詢,這決定了Kylin能夠擁有很好的快速查詢和高並發能力。

Apache Kylin架構

kylin由以下幾部分組成:

· REST Server:提供一些restful介面,例如創建cube、構建cube、刷新cube、合併cube等cube的操作,project、table、cube等元數據管理、用戶訪問許可權、系統配置動態修改等。除此之外還可以通過該介面實現SQL的查詢,這些介面一方面可以通過第三方程序的調用,另一方也被kylin的web界面使用。

· Query引擎:kylin使用一個開源的Calcite框架實現SQL的解析,相當於SQL引擎層。

· Routing:該模塊負責將解析SQL生成的執行計劃轉換成cube緩存的查詢,cube是通過預計算緩存在hbase中,這部分查詢是可以再秒級甚至毫秒級完成,而還有一些操作使用過查詢原始數據(存儲在hadoop上通過hive上查詢),這部分查詢的延遲比較高。

· Metadata:kylin中有大量的元數據信息,包括cube的定義,星狀模型的定義、job的信息、job的輸出信息、維度的directory信息等等,元數據和cube都存儲在hbase中,存儲的格式是json字元串,除此之外,還可以選擇將元數據存儲在本地文件系統。

· Cube構建引擎:這個模塊是所有模塊的基礎,它負責預計算創建cube,創建的過程是通過hive讀取原始數據然後通過一些mapreduce計算生成Htable然後load到hbase中。

Apache Kylin關鍵流程

在kylin中,最關鍵的兩個流程是cube的預計算過程和SQL查詢轉換成cube的過程,cube的構造可以分成cube的構建和cube的合併,首先需要創建一個cube的定義,包括設置cube名、cube的星狀模型結構,dimension信息、measure信息、設置where條件、根據hive中事實表定義的partition設置增量cube,設置rowkey等信息,這些設置在mondrian中也是可以看到的,一個cube包含一些dimension和measure,where條件決定了源數據的大小,在mondrian中可以通過view實現。另外,kylin還提供了增量計算的功能,雖然達不到實時計算的需求,但是基本上可以滿足數據分析的需求。

Apache Kylin cube模型

首先我們會設置cube名和notification列表,前者需要保證是全局唯一的,後者是一些Email用於通知cube的一些事件的發生。接著我們需要定義一個星狀模型,和一般的數據倉庫模型一樣,需要指定一個事實表和任意多個維度表,如果存在維度表還需要指定事實表和維度表的關聯關係,也就是join方式。接下來是定義dimension,在定義dimension的時候可以選擇dimension的類型,分為Normal、Hierachy以及Derived,這個後面再進行介紹,dimension的定義決定著cube的大小,也需要用戶對原始的表非常了解。

接下來是定義measure,kylin會為每一個cube創建一個聚合函數為count(1)的度量,它不需要關聯任何列,用戶自定義的度量可以選擇SUM、COUNT、DISTINCT COUNT、MIN、MAX,而每一個度量定義時還可以選擇這些聚合函數的參數,可以選擇常量或者事實表的某一列,一般情況下我們當然選擇某一列。

定義完measure之後需要設置where條件,這一步是對原始數據進行過濾,例如我們設定銷售額小於XXX的地區不在於本次分析範圍之內,那麼就可以在where條件里設定location in xxx(子查詢),那麼生成的cube會過濾掉這些location,這一步其實相當於對無效數據的清洗,但是在kylin中這個是會固化的,不容易改變,例如我今天希望將銷售額小於XX的地區清洗掉,明天可能有想將年消費小於xxx的用戶去除,這就需要每次都創建一個相同的cube,區別僅僅在於where條件,他們之間會有很多的重複緩存數據,也會導致存儲空間的浪費,但這也是MOLAP系統不可避免的,因此當過濾條件變化比較多的時候,更好的方案則是創建一個完整的cube(不設置任何where條件),使用子查詢的方式過濾掉不希望要的一些維度成員。

接下來的一步是設置增量cube信息,首先需要選擇事實表中的某一個時間類型的分區列(貌似只能是按照天進行分區),然後再指定本次構建的cube的時間範圍(起始時間點和結束時間點),這一步的結果會作為原始數據查詢的where條件,保證本次構建的cube只包含這個閉區間時間內的數據,如果事實表沒有時間類型的分區別或者沒有選擇任何分區則表示數據不會動態更新,也就不可以增量的創建cube了。

最後一步設置rowkey,這一步的建議是看看就可以了,不要進行修改,除非對kylin內部實現有比較深的理解才能知道怎麼去修改。當然這裡有一個可以修改的是mandatory dimension,如果一個維度需要在每次查詢的時候都出現,那麼可以設置這個dimension為mandatory,可以省去很多存儲空間,另外還可以對所有維度進行劃分group,不會組合查詢的dimension可以劃分在不同的group中,這樣也會降低存儲空間。

Dimension介紹

在一個多維數據集合中,維度的個數決定著維度之間可能的組合數,而每一個維度中成員集合的大小決定著每一個可能的組合的個數,例如有三個普通的維度A、B、C,他們的不同成員數分別為10/100/1000,那麼一個維度的組合有2的3次方個,分別是,每一個成員我們稱為cuboid(維度的組合),而這些集合的成員組合個數分別為1、10、100、1000、10*100、100*1000、10*1000和10*100*1000。我們稱每一個dimension中不同成員個數為cardinatily,我們要盡量避免存儲cardinatily比較高的維度的組合,在上面的例子中我們可以不緩存BC和C這兩個cuboid,可以通過計算的方式通過ABC中成員的值計算出BC或者C中某個成員組合的值,這相當於是時間和空間的一個權衡吧。

在kylin中存在的四種維度是為了減少cuboid的個數,而不是每一個維度是否緩存的,當前kylin是對所有的cuboid中的所有組合都進行計算和存儲的,對於普通的dimension,從上面的例子中可以看出N個維度的cuboid個數為2的N次方,而kylin中設置了一些維度可以減少cuboid個數,當然,這需要使用者對自己需要的維度十分了解,知道自己可能根據什麼進行group by。

好了,我們先來看一下kylin中的三種特殊的dimension以及它們的作用

1、Mandatory維度

這種維度意味著每次查詢的group by中都會攜帶的,將某一個dimension設置為mandatory可以將cuboid的個數減少一半,如下圖:

這是因為我們確定每一次group by都會攜帶A,那麼就可以省去所有不包含A這個維度的cuboid了。

2、hierarchy維度

這種維度是最常見的,尤其是在mondrian中,我們對於多維數據的操作經常會有上卷下鑽之類的操作,這也就需要要求維度之間有層級關係,例如國家、省、城市,年、季度、月等。有層級關係的維度也可以大大減少cuboid的個數。如下圖:

這裡僅僅局限於A/B/C是一個層級,例如A是年份,B是季度、C是月份,那麼查詢的時候可能的組合只有年、xx年的季度、xx年xx季度的xx月,這就意味著我們不能再單獨的對季度和月份進行聚合了,例如我們查詢的時候不能使用group by month,而必須使用group by year,quart,month。如果需要單獨的對month進行聚合,那麼還需要再使用month列定義一個單獨的普通維度。

3、derived維度

這類維度的意思是可推導的維度,需要該維度對應的一個或者多個列可以和維度表的主鍵是一對一的,這種維度可以大大減少cuboid個數,如下圖:

例如timeid是時間這個維度表的主鍵,也就是事實表的外檢,時間只精確到天,那麼year、month、day三列可以唯一對應著一個time_id,而time_id是事實表的外鍵,那麼我們可以指定year、month、day為一個derived維度,實際存儲的時候可以只根據timeid的取值決定維度的組合,但這就要求我們在查詢的時候使用的group by必須指定derived維度集合中的所有列。

最後,簡單介紹一下如何計算cuboid個數的,假設我們存在兩個普通維度brand、product,存在一個hierarchy,包含四個維度分別為year、quart、month和day,一個derived維度,指定location信息,包含country、province和city列,這相當於一共9個維度,但是根據上面的分析我們並不需要512分cuboid。

第0層的cuboid(不包含任何維度,不包含group by),cuboid的個數為1,這個cuboid的成員個數也為1;

第1層的cuboid包含一個維度,一共有4種組合(分別為brand、product、year、location,因為quart是hierarchy的第二個層級,不能單獨group by,而location的三列可以視為一個整體),成員個數則有每一個維度的cardinality;

第2層的cuboid有7種,分別為、、、、、和;

第3層的cuboid有8種,分別為、、、、、、、;

第4層的cuboid有8種,分別為、、、、、、、

第5層的cuboid有7種,分別為、、、、、、

第6層的cuboid有5種,分別為、、、

第7層的cuboid有1中,為

所以一共40個cuboid(kylin計算的是39個,應該沒有把第0層的計算在內)。

增量cube

由於kylin的核心在於預計算緩存數據,那麼對於實時的數據查詢的支持就不如mondrian好了,但是一般情況下我們數據分析並沒有完全實時的要求,數據延遲幾個小時甚至一天是可以接受的,kylin提供了增量cube的介面,kylin的實現是一個cube(這裡是指邏輯上的cube)中可以包含多個segment,每一個segment對應著一個物理cube,在實際存儲上對應著一個hbase的一個表,用戶定義根據某一個欄位進行增量(目前僅支持時間,並且這個欄位必須是hive的一個分區欄位),在使用的時候首先需要定義好cube的定義,可以指定一個時間的partition欄位作為增量cube的依賴欄位,其實這個選擇是作為原始數據選擇的條件,例如選擇起始時間A到B的數據那麼創建的cube則會只包含這個時間段的數據聚合值,創建完一個cube之後可以再次基於以前的cube進行build,每次build會生成一個新的segment,只不過原始數據不一樣了(根據每次build指定的時間區間),每次查詢的時候會查詢所有的segment聚合之後的值進行返回,有點類似於tablet的存儲方式,但是當segment存在過多的時候查詢效率就會下降,因此需要在存在多個segment的時候將它們進行合併,合併的時候其實是指定了一個時間區間,內部會選擇這個時間區間內的所有segment進行合併,合併完成之後使用新的segment替換被合併的多個segment,合併的執行時非常迅速的,數據不需要再從HDFS中獲取,直接將兩個hbase表中相同key的數據進行聚合就可以了。但是有一點需要注意的是當合併完成之後,被合併的幾個segment所對應的hbase表並沒有被刪除。實際的使用過程中對於增量的cube可以寫個定時任務每天凌晨進行build,當達到一個數目之後進行merge(其實每次build完成之後都進行merge也應該是可以的)。

cube的詞典樹

kylin的cube數據是作為key-value結構存儲在hbase中的,key是每一個維度成員的組合值,不同的cuboid下面的key的結構是不一樣的,例如cuboid=下面的一個key可能是brand=』Nike』,product=』shoe』,year=2015,那麼這個key就可以寫成Nike:shoe:2015,但是如果使用這種方式的話會出現很多重複,所以一般情況下我們會把一個維度下的所有成員取出來,然後保存在一個數組裡面,使用數組的下標組合成為一個key,這樣可以大大節省key的存儲空間,kylin也使用了相同的方法,只不過使用了字典樹(Trie樹),每一個維度的字典樹作為cube的元數據以二進位的方式存儲在hbase中,內存中也會一直保持一份。

附Apache Kylin使用總結之一,僅供參考。

Apache Kylin是一款以預處理Cube來提高查詢速度的OLAP引擎。

首先對維度表做個簡單的介紹。

麒麟只支持星型模型,也就是說一個事實表加上多個維度表。維度表不存在支架型結構。維度表存放的大多是描述性欄位,用於篩選。其實以SQL的角度來看就是group by/filter through where 的效果。對於一個有N個維度的Cube,可以構建2的N次方個Cuboid。

最開始對Cuboid的概念不是很清楚。看OLAP的概念可以有上鑽,切片之類的操作,但很少說道什麼是Cuboid,和Cuboid裡面到底存放什麼。

首先說下Cuboid裡面存放什麼?其實就是定義那些指標,比如銷售量,貨物總量,或者說就是在麒麟建Data Model時的Measure。那麼什麼是Cuboid呢?Cuboid是某些維度的組合。從包含所有的維度的Base Cuboid到包含0個維度的Apex Cuboid。

在這個Cuboid中會根據維度的值對指標進行聚合,比如Sum,Count。比如日期維度里有20160901-20160930這三十個值,那麼麒麟會把定義好的指標預聚合成三十個分組,當使用group by或者filter時只需要選取其中一個或者幾個分組,再通過SQL引擎進行聚合。

那麼接下來說下我們使用Apache Kylin時候遇到的坑吧,或者說一些我覺得比較難理解的地方。

首先Kylin是一個通過預處理的過程節省查詢時間的OLAP工具,也就是說是空間換時間。所以設計的數據倉庫模型盡量簡潔,把大計算量的數據轉換放到之前的ETL中去進行。開始我們陷入了Hive的思路,試想Kylin能不能載入Hive的UDF。事實上是完全沒有必要的。

二是維度表中除了代理鍵外都設置成derived的維度,可以節省很多空間,因為Kylin自身對derived dimension做了優化。

三是如果維度基數大於一百萬,Rowkey不建議使用字典,因為要載入進內存。當然如果使用fix_length,可能會增大Cube大小。對於基數較大的維度,可以選擇sharding。sharding是一種分表分庫的資料庫存儲方法。由於底層HBase可以並行查詢,使用sharding可以提高查詢效率。

四是Aggregation Group需要仔細設計。通過AGG可以把原來需要構建多個Cube的工作簡化成構建一個Cube,多個AGG,減少了MR Job的開銷。實驗證明可以至少減少一半的時間。

這就是目前使用Apache Kylin遇到的一些坑,匆匆總結如有錯誤請拍磚。

(本文相關信息來自博主彙編,大咖雲集,特别致謝!)

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技金融vs咖啡人生 的精彩文章:

TAG:科技金融vs咖啡人生 |