赞
踩
Kylin目前作为公司离线OLAP的核心组件,在线上稳定运行已经一年之久,在这之间遇见过各种问题:比如查询慢、cube构建不出来等等;遇到诸如此类的问题时候,通常需要对cube进行调优,而对于cube的各个构建步骤的理解是作为cube调优过程中的必备技能之一,本篇文章将从cube的构建步骤出发,结合原理来谈谈在各构建步骤的cube优化该如何抉择
创建Hive的临时平表
作为构建的第一步,Kylin从Hive中将源数据抽取出来并插入到一张临时创建的表中
后续的处理将以这张表为输入,待cube构建完成后,再将其删除
抽取时只会选择cube模型中用到的列,如果模型是按某个日期/时间列做分区的,还会将时间条件应用在创建平表的Hive命令中
下面是一个创建Hive平表的示例语句,可以通过kylin web ui的monitor界面进行查看:
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将抽取出的数据生成在指定的HDFS目录下
我们仔细观察后可以发现,有的文件比较大,有的文件比较小甚至是空的
文件大小的不均衡,会导致后续的MR任务也不均衡:
这样就会形成“木桶效应”,为消除这种不均衡,Kylin需要对临时表的数据做一次重新分布,希望借助这次重分布使得文件块的大小适中且基本一样大,根本原理是通过DISTRIBUTE BY 来解决的
下面是一个重分布数据的例子:
total input rows = 159869711 expected input rows per mapper = 1000000 num reducers for RedistributeFlatHiveTableStep = 160 Redistribute table, cmd: 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是通过查询Hive获得临时表的行数,基于此行数计算出需要重分布的文件块数量
默认情况下kylin会为每100万行数据分配一个文件:
每个文件100万行的配置是一个经验值;实际的设置需要预估每条业务线的数据量来决定的
可以通过在conf/kylin.properties中设置特定参数,如:kylin.job.mapreduce.mapper.input.rows=500000
多数情况下,Kylin会让Hive随机地重分布数据,因此我们也可以看到重分布语句是
DISTRIBUTE BY RAND();因为是随机的,它会让最终的数据分布的非常均匀,且毫无规律
当然,我们也可以通过指定字段来进行数据的重分布,只需要在RowKey设计界面时,对需要指定的字段选择Shard By即可,值得注意的是此列需要是一个高基数列:
高基数可以理解为对维度count distinct之后获取的值,该值越高,则基数越高
按高基数维度列做重分布的好处是,具有相同此列值的行,将被写到同一个分片当中去
这样就非常利于后续的聚合计算:大量的聚合在本地完成(可以理解为combine),减少了数据的交叉传递
在一个典型场景中,这一优化使得cube构建的时间减少了40%。
设置高基数维度列时的注意点:
按高基数维度进行分片会提高查询速度的原理:
抽取各维度不同的值
在此步骤中kylin会启动一个mapreduce任务来获取各个维度在临时表中出现的不同值,用于构建维度字典
实际上该步骤做了更多事情:
在这一步中如果发现map任务非常慢,通常就说明cube的设计会有问题:
在这一步中如果发现reduce任务总是报OutOfMemory 错误:
当然我们还可以通过修改配置来降低此步的数据采样率,从而使得整个cube的构建效率提升,但并不推荐这样做因为它会降低cube统计的准确性
Too high cardinality is not suitable for dictionary
的信息,建议用户对超高基数维度采用非字典编码,如fixed_length、integer等此任务的map数等于步骤2的reduce数量
此任务的reduce数量是基于cube统计出的此任务的output大小而估算的:
kylin.job.mapreduce.default.reduce.input.mb=200
构建N维的Cuboid
这是逐层cube构建的其它轮当中的mapreduce任务,每一轮以上一轮的输出为输入,然后减去一个维度生成新的组合,并在reduce中聚合以生成子cuboid
有些维度组合可以从多个父亲组合来生成,在这种情况下,Kylin会选择ID值“最小”的那个父亲组合来生成:
例如,组合AB可以从ABC(id: 1110)生成,也可以从ABD(id: 1101)生成,由于1101 < 1110, 所以ABD会被用来生成AB
基于此规则,如果维度D的基数很小,那么此时的聚合量将会很少,也就更加高效
cuboid生成树:
因此,当我们在设计cube的时候,在高级设置页面,请将低基数维度尽量拖动放置在高基数维度的后面;这个原则不仅会使得cube构建更快,也会使得查询时的后聚合性能更好:
通常从N-维到 (N/2)-维的计算比较慢,因为这是一个数据爆炸的过程(可以通过cuboid生成树来进行理解):
生成HFile
此步骤启动一个mapreduce任务,将前面计算好的cuboid文件(sequence文件格式)转换成HBase的HFile
Kylin会根据cube统计信息,计算并预先分配好region:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。