Kylin構(gòu)建Cube的過(guò)程1

#.參考鏈接

refer: https://kylin.apache.org/docs20/howto/howto_optimize_build.html
refer:?https://kylin.apache.org/cn/docs/howto/howto_optimize_build.html
refer:?https://kylin.apache.org/cn/docs/tutorial/cube_build_performance.html

1.創(chuàng)建Hive的中間平表

這一步將數(shù)據(jù)從源Hive表提取出來(lái)(和所有join的表一起)并插入到一個(gè)中間平表。如果Cube是分區(qū)的,Kylin會(huì)加上一個(gè)時(shí)間條件以確保只有在時(shí)間范圍內(nèi)的數(shù)據(jù)才會(huì)被提取。你可以在這個(gè)步驟的log查看相關(guān)的Hive命令,比如:

hive -e "USE default;

DROP TABLE IF EXISTS kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34;

CREATE EXTERNAL TABLE IF NOT EXISTS kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34

(AIRLINE_FLIGHTDATE date,AIRLINE_YEAR int,AIRLINE_QUARTER int,...,AIRLINE_ARRDELAYMINUTES int)

STORED AS SEQUENCEFILE

LOCATION 'hdfs:///kylin/kylin200instance/kylin-0a8d71e8-df77-495f-b501-03c06f785b6c/kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34';

SET dfs.replication=2;

SET hive.exec.compress.output=true;

SET hive.auto.convert.join.noconditionaltask=true;

SET hive.auto.convert.join.noconditionaltask.size=100000000;

SET mapreduce.job.split.metainfo.maxsize=-1;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT

AIRLINE.FLIGHTDATE

,AIRLINE.YEAR

,AIRLINE.QUARTER

,...

,AIRLINE.ARRDELAYMINUTES

FROM AIRLINE.AIRLINE as AIRLINE

WHERE (AIRLINE.FLIGHTDATE >= '1987-10-01' AND AIRLINE.FLIGHTDATE < '2017-01-01');

在Hive命令運(yùn)行時(shí),Kylin會(huì)用conf/kylin_hive_conf.properties里的配置,比如保留更少的冗余備份和啟用Hive的mapper side join。需要的話可以根據(jù)集群的具體情況增加其他配置。

如果cube的分區(qū)列(在這個(gè)案例中是”FIGHTDATE”)與Hive表的分區(qū)列相同,那么根據(jù)它過(guò)濾數(shù)據(jù)能讓Hive聰明地跳過(guò)不匹配的分區(qū)。因此強(qiáng)烈建議用Hive的分區(qū)列(如果它是日期列)作為cube的分區(qū)列。這對(duì)于那些數(shù)據(jù)量很大的表來(lái)說(shuō)幾乎是必須的,否則Hive不得不每次在這步掃描全部文件,消耗非常長(zhǎng)的時(shí)間。

如果啟用了Hive的文件合并,你可以在conf/kylin_hive_conf.xml里關(guān)閉它,因?yàn)镵ylin有自己合并文件的方法(下一節(jié)):

<property>

? ? <name>hive.merge.mapfiles</name>

? ? <value>false</value>

? ? <description>Disable Hive's auto merge</description>

</property>

2.重新分發(fā)中間表

在之前的一步之后,Hive在HDFS上的目錄里生成了數(shù)據(jù)文件:有些是大文件,有些是小文件甚至空文件。這種不平衡的文件分布會(huì)導(dǎo)致之后的MR任務(wù)出現(xiàn)數(shù)據(jù)傾斜的問(wèn)題:有些mapper完成得很快,但其他的就很慢。針對(duì)這個(gè)問(wèn)題,Kylin增加了這一個(gè)步驟來(lái)“重新分發(fā)”數(shù)據(jù),這是示例輸出:

total input rows = 159869711

expected input rows per mapper = 1000000

num reducers for RedistributeFlatHiveTableStep = 160

