原文地址:https://kylin.apache.org/docs16/howto/howto_optimize_build.html

Kylin将一个cube的build过程分解为若干个子步骤,然后串行执行这些子步骤。这些步骤包括Hive操作,MR任务和其他类型的工作。如果每天都有许多cube进行build操作,那么肯定会办法加速这一过程。这里有一些建议可以参考,我们就按照build的顺序依次介绍。

Create Intermediate Flat Hive Table

该步骤会从源Hive表中抽取数据(将所有的相关表join之后的数据),并且插入到一个临时的扁平表中。如果cube是带有分区列的,Kylin将会增加一个时间条件,这样就会保证只有符合条件的数据才会被抓取。可以在日志中查看与该步骤相关的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');
"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

当执行Hive命令的时候,Kylin会使用conf/kylin_hive_conf.xml中的配置项,例如,使用更少的副本数和允许Hive的mapper连接操作。如果有需要的话,也可以添加其他的配置项。

如果Cube的分区列(这里是“FLIGHTDATE ”)与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>
  • 1
  • 2
  • 3
  • 4
  • 5

Redistribute intermediate table

经过上一个步骤之后,Hive会在HDFS的目录中生成一些数据文件,但是一些文件可能会很大,而另外一些文件可能会很小甚至是空的。文件大小分布的不均衡也会导致后续的MR任务执行的不平衡:一些mapper任务会执行的很快,而其他的mapper可能会执行的很慢。为了使这些数据分布的更均匀一些,Kylin增加了该步骤用来重新分配各个数据文件中的数据。下面是一个简单的输出:

total input rows = 159869711
expected input rows per mapper = 1000000
num reducers for RedistributeFlatHiveTableStep = 160
  • 1
  • 2
  • 3

重分配数据之后执行的Hive命令如下所示:

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();
"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

首先,Kylin会获取临时表的行数;然后,基于这个行数就可以获取需要进行数据重分配的文件的数量。Kylin默认一个文件包含1百万行的数据。在这个例子中,一共有1.6亿行数据和160个reducer,并且每个reducer写一个文件。在后续的MR步骤中,Hadoop将会启动相同数量的mapper来对这些文件进行处理(通常1百万行数据的大小会比一个HDFS块要小)。如果日常的数据规模不是很大或者Hadoop集群有足够的资源,可以通过在“conf/kylin.properties”中将配置项“kylin.job.mapreduce.mapper.input.rows”设置为更小的值来获取更高的并发度,如下所示:

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

其次,Kylin通过运行一个HiveQL “INSERT OVERWIRTE TABLE … DISTRIBUTE BY …” 来为指定数目的reducer重新分配数据行。

在大多数情况下,Kylin会要求Hive随机地为这些reducer重新分配数据行,以保证这些文件在大小上相近。此时,重分配语句就是 “DISTRIBUTE BY RAND()”

如果Cube中确定了一个“shard by”维度列(在Cube的“Advanced setting”界面进行设置),该维度列是一个基数很大的维度列(例如“USER_ID”),那么Kylin会要求Hive通过该维度列的值来重新分配数据。对于该列拥有相同值的数据行将会被分配在同一个文件中。这比随机分配要好,因为数据不仅被重新分配了,而且在没有消耗额外成本的情况下就对数据进行了重新分类,这对于后续的Cube构建过程是有帮助的。在特定的情况下,这种优化可以减少40%的构建时间。这种情况下的重分配语句就是 “DISTRIBUTE BY USER_ID”

请注意:
1.设置为“shard by”的维度列应该是一个基数很大的维度列,并且它会出现在很多cuboid中(不会是仅仅出现在很少的cuboid中)。使用它进行重分配可能会在每一个时间间隔上获得等分布;反之则会造成数据倾斜,而这则会减少构建速度。典型的适合情景就是:“USER_ID”,“SELLER_ID”,“PRODUCT”,“CELL_NUMBER”等等,一般基数应该大于1000(应该远远大于reducer的数目)。
2.使用“shard by”在Cube存储中还有其他的优势,但不在本文的讨论范围中。

Extract Fact Table Distinct Columns

在此步骤中,Kylin通过运行一个MR任务来获取维度列的distinct值,用于进行字典编码。

