去年12月挖的坑,今天找時間填上。update:20190119
一、kylin架構
核心是預計算,在此架構上做了一些優化。計算結果存儲在Hbase,對Hive等查詢轉換為Hbase的Scan,提高速度。
缺點亦明顯,先天沒有AD-HOC能力
二、kylin高可用部署
Kylin的每個結點都可以部署為Job節點(build cube用)兼查詢節點。並且每個節點之間對等。因此只要前面加個Nginx做請求轉發即可。
Kylin支持通過增加節點水平擴容。
三、kylin on hbase vs kylin on druid
目前的 Kylin 數據存儲使用 HBase,存儲 Cube 時將維度值和度量值轉換成 HBase 的 KeyValue。因為 HBase 不支持二級索引,只有一個行鍵 (RowKey) 索引,Kylin 的維度值會按照固定的順序拼接作為 RowKey 存儲,那么排在 RowKey 前面的維度,就會獲得比后面的維度更好的過濾性能。
也就是說排在rowkey后面的維度查詢,效率極低,因為需要scan Hbase的行數非常大,Druid可以解決這個問題。
其特點:
1)數據實時流入,毫秒級延遲即可查詢。與ES有些像?
2)支持倒排索引,具有良好的過濾性能。(Hbase只支持一級索引,導致rowkey后面的維度過濾性能差)
這是其較於 Kylin On Hbase最重要的優勢。
四、rowkey設計優化
直接貼結論:
1)查詢頻率高的維度在前
2)基數大的維度在前
兩者沖突時,暫時沒想明白。
五、維度優化
為什么需要維度優化
因為如果不進行任何維度優化,直接將所有的維度放在一個聚集組里,Kylin就會計算所有的維度組合(cuboid)。
比如,有12個維度,Kylin就會計算2的12次方即4096個cuboid,實際上查詢可能用到的cuboid不到1000個,甚至更少。 如果對維度不進行優化,會造成集群計算和存儲資源的浪費,也會影響cube的build時間和查詢性能,所以我們需要進行cube的維度優化。
聚集組
聚集組:用來控制哪些cuboid需要計算。
適用場景:不是只需要計算base cuboid的情況下,都需要聚集組。
注意事項:一個維度可以出現在多個聚集組中,但是build期間只會計算一次。
如果不設置聚集組,默認情況下只會計算 base cuboid。
聚集組不宜太多。
衍生維度
衍生維度:維表中可以由主鍵推導出值的列可以作為衍⽣維度。
使用場景:以星型模型接入時。例如用戶維表可以從userid推導出用戶的姓名,年齡,性別。
優化效果:維度表的N個維度組合成的cuboid個數會從2的N次方降為2。
強制維度
強制維度:所有cuboid必須包含的維度,不會計算不包含強制維度的cuboid。
適用場景:可以將確定在查詢時一定會使用的維度設為強制維度。例如,時間維度。
優化效果:將一個維度設為強制維度,則cuboid個數直接減半。
層次維度
層次維度:具有一定層次關系的維度。
使用場景:像年,月,日;國家,省份,城市這類具有層次關系的維度。
優化效果:將N個維度設置為層次維度,則這N個維度組合成的cuboid個數會從2的N次方減少到N+1。
聯合維度
聯合維度:將幾個維度視為一個維度。
適用場景: 1 可以將確定在查詢時一定會同時使用的幾個維度設為一個聯合維度。
2 可以將基數很小的幾個維度設為一個聯合維度。
3 可以將查詢時很少使用的幾個維度設為一個聯合維度。
優化效果:將N個維度設置為聯合維度,則這N個維度組合成的cuboid個數會從2的N次方減少到1。
Extended Column
在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。
另外需要提一個分片維度,集群目前用錯了:
分片維度
Cube支持在構建階段進行分片以提高效率,可以並只可以將一個維度設為分片(shard by)維度(注意分片維度和cube的partition維度不同,前者作用於構建階段,后者是用於分割時間段以支持增量構建)。Cube build第二步需要將中間表的數據重新分布到HDFS各個節點上,默認的partition方式是隨機,如果指定了分片維度,則改為使用分片維度進行partition。重新分布數據的意義在於防止中間表文件大小相差太大造成數據傾斜,因此分片維度應該是高基數列以保證分片的粒度足夠小,可以較為均勻地分布到各個節點上,這能大大加速之后的MapReduce任務。
六、優化實踐
優化
1,shop_id維度,由dict編碼改為integer編碼。is_pre_order修改為boolean編碼。
2,前面理解錯了partition的含義,它與Hive里面的Partition不同。用於build cube時中間表的HDFS分布,因此粒度超小越好,數據傾斜的可能越小,因此由dt->shop_id
3,Hbase存了太多的表?會不會因為metadata多影響效率?是否可以優化?Merge后自動刪除之?什么情況不適應merge?待討論。
4,設置shop_id, dt為必選維度,減小cube大小以及build時間。
5,hbase表,hive中間表,job中間數據使用snappy壓縮,cpu換內存IO ——已經做了
6,Kylin On Druid?目前看還不需要,目前的表及維度查詢實際並沒達到觸發Hbase的瓶頸問題。
七、Hybird模式
修改維度后,查詢向前兼容,適用不能重新build舊的數據的情況(可能因為數據太多,build時間太久不可操作,可能由於舊原始數據已經遺失)
例:
原先維度shop_id、dt, 現新增一個維度is_pre_order。
在20190119這天做的cube維度修改。
則以后查詢:
1)sql含有is_pre_order且日期>20190119,則自動路由到含is_pre_order dm的新cube。
2)sql含有is_pre_order但日期<= 20190119,則返回空數據。
3)若sql不含is_pre_order,可查所有日期,<=20190119路由到舊的cube,>20190119路由到新的cube。
也就是Hybird使新增dim不需要重新更換cube,dim的修改對用戶透明,用戶查詢代碼不需要任何改動。