重新分發(fā)表的命令:

hive -e "USE default;

SET dfs.replication=2;

SET hive.exec.compress.output=true;

SET hive.auto.convert.join.noconditionaltask=true;

SET hive.auto.convert.join.noconditionaltask.size=100000000;

SET mapreduce.job.split.metainfo.maxsize=-1;

set mapreduce.job.reduces=160;

set hive.merge.mapredfiles=false;

INSERT OVERWRITE TABLE kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 SELECT * FROM kylin_intermediate_airline_cube_v3610f668a3cdb437e8373c034430f6c34 DISTRIBUTE BY RAND();

"

首先,Kylin計(jì)算出中間表的行數(shù),然后基于行數(shù)的大小算出重新分發(fā)數(shù)據(jù)需要的文件數(shù)。默認(rèn)情況下,Kylin為每一百萬(wàn)行分配一個(gè)文件。在這個(gè)例子中,有1.6億行和160個(gè)reducer,每個(gè)reducer會(huì)寫一個(gè)文件。在接下來(lái)對(duì)這張表進(jìn)行的MR步驟里,Hadoop會(huì)啟動(dòng)和文件相同數(shù)量的mapper來(lái)處理數(shù)據(jù)(通常一百萬(wàn)行數(shù)據(jù)比一個(gè)HDFS數(shù)據(jù)塊要小)。如果你的日常數(shù)據(jù)量沒(méi)有這么大或者Hadoop集群有足夠的資源,你或許想要更多的并發(fā)數(shù),這時(shí)可以將conf/kylin.properties里的kylin.job.mapreduce.mapper.input.rows設(shè)為小一點(diǎn)的數(shù)值,比如:

kylin.job.mapreduce.mapper.input.rows=500000

其次,Kylin會(huì)運(yùn)行?“INSERT OVERWRITE TABLE … DISTRIBUTE BY “?形式的HiveQL來(lái)分發(fā)數(shù)據(jù)到指定數(shù)量的reducer上。

在很多情況下,Kylin請(qǐng)求Hive隨機(jī)分發(fā)數(shù)據(jù)到reducer,然后得到大小相近的文件,分發(fā)的語(yǔ)句是”DISTRIBUTE BY RAND()”。

如果你的cube指定了一個(gè)高基數(shù)的列,比如”USER_ID”,作為”分片”維度(在cube的“高級(jí)設(shè)置”頁(yè)面),Kylin會(huì)讓Hive根據(jù)該列的值重新分發(fā)數(shù)據(jù),那么在該列有著相同值的行將被分發(fā)到同一個(gè)文件。這比隨機(jī)要分發(fā)要好得多,因?yàn)椴粌H重新分布了數(shù)據(jù),并且在沒(méi)有額外代價(jià)的情況下對(duì)數(shù)據(jù)進(jìn)行了預(yù)先分類,如此一來(lái)接下來(lái)的cube build處理會(huì)從中受益。在典型的場(chǎng)景下,這樣優(yōu)化可以減少40%的build時(shí)長(zhǎng)。在這個(gè)案例中分發(fā)的語(yǔ)句是”DISTRIBUTE BY USER_ID”:

請(qǐng)注意: 1)“分片”列應(yīng)該是高基數(shù)的維度列,并且它會(huì)出現(xiàn)在很多的cuboid中(不只是出現(xiàn)在少數(shù)的cuboid)。 使用它來(lái)合理進(jìn)行分發(fā)可以在每個(gè)時(shí)間范圍內(nèi)的數(shù)據(jù)均勻分布,否則會(huì)造成數(shù)據(jù)傾斜,從而降低build效率。典型的正面例子是:“USER_ID”、“SELLER_ID”、“PRODUCT”、“CELL_NUMBER”等等,這些列的基數(shù)應(yīng)該大于一千(遠(yuǎn)大于reducer的數(shù)量)。 2)”分片”對(duì)cube的存儲(chǔ)同樣有好處,不過(guò)這超出了本文的范圍。