实际上,该步骤还做了其他的工作:通过使用HyperLogLog计数器预估每个cuboid的行数,依次来收集cube的统计信息。如果你发现mapper任务执行非常慢,通过就意味着cube设计的太复杂,可以参考:Cube设计优化,对cube进行优化,使cube更加精简。如果reducer发生了OOM错误,通常意味着cuboid的维度组合数太多或者默认的yarn内存分配不能满足需求。如果此步骤不能在合理的时间内完成,请重新对cube进行设计,因为真正的build过程会花费更长的时间。

你可以减少采样比例(通过在kylin.properties中设置kylin.job.cubing.inmem.sampling.percent配置项),来加速该步骤的执行,但是这可能不会有太大的效果,而且还会影响cube统计信息的准确性,因此一般不推荐这么做。

Build Dimension Dictionary

在上一步中已经获得了所有维度列的distinct值,接着Kylin将会在内存中构建字典(在下个版本中将会将此操作移到MR任务中)。通常这一步会很快,但是如果distinct值的集合很大,Kylin可能会报错,例如,“Too high cardinality is not suitable for dictionary”。对于UHC(超大容量)列,请使用其他编码方式,例如“fixed_length”,“integer”等。

Save Cuboid Statistics and Create HTable

这两个步骤是轻量级的,并且很快。

Build Base Cuboid

这一步是通过临时表构建基本的cuboid,这是逐层算法的第一轮MR任务。Mapper的数量等于步骤二中reducer的数量;而Reducer(这里指的是本步骤中启动的reducer)的数量是通过cube的统计信息预估出来的:默认每500M使用一个reducer。如果你发现reducer的数目很少,可以通过在kylin.properties中对配置项“kylin.job.mapreduce.default.reduce.input.mb”设置更小的值,来获取更多的集群资源,如下所示:
kylin.job.mapreduce.default.reduce.input.mb=200

Build N-Dimension Cuboid

这些步骤是逐层算法的处理过程,每一步都使用前一步的输出作为输入,然后去除某个维度进行聚合,生成一个子cuboid。例如,对于cuboid ABCD,去除维度A可以获得cuboid BCD,去除维度B可以获得cuboid ACD等。

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

通常从N-D到(N/2)-D的构建过程很慢,因为这是一个cuboid爆炸增长的过程:N-D有1个cuboid,(N-1)-D有N个cuboid,(N-1)-D有N*(N-1)个cuboid等等。在(N/2)-D步骤之后,构建过程会越来越快。

Build Cube

这一步骤使用了一种新的算法来构建cube:逐块算法(也称作“in-mem”算法)。该算法只使用一轮MR任务来构建所有的cuboid,但它比逐层算法需要更多占用更多的内存。该步骤在执行的时候会使用“conf/kylin_job_conf_inmem.xml”中的相关配置项。默认情况下,每个mapper需要3G的内存。如果集群有足够大的内存,可以在“conf/kylin_job_conf_inmem.xml”中通过修改配置来获取更大的内存,这样就可以处理更多的数据,并且性能也会更好。修改配置如下所示:

<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

请注意,Kylin会根据数据分布(通过cube统计信息获取)自动地选择合适的cube构建算法。一般不需要显示地选择使用哪个算法。

Convert Cuboid Data to HFile

这一步会启动一个MR任务用来将cuboid文件(顺序文件格式)转换为Hbase的HFile文件。Kylin通过cube的统计信息来计算HBase的region个数,默认每个region大小是5G。Region数越多,就会使用更多的reducer。如果发现reducer的数目很少,并且性能很差,就可以在“conf/kylin.properties”中增加如下配置项:

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

如果不能确定一个HBase的region该设置为多大,请联系HBase管理员。

Load HFile to HBase Table

这一步使用了HBase API将HFile导入到HBase的region中,这一步很简单,也很快。

Update Cube Info

将数据导入Hbase中之后,Kylin会将新生成的segment在元数据中的状态修改为ready。这一步也非常快。

Cleanup

这一步主要就是从Hive中删除临时表。由于在上一步中,已经将segment的状态修改为ready,所以这一步的操作不会对segment产生任何影响。即使这一步执行发生了错误,也不需要担心,因为所有的垃圾都会在Kylin执行StorageCleanupJob的时候进行回收。

