前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kylin简单优化cube

kylin简单优化cube

作者头像
用户1217611
发布2022-05-06 15:40:37
6940
发布2022-05-06 15:40:37
举报
文章被收录于专栏:文渊之博文渊之博

优化Cube

层次结构

      理论上,对于N维,你最终会得到2 ^ N维组合。但是对于某些维度组,不需要创建这么多组合。例如,如果您有三个维度:洲,国家,城市(在层次结构中,“更大”维度首先出现)。在深入分析时,您只需要以下三种组合组合:

按大陆分组

按大陆,国家分组

按大陆,国家,城市分组

在这种情况下,组合计数从2 ^ 3 = 8减少到3,这是一个很好的优化。 YEAR,QUATER,MONTH,DATE案例也是如此。

派生列

派生列用于一个或多个维度(它们必须是查找表上的维度,这些列称为“派生”)可以从另一个维度推导出来(通常它是相应的FK,这称为“主机列”)

例如,假设我们有一个查找表,我们将其连接到事实表,并将其与“其中DimA = DimX”。请注意,在Kylin中,如果您选择FK为维度,相应的PK将自动排队,无需任何额外费用。秘诀是,由于FK和PK总是相同的,Kylin可以先在FK上应用过滤器/ groupby,然后将它们透明地替换为PK。这表明如果我们想在我们的立方体中使用DimA(FK),DimX(PK),DimB,DimC,我们可以安全地选择DimA,DimB,DimC。

事实表(连接)查找表

column1,column2 ,,,,,, DimA(FK)DimX(PK),, DimB,DimC

假设DimA(代表FK / PK的维度)具有到DimB的特殊映射:

dimA    dimB     dimC
 1       a       ?
 2       b      ?
 3       c       ?
 4       a       ?

在这种情况下,给定DimA中的值,确定DimB的值,因此我们说dimB可以从DimA导出。当我们构建一个包含DimA和DimB的多维数据集时,我们简单地包含DimA,并将DimB标记为派生。派生列(DimB)不参与长方体生成:

原创组合:

ABC,AB,AC,BC,A,B,C

从A到B时的组合:

AC,A,C

在运行时,如果查询类似于“select count(*) from fact_table inner join looup1 group by looup1 .dimB”,则期望包含DimB的长方体来回答查询。但是,由于派生优化,DimB将出现在NONE的长方体中。在这种情况下,我们首先修改执行计划以使其由DimA(其主机列)进行分组,我们将得到如下的中间答案:

 DIMA   COUNT(*)
1         1
2         1
3          1
4          1

之后,Kylin将用DimB值替换DimA值(因为它们的值都在查找表中,Kylin可以将整个查找表加载到内存中并为它们构建映射),并且中间结果变为:

  DimB     count(*)
a                1
b                1
c                1
a                1

在此之后,运行时SQL引擎将进一步将中间结果聚合为:

 DimB    count(*)
a          2
b          1
c          1

这一步发生在查询运行时,这意味着“以额外的运行时聚合为代价”

性能优化

分区列优化

    如果cube的分区列与Hive表的分区列相同,那么根据它过滤数据能让Hive聪明地跳过不匹配的分区。因此强烈建议用Hive的分区列(如果它是日期列)作为cube的分区列。这对于那些数据量很大的表来说几乎是必须的,否则Hive不得不每次在这步扫描全部文件,消耗非常长的时间。

文件合并

    如果启用了Hive的文件合并,你可以在conf/kylin_hive_conf.xml里关闭它,因为Kylin有自己合并文件的方法(下一节):

<property>
    <name>hive.merge.mapfiles</name>
    <value>false</value>
    <description>Disable Hive's auto merge</description>
</property>

重新分发中间表

    Hive在HDFS上的目录里生成了数据文件:有些是大文件,有些是小文件甚至空文件。这种不平衡的文件分布会导致之后的MR任务出现数据倾斜的问题:有些mapper完成得很快,但其他的就很慢。针对这个问题,Kylin增加了这一个步骤来“重新分发”数据,这是示例输出:

total input rows = 159869711
expected input rows per mapper = 1000000
num reducers for RedistributeFlatHiveTableStep = 160

重新分发表的命令:

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计算出中间表的行数,然后基于行数的大小算出重新分发数据需要的文件数。默认情况下,Kylin为每一百万行分配一个文件。在这个例子中,有1.6亿行和160个reducer,每个reducer会写一个文件。在接下来对这张表进行的MR步骤里,Hadoop会启动和文件相同数量的mapper来处理数据(通常一百万行数据比一个HDFS数据块要小)。如果你的日常数据量没有这么大或者Hadoop集群有足够的资源,你或许想要更多的并发数,这时可以将conf/kylin.properties里以下配置设为小一点的数值,比如:

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

其次,Kylin会运行 “INSERT OVERWRITE TABLE … DISTRIBUTE BY “ 形式的HiveQL来分发数据到指定数量的reducer上。在很多情况下,Kylin请求Hive随机分发数据到reducer,然后得到大小相近的文件,分发的语句是”DISTRIBUTE BY RAND()”。