3.提取事實(shí)表的唯一列

在這一步驟Kylin運(yùn)行MR任務(wù)來(lái)提取使用字典編碼的維度列的唯一值。

實(shí)際上這步另外還做了一些事情:通過(guò)HyperLogLog計(jì)數(shù)器收集cube的統(tǒng)計(jì)數(shù)據(jù),用于估算每個(gè)cuboid的行數(shù)。如果你發(fā)現(xiàn)mapper運(yùn)行得很慢,這通常表明cube的設(shè)計(jì)太過(guò)復(fù)雜,請(qǐng)參考

優(yōu)化cube設(shè)計(jì)來(lái)簡(jiǎn)化cube。如果reducer出現(xiàn)了內(nèi)存溢出錯(cuò)誤,這表明cuboid組合真的太多了或者是YARN的內(nèi)存分配滿足不了需要。如果這一步從任何意義上講不能在合理的時(shí)間內(nèi)完成,你可以放棄任務(wù)并考慮重新設(shè)計(jì)cube,因?yàn)槔^續(xù)下去會(huì)花費(fèi)更長(zhǎng)的時(shí)間。

你可以通過(guò)降低取樣的比例(kylin.job.cubing.inmen.sampling.percent)來(lái)加速這個(gè)步驟,但是幫助可能不大而且影響了cube統(tǒng)計(jì)數(shù)據(jù)的準(zhǔn)確性,所有我們并不推薦。

4.構(gòu)建維度字典

有了前一步提取的維度列唯一值,Kylin會(huì)在內(nèi)存里構(gòu)建字典(在下個(gè)版本將改為MapReduce任務(wù))。通常這一步比較快,但如果唯一值集合很大,Kylin可能會(huì)報(bào)出類似“字典不支持過(guò)高基數(shù)”。對(duì)于UHC類型的列,請(qǐng)使用其他編碼方式,比如“fixed_length”、“integer”等等。

5.保存cuboid的統(tǒng)計(jì)數(shù)據(jù)和創(chuàng)建 HTable

這兩步是輕量級(jí)和快速的。

6.構(gòu)建基礎(chǔ)cuboid

這一步用Hive的中間表構(gòu)建基礎(chǔ)的cuboid,是“逐層”構(gòu)建cube算法的第一輪MR計(jì)算。Mapper的數(shù)目與第二步的reducer數(shù)目相等;Reducer的數(shù)目是根據(jù)cube統(tǒng)計(jì)數(shù)據(jù)估算的:默認(rèn)情況下每500MB輸出使用一個(gè)reducer;如果觀察到reducer的數(shù)量較少,你可以將kylin.properties里的“kylin.job.mapreduce.default.reduce.input.mb”設(shè)為小一點(diǎn)的數(shù)值以獲得過(guò)多的資源,比如:

kylin.job.mapreduce.default.reduce.input.mb=200

7.構(gòu)建N維cuboid

這些步驟是“逐層”構(gòu)建cube的過(guò)程,每一步以前一步的輸出作為輸入,然后去掉一個(gè)維度以聚合得到一個(gè)子cuboid。舉個(gè)例子,cuboid ABCD去掉A得到BCD,去掉B得到ACD。

有些cuboid可以從一個(gè)以上的父cuboid聚合得到,這種情況下,Kylin會(huì)選擇最小的一個(gè)父cuboid。舉例,AB可以從ABC(id:1110)和ABD(id:1101)生成,則ABD會(huì)被選中,因?yàn)樗谋華BC要小。在這基礎(chǔ)上,如果D的基數(shù)較小,聚合運(yùn)算的成本就會(huì)比較低。所以,當(dāng)設(shè)計(jì)rowkey序列的時(shí)候,請(qǐng)記得將基數(shù)較小的維度放在末尾。這樣不僅有利于cube構(gòu)建,而且有助于cube查詢,因?yàn)轭A(yù)聚合也遵循相同的規(guī)則。