Kylin Cube构建过程优化的更多相关文章

  1. kylin cube 构建过程

    本文是对 http://kylin.apache.org/docs20/howto/howto_optimize_build.html的翻译,以便阅读. 1.  创建 Hive 中间表(Create ...

  2. Apache Kylin Cube 的构建过程

    不多说,直接上干货! 1. Cube的物理模型 Cube物理模型 如上图所示,一个常用的3维立方体,包含:时间.地点.产品.假如data cell 中存放的是产量,则我们可以根据时间.地点.产品来确定 ...

  3. DOM 操作成本究竟有多高,HTML、CSS构建过程 ,从什么方向出发避免重绘重排)

    前言: 2019年!我准备好了 正文:从我接触前端到现在,一直听到的一句话:操作DOM的成本很高,不要轻易去操作DOM.尤其是React.vue等MV*框架的出现,数据驱动视图的模式越发深入人心,jQ ...

  4. android构建过程

    参考: http://blog.csdn.net/shangmingchao/article/details/47375111 首先,需要了解一下构建APK的七大工具: ①aapt 全称是Androi ...

  5. Linux内核剖析(五)Linux内核的构建过程

    参考 一次实验引发的故事 – kernel build system探索—vmlinux是如何炼成的– kernel makefile 深度探索Linux操作系统:系统构建和原理解析.pdf 问题 在 ...

  6. vue项目构建过程

    # template 模版项目 > A Vue.js project* 构建过程* 安装过程* 差异点* 打包优化 ## 构建过程```bashbogon:vue-cli caoke$ vue ...

  7. 用gulp+webpack构建多页应用——记一次Node多页应用的构建过程

    通过参考网上的一些构建方法,当然也在开发过程中进行了一番实践,最终搭建了一套适用于当前多页应用的构建方案,当然该方案还处于draft版本,会在后续的演进过程中不断的优化. 个人觉得该方案的演进过程相对 ...

  8. Mysql主从复制,读写分离(mysql-proxy),双主结构完整构建过程

    下面介绍MySQL主从复制,读写分离,双主结构完整构建过程,不涉及过多理论,只有实验和配置的过程. Mysql主从复制(转载请注明出处,博文地址:) 原理是master将改变记录到二进制日志(bina ...

  9. Android分析应用程序的构建过程

    为了方便Android应用开发要求我们Androidproject编制和包装有了更深入的了解,例如,我们知道这是做什么的每一步,境和工具.输入和输出是什么.等等. 在前文<命令行下Android ...

随机推荐

  1. ssm框架使用jsp提交表单到controller

    jsp代码: controller代码:

  2. 容器viewController添加或者删除子viewController

    假设有一个viewControllerA,我们想在viewControllerA中添加viewControllerB,需要执行以下方法: [viewControllerA addChildViewCo ...

  3. python语言中的数据类型之元组

    数据类型 元组       tuple 元组:不可变类型 用途:元组就是一个不可变的列表,当需要存不改动的值时可用元组 定义方式:在()内用逗号分隔开多个任意类型的元素 t=(1,2.2,'aa',( ...

  4. Eclipse SVN文件冲突及不能直接提交情况

    下图为Eclipse SVN使用过程中存在文件冲突的情形. 以下是三种冲突情形及相应解决办法: 1.简单的文件版本冲突 情形:A改变了文件的头部,B改变了文件的尾部,如果两者改动互不影响,SVN可以智 ...

  5. U3D的结构体堆分配栈分配

    ST ot;//分配在栈上 ST[] arrt = new ST[2];//分配在堆上,因为数组是引用

  6. 今天学习到的几条shell技巧

    1.获取某个进程的进程号 PID=`ps aux | grep 进程名 | grep -v "grep" | awk '{print $2}'` 2.获取某个进程的CPU(同理可获 ...

  7. MySQL中tinytext、text、mediumtext和longtext详解【转】

    一.数字类型 类型 范围 说明   Char(N) [binary] N=1~255 个字元binary :分辨大小写 固定长度 std_name cahr(32) not null VarChar( ...

  8. MyBatis动态SQL中trim标签的使用

    My Batis 官方文档 对 动态SQL中使用trim标签的场景及效果介绍比较少. 事实上trim标签有点类似于replace效果. trim 属性 prefix:前缀覆盖并增加其内容 suffix ...

  9. Spring3.0学习1.1(模拟spring)

    层次划分 面向抽象编程  带来极大的灵活性 IOC(DI)  依赖注入 控制反转: 正式使用spring IOC   控制反转 不用自己写实现 由容器完成 建议使用appicatiioncontext ...

  10. 前端CSS3笔记

    第1章CSS3简介 如同人类的的进化一样,CSS3是CSS2的“进化”版本,在CSS2基础上,增强或新增了许多特性, 弥补了CSS2的众多不足之处,使得Web开发变得更为高效和便捷. 1.1   CS ...