近幾年,Apache Kylin做爲一個高速的開源分佈式大數據查詢引擎正在迅速崛起。它充分發揮Hadoop、Spark、HBase等技術的優點,經過對超大規模數據集進行預計算,實現秒級甚至亞秒級的查詢響應時間,同時提供標準SQL接口。目前,Apache Kylin已在全球範圍獲得了普遍應用,如百度、美團、今日頭條、eBay等,支撐着單個業務上萬億規模的數據查詢業務。在超高性能的背後,Cube是相當重要的核心。一個優化得當的Cube既能知足高速查詢的須要,又能節省集羣資源。本文將從多個方面入手,介紹如何經過優化Cube提高系統性能。服務器
在傳統多維分析就有多維立方體(OLAP Cube)的概念。Apache Kylin在大數據領域對Cube進行了擴展,經過執行 MapReduce/Spark任務構建Cube,對業務所需的維度組合和度量進行預聚合,當查詢到達時直接訪問預計算聚合結果,省去對大數據的掃描和運算,這就是Apache Kylin高性能查詢的基本實現原理。併發
如圖1所示,Apache Kylin會對SQL的查詢計劃進行改寫,把源表掃描、多表鏈接、指標聚合等在線計算轉換成對預計算結果的讀取,極大減小了在線計算和I/O讀寫的代價。 而查詢所訪問的預計算結果保存在Cuboid當中(見圖1紅色方框),Cuboid大小隻和維度列的基數有關,和源數據行數無關,這使得查詢的時間複雜度能夠取得一個量級的提高。分佈式
圖 - 1預計算查詢計劃oop
一個Cuboid對應着一組分析的維度,並保存了度量的聚合結果。Cube就是全部Cuboid的集合,如圖2所示,每一個節點表明一個Cuboid。當查詢到達,Apache Kylin會根據SQL所使用的維度列在Cube中選擇最合適的Cuboid,最大程度地節省查詢時間。性能
圖 - 2 Cube示意圖大數據
社區不乏一些使用Apache Kylin的成功案例分享,但常常還會看到不少朋友遇到性能問題,例如SQL查詢過慢、Cube構建時間過長甚至失敗、Cube膨脹率太高等等。究其緣由,大多數問題都是因爲Cube設計不當形成的。所以,合理地進行Cube優化就顯得尤其重要。優化
這裏先分享兩個社區用戶進行優化的案例:ui
案例1 – 提高Cube查詢效率spa
背景:某智能硬件企業使用Apache Kylin做爲大數據平臺查詢引擎,對查詢性能有較高要求,但願提升查詢效率。.net
數據:
優化方案:
優化成果:
案例二 – 提高Cube構建效率
背景:某金融企業使用Apache Kylin做爲報表分析引擎,發現Cube膨脹率多大、構建時間過長,但願對這一狀況進行改善。
硬件:20臺高配置PC服務器
數據:事實表有100多萬條記錄,度量是某些列的平均值
優化方案:
優化成果:
從以上案例能夠看出,經過Cube調優能夠顯著改善Apache Kylin的構建性能、查詢性能及Cube膨脹率。那麼這些改進的背後到底是什麼原理呢?
爲了深刻理解Cube,首先要先了解Cuboid生成樹。如圖3所示,在Cube中,全部的Cuboid組成一個樹形結構,根節點是全維度的Base Cuboid,再依次逐層聚合掉每一個維度生成子Cuboid,直到出現0個維度時結束。圖3中綠色部分就是一條完整的Cuboid生成路徑。預計算的過程實際就是按照這個流程構建全部的Cuboid。
圖 - 3 Cuboid生成樹
經過這顆Cuboid生成樹,咱們不難發現:當維度數量過多,就會致使Cuboid數量以指數級膨脹;若是維度基數過大,還會使所在的Cuboid結果集變大。這些都是影響Cube膨脹率和構建時間的重要因素。
可是,全部的Cuboid都是必要的嗎?實際上,在多數狀況下,咱們並不須要這裏的每個Cuboid,所以須要對Cuboid生成樹作剪枝。剪枝能夠從兩個方面入手:數據特性、查詢需求。首先介紹數據特性,考慮下圖的兩個Cuboid,左側Cuboid包含4個維度(ABCD),右側Cuboid包含3個維度(ABC),而兩個Cuboid都包含相同(或極度相近)行數的記錄,說明讀取兩個Cuboid結果的代價是同樣的,同時左側Cuboid除了具備右側Cuboid的查詢支持能力外,還能支持帶有維度D的查詢,所以右側Cuboid就能夠被去除。
圖 - 4 去除冗餘Cuboid
再考慮查詢需求,在報表或多維分析場景中,有些維度是每次查詢都會出現的,如年份;有些維度老是一塊兒出現的,如開始時間、結束時間;有些維度間是有層級關係的,如商品分類或地理信息。充分利用查詢的這些實際需求也能去除不須要的Cuboid,例如:若是年份是必要的,那麼全部不包含年份維度的Cuboid均可以被去除;若是兩個維度老是同時出現,那麼這這些維度單獨出現的Cuboid就能夠被去除。
在Apache Kylin中,能夠經過設置Cube的維度組合規則來去除無用的Cuboid。首先,能夠經過定義(1)聚合組對維度分組,只在每一個聚合組內生成Cuboid。此外,在單個聚合組內部,還能夠設置維度組合規則,如:(2)必須維度用於定義必定出現的維度、(3)聯合維度用於定義一組同時出現的維度、(4)層級維度用於定義一組有層級關係的維度,詳細的Cuboid生成規則以下圖所示:
圖 - 5聚合組規則
維表中能夠由主鍵推導出值的列能夠做爲衍⽣維度。使用場景:以星型模型接入時。例如用戶維表能夠從userid推導出用戶的姓名,年齡,性別。優化效果:維度表的N個維度組合成的cuboid個數會從2的N次方降爲2。
彙集組:用來控制哪些cuboid須要計算。
適用場景:不是隻須要計算base cuboid的狀況下,都須要彙集組。
注意事項:一個維度能夠出如今多個彙集組中,可是build期間只會計算一次。
若是不設置彙集組,默認狀況下只會計算 base cuboid。
彙集組不宜太多。
強制維度:全部cuboid必須包含的維度,不會計算不包含強制維度的cuboid。
適用場景:能夠將肯定在查詢時必定會使用的維度設爲強制維度。例如,時間維度。
優化效果:將一個維度設爲強制維度,則cuboid個數直接減半。
聯合維度:將幾個維度視爲一個維度。
適用場景: 1 能夠將肯定在查詢時必定會同時使用的幾個維度設爲一個聯合維度。
2 能夠將基數很小的幾個維度設爲一個聯合維度。
3 能夠將查詢時不多使用的幾個維度設爲一個聯合維度。
優化效果:將N個維度設置爲聯合維度,則這N個維度組合成的cuboid個數會從2的N次方減小到1。
層次維度:具備必定層次關係的維度。
使用場景:像年,月,日;國家,省份,城市這類具備層次關係的維度。
優化效果:將N個維度設置爲層次維度,則這N個維度組合成的cuboid個數會從2的N次方減小到N+1。
在OLAP分析場景中,常常存在對某個id進行過濾,但查詢結果要展現爲name的狀況,好比user_id和user_name。這類問題一般有三種解決方式:
a. 將ID和Name都設置爲維度,查詢語句相似
select name, count(*) from table where id = 1 group by id,name
。這種方式的問題是會致使維度增多,致使預計算結果膨脹;b. 將id和name都設置爲維度,而且將二者設置爲聯合。這種方式的好處是保持維度組合數不會增長,但限制了維度的其它優化,好比ID不能再被設置爲強制維度或者層次維度;
c. 將ID設置爲維度,Name設置爲特殊的Measure,類型爲Extended Column。這種方式既能保證過濾id且查詢name的需求,同時也不影響id維度的進一步優化。
因此此類需求咱們推薦使用 Extended Column。
簡單的講,查詢頻率越高的維度在Rowkey中的順序須要越靠前。
當Segment中某個Cuboid的大小超出必定的閾值時,系統會將該Cuboid的數據分片到多個Hbase Region Server,從而實現Cuboid數據讀取的並行化,優化Cube的查詢速度。
kylin的默認設置中
kylin.storage.hbase.min-region-count=1,
kylin.storage.hbase.max-region-count=500,
kylin.storage.hbase.region-cut-gb=5
在實際應用中(根據實際數據量調整),能夠將
kylin.storage.hbase.min-region-count=2,
kylin.storage.hbase.max-region-count=100,
kylin.storage.hbase.region-cut-gb=1
上面設置爲最小爲2個分區,每一個分區大小爲1G,最多設置100個region分區。
[1] Apache Kylin 深刻Cube和查詢優化
http://geek.csdn.net/news/detail/199615
[2] Apache Kylin 維度優化指南
[3] 【技術帖】Apache Kylin Cube優化方式