通常來(lái)說(shuō),從N維到(N/2)維的構(gòu)建比較慢,因?yàn)檫@是cuboid數(shù)量爆炸性增長(zhǎng)的階段:N維有1個(gè)cuboid,(N-1)維有N個(gè)cuboid,(N-2)維有N*(N-1)個(gè)cuboid,以此類推。經(jīng)過(guò)(N/2)維構(gòu)建的步驟,整個(gè)構(gòu)建任務(wù)會(huì)逐漸變快。

8.構(gòu)建cube

這個(gè)步驟使用一個(gè)新的算法來(lái)構(gòu)建cube:“逐片”構(gòu)建(也稱為“內(nèi)存”構(gòu)建)。它會(huì)使用一輪MR來(lái)計(jì)算所有的cuboids,但是比通常情況下更耗內(nèi)存。配置文件”conf/kylin_job_inmem.xml”正是為這步而設(shè)。默認(rèn)情況下它為每個(gè)mapper申請(qǐng)3GB內(nèi)存。如果你的集群有充足的內(nèi)存,你可以在上述配置文件中分配更多內(nèi)存給mapper,這樣它會(huì)用盡可能多的內(nèi)存來(lái)緩存數(shù)據(jù)以獲得更好的性能,比如:

<property>

? ? <name>mapreduce.map.memory.mb</name>

? ? <value>6144</value>

? ? <description></description>

</property>

<property>

? ? <name>mapreduce.map.java.opts</name>

? ? <value>-Xmx5632m</value>

? ? <description></description>

</property>

請(qǐng)注意,Kylin會(huì)根據(jù)數(shù)據(jù)分布(從cube的統(tǒng)計(jì)數(shù)據(jù)里獲得)自動(dòng)選擇最優(yōu)的算法,沒(méi)有被選中的算法對(duì)應(yīng)的步驟會(huì)被跳過(guò)。你不需要顯式地選擇構(gòu)建算法。

9.將cuboid數(shù)據(jù)轉(zhuǎn)換為HFile

這一步啟動(dòng)一個(gè)MR任務(wù)來(lái)講cuboid文件(序列文件格式)轉(zhuǎn)換為HBase的HFile格式。Kylin通過(guò)cube統(tǒng)計(jì)數(shù)據(jù)計(jì)算HBase的region數(shù)目,默認(rèn)情況下每5GB數(shù)據(jù)對(duì)應(yīng)一個(gè)region。Region越多,MR使用的reducer也會(huì)越多。如果你觀察到reducer數(shù)目較小且性能較差,你可以將“conf/kylin.properties”里的以下參數(shù)設(shè)小一點(diǎn),比如:

kylin.hbase.region.cut=2

kylin.hbase.hfile.size.gb=1

如果你不確定一個(gè)region應(yīng)該是多大時(shí),聯(lián)系你的HBase管理員。

10.將HFile導(dǎo)入HBase表

這一步使用HBase API來(lái)講HFile導(dǎo)入region server,這是輕量級(jí)并快速的一步。

11.更新cube信息

在導(dǎo)入數(shù)據(jù)到HBase后,Kylin在元數(shù)據(jù)中將對(duì)應(yīng)的cube segment標(biāo)記為ready。

12.清理資源

將中間寬表從Hive刪除。這一步不會(huì)阻塞任何操作,因?yàn)樵谇耙徊絪egment已經(jīng)被標(biāo)記為ready。如果這一步發(fā)生錯(cuò)誤,不用擔(dān)心,垃圾回收工作可以晚些再通過(guò)Kylin的StorageCleanupJob完成。

#

refer:https://kylin.apache.org/docs20/howto/howto_optimize_build.html


refer:https://kylin.apache.org/docs20/howto/howto_optimize_build.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。