本文已参与「开源摘星计划」,欢迎正在阅读的你加入。活动链接:github.com/weopenproje…
使用的Apache Kylin版本
2.6.5 或 3.0.1
说明
本文为结合了官方文档以及个人理解总结到的经验,还请辩证看待。
如果与官方文档有歧义,建议以官方文档为准。
贴一下官方文档连接:Apache Kylin | 优化 Cube 构建
正文开始
构建步骤:Create Intermediate Flat Hive Table [创建Hive的中间平表]
这一步是将数据从源Hive表提取出来(和所有join的表一起)并插入到一个中间平表。如果是增量构建,kylin在构建这一步时会加一个时间条件以确保只有在时间范围内的数据才会被提取。在Hive命令运行时,Kylin会用conf/kylin_hive_conf.properties里的配置,比如保留更少的冗余备份和启用Hive的mapper side join。需要的话可以根据集群的具体情况增加其他配置。这一步执行的Hive命令,可以在日志中查看,示例如下:
//为提高可读性,代码块中有部分省略内容,用......表示。
Create and distribute table, cmd:
hive -e "USE kylin_db;
DROP TABLE IF EXISTS kylin_intermediate_app_mail_record_cube_15e19706_a550_db14_ce7e_63a7a0625f75;
CREATE EXTERNAL TABLE IF NOT EXISTS kylin_intermediate_app_mail_record_cube_15e19706_a550_db14_ce7e_63a7a0625f75 ......
INSERT OVERWRITE TABLE \`kylin_intermediate_app_mail_record_cube_15e19706_a550_db14_ce7e_63a7a0625f75\` SELECT \`APP_MAIL_RECORD\`.\`MAIL_BH\` as \`APP_MAIL_RECORD_MAIL_BH\`
......
,\`APP_MAIL_RECORD\`.\`DT\` as \`APP_MAIL_RECORD_DT\` WHERE 1=1 AND (\`APP_MAIL_RECORD\`.\`DT\` >= '20200613' AND \`APP_MAIL_RECORD\`.\`DT\` < '20200614') ;
......
优化点:
- 如果是增量构建,那么源Hive表中必须有一个日期字段,而且最好是分区字段。这个日期字段是分区字段的好处就是避免Hive进行全表扫描,节约这一步的执行时间。
- 如果启用了Hive的文件合并,你可以在conf/kylin_hive_conf.xml里关闭它,因为Kylin有自己合并文件的方法。如下:
<property>
<name>hive.merge.mapfiles</name>
<value>false</value>
</property>
<property>
<name>hive.merge.mapredfiles</name>
<value>false</value>
</property>
构建步骤:Redistribute Flat Hive Table [重新分发Hive中间表]
在之前的一步之后,Hive在HDFS上的目录里生成了数据文件:有些是大文件,有些是小文件甚至空文件。这一步主要目的重新调整文件分布,减少后续MapReduce任务出现数据倾斜的可能性。这一步执行的Hive命令,可以在日志中查看,示例如下:
//为提高可读性,代码块中有部分省略内容,用......表示。
......
hive -e "USE kylin_db;
set mapreduce.job.reduces=1;
set hive.merge.mapredfiles=false;
INSERT OVERWRITE TABLE \`kylin_intermediate_app_mail_record_cube_15e19706_a550_db14_ce7e_63a7a0625f75\` SELECT * FROM \`kylin_intermediate_app_mail_record_cube_15e19706_a550_db14_ce7e_63a7a0625f75\` DISTRIBUTE BY APP_MAIL_RECORD_DABH,APP_MAIL_RECORD_ZJHM,APP_MAIL_RECORD_LXRZJHM;
......
优化点:
- 在cube设计中,Rowkeys的排序至关重要。合理的排序不仅会减少构建时间,还会减少查询时间。原则:常用过滤维度在前,高基维度在前。
构建步骤:Extract Fact Table Distinct Columns [提取事实表唯一列]
在这一步骤Kylin运行MR任务来提取使用字典编码的维度列的唯一值。还有,通过HyperLogLog计数器收集cube的统计数据,用于估算每个cuboid的行数。
优化点:
- 如果cube中存在count distinct计算,并且统计的值很大(亿级),那么这一步不会太快。
- 查看MR日志,如果mapper运行特别慢,通常表明cube设计的太复杂,建议优化cube设计。还有个办法是可以通过降低取样的比例(kylin.job.cubing.inmen.sampling.percent)来加速这个步骤,但是帮助可能不大而且影响了cube统计数据的准确性,并不推荐。
构建步骤:Build Dimension Dictionary [构建维度字典]
基于上一步的结果,kylin会在内存中构建字典。通常比较快,速度受唯一值的基数影响。
优化点:
- 如果唯一值集合很大,Kylin可能会报出类似“字典不支持过高基数”。对于UHC类型的列,请使用其他编码方式,比如“fixed_length”、“integer”。
构建步骤:Save Cuboid Statistics [保存cuboid的统计数据]
轻量级、很快。
构建步骤:Create HTable [创建HTable]
这一步同样轻量级、很快。
构建步骤:Build Base Cuboid [构建基础cuboid]
这一步用Hive的中间表构建基础的cuboid,是“逐层”构建cube算法的第一轮MR计算。Mapper的数目与第二步的reducer数目相等;Reducer的数目是根据cube统计数据估算的:默认情况下每500MB输出使用一个reducer;
优化点:
- 如果观察到reducer的数量较少,你可以将kylin.properties里的“kylin.job.mapreduce.default.reduce.input.mb”设为小一点的数值以获得过多的资源,比如:kylin.job.mapreduce.default.reduce.input.mb=200 注意:这个配置是全局配置,所有cube共享。
构建步骤:Build N-Dimension Cuboid [构建N维cuboid]
这一步在实际cube构建过程中会有N步(由cube的设计决定),这些步骤逻辑是一样的,根据上一步的结果“逐层”构建cuboid,每一步以前一步的输出作为输入,然后去掉一个维度以聚合得到一个子cuboid。比如下图“邮件分析CUBE”(APP_MAIL_RECORD_CUBE)中, cuboid 1是全维度组合(也就是上一步 Build Base Cuboid的结果),cuboid 2是由cuboid 1去掉一些维度("cuboid 2 维度"中字体为灰色的维度)得到的,之后的每一层构建原理都类似。可以在下图中看到,除了Base Cuboid以外,一共有7个层级(除了中间cuboid之外,外边一共7层)。所以在“邮件分析CUBE”中这一步实际被分为了7个步骤(level1->level7)执行。
通常情况下,从N维到(N/2)维的构建相对来说比较慢,因为这是cuboid数量爆炸性增长的阶段,经过(N/2)维构建的步骤,整个构建任务又会逐渐变快。比如下图所示,现在base cuboid为ABCD四个维度,那么理论上有(2^4-1=15)个cuboid,level-1到level-2逐渐变慢,level-2构建应该是最慢的,之后又会变快。
构建步骤:Build Cube In-Mem [内存构建cube]
这个步骤使用一个新的算法来构建cube,它会使用一轮MR来计算所有的cuboids,但是比通常情况下更耗内存。注意,Kylin会根据数据分布(从cube的统计数据里获得)自动选择最优的算法,没有被选中的算法对应的步骤会被跳过。你不需要显式地选择构建算法。
优化点:
- 这一步不一定会启用,如果用到了这一步,配置文件”conf/kylin_job_inmem.xml”正是为这步而设。默认情况下它为每个mapper申请3GB内存。如果集群有充足的内存,可以在上述配置文件中分配更多内存给mapper,这样它会用尽可能多的内存来缓存数据以获得更好的性能,比如:
<property>
<name>mapreduce.map.memory.mb</name>
<value>6144</value>
</property>
<property>
<name>mapreduce.map.java.opts</name>
<value>-Xmx5632m</value>
<description></description>
</property>
构建步骤:Convert Cuboid Data to HFile [将cuboid转换为HFile]
这一步kylin会使用MR任务来将cuboid文件转换为HBase的HFile格式。Kylin通过cube统计数据计算HBase的region数目,默认情况下每5GB数据对应一个region。Region越多,MR使用的reducer也会越多。
优化点:
- 如果reducer数目较小且性能较差,你可以将“conf/kylin.properties”里的以下参数设小一点(设置时一定要考虑HBase中region的大小),比如:
kylin.hbase.region.cut=2
kylin.hbase.hfile.size.gb=1
构建步骤:Load HFile to HBase Table [将HFile导入HBase表]
这一步使用HBase API来将HFile导入region server,通常是轻量级并快速的一步,取决于网络、数据量、等等。
构建步骤:Update Cube Info [更新cube信息]
在导入数据到HBase后,Kylin在元数据中将对应的cube segment标记为ready。通常非常快。这一步完成之后,cube数据已经可以通过kylin查询、使用。即便是之后出错,也不会影响本次构建数据的使用。
构建步骤:Hive Cleanup [清理Hive中剩余的无用资源]
主要将中间宽表从Hive删除。如果这一步出错可以手动清理,不会影响本次构建数据的使用。
构建步骤:Garbage Collection on HDFS [HDFS上的垃圾回收]
主要是HDFS上一些垃圾的清理,包括:清理提取出来的事实表中的唯一列数据、清理cuboid转换为HFile的文件等等。
注意:
-
截止到当前版本(Kylin 2.6.5或Kylin 3.0.1)Kylin在构建步骤中做的垃圾清理并不完善,需要定期做离线的垃圾清理。
其他
上面是Kylin相关的构建步骤、原理和构建步骤中涉及的一些优化内容。除此之外,从上面的原理中看到,Kylin构建中使用了很多Hive、Spark任务。所以,HDP/CDH平台的性能对Kylin构建速度有着至关重要的影响。