如果你的cube指定了一个高基数的列,比如”USER_ID”,作为”分片”维度(在cube的“高级设置”页面),Kylin会让Hive根据该列的值重新分发数据,那么在该列有着相同值的行将被分发到同一个文件。这比随机要分发要好得多,因为不仅重新分布了数据,并且在没有额外代价的情况下对数据进行了预先分类,如此一来接下来的cube build处理会从中受益。在典型的场景下,这样优化可以减少40%的build时长。在这个案例中分发的语句是”DISTRIBUTE BY USER_ID”:

请注意: 1)“分片”列应该是高基数的维度列,并且它会出现在很多的cuboid中(不只是出现在少数的cuboid)。 使用它来合理进行分发可以在每个时间范围内的数据均匀分布,否则会造成数据倾斜,从而降低build效率。典型的正面例子是:“USER_ID”、“SELLER_ID”、“PRODUCT”、“CELL_NUMBER”等等,这些列的基数应该大于一千(远大于reducer的数量)。 2)”分片”对cube的存储同样有好处,不过这超出了本文的范围。

将cuboid数据转换为HFile

    这一步启动一个MR任务来讲cuboid文件(序列文件格式)转换为HBase的HFile格式。Kylin通过cube统计数据计算HBase的region数目,默认情况下每5GB数据对应一个region。Region越多,MR使用的reducer也会越多。如果你观察到reducer数目较小且性能较差,你可以将“conf/kylin.properties”里的以下参数设小一点,比如:

kylin.hbase.region.cut=2
kylin.hbase.hfile.size.gb=1

rowkey构建

    对rowkey的构建也有一定的要求,一般而言,需要把基数大的字段放在前面,这样可以在scan的过程中尽可能的跳过更多的rowkey。

    另一方面将基数小的列放在rowkey的后面,可以减少构建的重复计算,有些cuboid可以通过一个以上的父cuboid聚合而成,在这种情况下,Kylin将会选择最小的父cuboid。例如,AB能够通过ABC(id:1110)和ABD(id:1101)聚合生成,因此ABD会被作为父cuboid使用,因为它的id比ABC要小。基于以上处理,如果D的基数很小,那么此次聚合操作就会花费很小的代价。因此,当设计cube的rowkey顺序的时候,请记住,将低基数的维度列放在尾部。这不仅对cube的构建过程有好处,而且对cube查询也有好处,因为后聚合(应该是指在HBase查找对应cuboid的过程)也遵循这个规则。

数据转换为HFile

kylin将生成的cube通过生成HFile的方式导入到hbase,这个优化点可以配置hbase的相关参数。

  1. region数量默认是1,如果数据量大的话可以提高region数量
  2. region大小默认是5GB,也就是hbae官方建议的大小;如果cube大小比这个值小太多,可以减小单region的大小
  3. hfile文件大小,默认是1GB,由于是通过mapreduce写入的,小文件意味着写入快,但是读取慢,大文件意味着写入慢,读取快

经验

  1. 尽量将需要展现的字段作为维度,没必要所有的一股脑加进去。
  2. 每次查询或者要经常group by的字段作为Mandatory维度。且该维度放在        rowkey的最前面。
  3. 将数量相近也就是说某两个字段通过select count("字段名")获取的结果近似1:1,设置为joint维度。
  4. rowkey的顺序按查询频率从高到低,从前往后排。
  5. 将经常出现在同一SQL中的不同维度放置在一个维度组中,将从不出现在一个SQL查询中的不同维度设置在不同的维度组中。
  6. Dictionary默认为dict类型,如果某个字段中的值非常大(小幽遇到过的一个字段中的值保存成文本足足有23Kb!!!),大到以至或者可能使得Cube在build过程中出现OOM的错误,则需要将该字段的值设置为fixed_length类型,取可以展现这个维度的前length个字节,比如对于之前那个23kb的字段值,经和业务人员协商,发现取前4000个字节就可以表示这个字段了。所以fixed_length的值设置为4000.值得一提的是,Dictionary默认为false,是不给该字段在内存中建立词典树的,而更改为true则表示给该字段建立词典树。有词典树,则会优化带有该字段的SQL查询,提升查询速度,但相应地也会消耗一些内存。

总结

基于kylin的ui,可以看到kylin在构建cube时各个流程的耗时,可以依据这些耗时做相应的优化,常见的,可以从耗时最长的步骤开始优化,比如:

  1. 遇到创建hive中间表时间很长,考虑对hive表进行分区处理,对表中的文件格式更改,使用orc,parquet等高性能的文件格式
  2. 遇到cube构建时间过长,查看cube设计是否合理,维度的组合关系是否可以再减少,构建引擎是否可以优化

分享一个其他得cube优化设计的推荐:https://www.cnblogs.com/wenBlog/p/10255467.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 优化Cube
    • 层次结构
      • 派生列
      • 性能优化
        • 分区列优化
          • 文件合并
            • 重新分发中间表
              • 将cuboid数据转换为HFile
                • rowkey构建
                  • 数据转换为HFile
                    • 经验
                    • 总结
                    相关产品与服务
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档