kylin cube 构建过程

本文是对 http://kylin.apache.org/docs20/howto/howto_optimize_build.html 的翻译,以便阅读。

1.  创建 Hive 中间表(Create Intermediate Flat Hive Table)

     这个过程会把 cube 中用到的所有 Hive 表(包括 look at 的表)汇聚成一张表。如果 Cube 是分区的,kylin 会增加时间条件以获取相应的数据。此过程的输出大致如下:

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 命令使用的配置文件在 conf/kylin_hive_conf.xml 中。

    如果 Cube 的分区列(partition cloumn)和 Hive 的分区列(partition cloumn) 相同,那么在这一列上进行过滤,会使 Hive 能智能的过滤掉不符合的分区。因此强烈建议使用 Hive 表的分区列(如果是日期格式的话) 作为 Cube 的分区列。对于很大的表来说,这几乎是必须的。

    如果你的 Hive 开启的文件合并,你应该在  conf/kylin_hive_conf.xml  中禁用它。因为 kylin 会在后面的步骤中会做这件事。

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

 

2. 重新分区中间表(Redistribute intermediate table)

    在第1步中生成的数据文件有大有小,这会导致后续 MapReduce 的 job 有的很快就完成了,有的要处理很久。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 默认情况下,一个文件分配一百万条数据(通常一百万条数据不会超过 HDFS 中一个块的大小)。此例中 159869711 条数据会被分到 160 个文件中,会有 160 个 Mapper 和 160 个 Reduce 任务。如果你想增加并发量,并且你的 Hadoop 集群有充足的资源,你可以在 “conf/kylin.properties”中给“kylin.job.mapreduce.mapper.input.rows” 设置一个较小的值。

    然后, Kylin 运行 “INSERT OVERWIRTE TABLE …. DISTRIBUTE BY “  这个 HiveQL, 把数据分发到各个 reducer 。通常会通过 “DISTRIBUTE BY RAND()” 将数据随机的分发到各个 reducer 中。

    如果你的 Cube 指定了 “shard by”  维度(在 Cube 的 “Advanced setting” 页),这个维度又是一个高基维(如:user_id),kylin 会告诉 Hive,让其使用这一列的值进行分发数据,代替上面的 RAND() 方式。这会有利于 Cube 后续的构建。在一些典型的场景中,这将减少 40% 的构建时间。此例中 distribute 的条件是 “DISTRIBUTE BY USER_ID”:

   注意:“shard by” 列必须是高基维的列,并且它会出现在大多数的 Cubeid 中,利用它可以获得每个时间范围内数据的均匀性,否则会引起数据倾斜。

 

3. 获取事实表去重后的值(Extract Fact Table Distinct Columns)

    在这一步, kylin 会获取每个维度的去重后的值,用于数据字典编码。它也会使用 HyperLogLog 计数器去收集 Cube 的统计信息用以估算每个 cubeid 的行数。

    如果你发现 Mapper 比较慢,这通常意味着 Cube 太复杂。

    如果 Reducer 发生 OutOfMemory  的错误,这意味着 Cubeid 组合过大,或者默认的 YARN 无法分配所需的资源。

    如果这一步不能在合理的时间内完成,你应该得新审视你的设计。

 

4. 建立维度字典(Build Dimension Dictionary)

    通过上一步得到值,kylin 在内存中(以后会移到MR)创建这些值的字典。这步通常很快,但是如果这些值有很多,kylin 会报告类似 “Too high cardinality is not suitable for dictionary” 的错误。对这些高基维(UHC)请使用 “fixed_length”, “integer” 做为编码方式。

 

5.  Save Cuboid Statistics and Create HTable

     这步很轻量,并且很快。

 

6. Build Base Cuboid

    这一步从中间表创建基础 cuboid。这是 “by layer” cubing 算法中的第一轮 MR。Mapper 的数量是第2步中的 Reducer 的值。Reducer 的数量通过 Cube 统计信息进行估算(默认每 500MB 的输出使用一个 reducer)。如果观察到 reducer 数量较少,可以在kylin.properties 中设置 “kylin.job.mapreduce.default.reduce.input.mb”  成一个较小的值。

 

7. Build N-Dimension Cuboid

   这一步会逐层构建 cube,每一步均使用上一步的结果作为此步的输入,然后减少一维,聚合成一个子 cuboid。例如:从 cuboid ABCD 中去除A,得到 BCD;去除 B 得到 ACD。

   一些 cuboid 可以从多个父 cuboid 中得到,kylin 会使用较小的 cuboid。记住,在设计 cube 的 rowkey 时,应该把高基维放到前面。

   通常从 N-D 到 (N/2)-D 的构建是慢的,因为这是由 cuboid 的爆发引起的: N-D 有 1 个 Cuboid,  (N-1)-D 有 N个 cuboids, (N-2)-D 有 N*(N-1) 个 cuboids... 经过 (N/2)-D 步后, 构建将会逐渐加快。

 

8. Build Cube

    这一步使用 “by-split” Cubing (也叫 “in-mem” cubing) 算法去构建 Cube,它使用一次 MR 去计算所有的 cuboid,需要更多的内存。每个 Mapper 默认需要3GB,如果你的集群有足够的资源,可以通过 “conf/kylin_job_conf_inmem.xml” 分配更多的内存,有助于提升性能。

<property>
    <name>mapreduce.map.memory.mb</name>
    <value>6144</value>
</property>

<property>
    <name>mapreduce.map.java.opts</name>
    <value>-Xmx5632m</value>
</property>

  注意: kylin 会自动根据数据分布(从 Cube 的统计信息中获得)选择最好的算法。你不必明确指定算法。

 

9. Convert Cuboid Data to HFile

   这一步会启动一个 MR 的 job,把 Cuboid 文件(sequence file format)转化成 HBase 的 HFile。Kylin 会计算 HBase 的 Region number,默认每个 Region 5GB 大小。Reducer 的数量随着 Region 的增加而增加。如果你发现 Reducer 的数量较小、效率较低, 你可以修改 “conf/kylin.properties” 中下面的配置: 

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

 

10. Load HFile to HBase Table

    这一步利用 HBase 的 API 把 HFile 载入到 region server。这一步会很快。

11. Update Cube Info

    数据加 HBase后,kylin 标记 Cube segment 在元数据中已准备完毕。这一步很快。

12. Cleanup

    清除 Hive 中的临时表。这一步如果出错的话,不会有任何影响。当 kylin 执行 StorageCleanupJob 时,会清除垃圾。

posted @ 2019-01-21 09:29  一剑侵心  阅读(2682)  评论(0编辑  收藏  举报