赞
踩
整体脑图如下:
数据来源主要来自hive表,所以可以优化hive表
数据输出主要是使用hbase,所以可以优化hbase表
kylin.hbase.default.compression.codec = snappy
参数优化有很多参数, 只列举下常用的增加内存的参数, 还有很多参数具体见官方文档
http://kylin.apache.org/cn/docs/install/configuration.html#cube-build
如果用户希望任务从 Yarn 获得更多内存,可以这样设置:
kylin.engine.mr.config-override.mapreduce.map.java.opts=-Xmx10g
kylin.engine.mr.config-override.mapreduce.map.memory.mb=10240
kylin.engine.mr.config-override.mapreduce.reduce.memory.mb=10240
kylin.engine.spark-conf.spark.driver.memory=8G
kylin.engine.spark-conf.spark.executor.memory=12G
设计的时候尽量去减少维度,去增加度量, 这时候就有个度量 EXTENDED_COLUMN
比如 city_id,city_name, 这时候就可以保留 city_id 作为维度, city_name 设置成度量 EXTENDED_COLUMN
这一步说明:
这样做的好处, 大大减少了维度组合, 减少了构建时各个步骤的时间
这样做的要求有 :
必须city_id,city_name 是一一对应的,一对多的时候,会随机选一个city_name
city_name 不可作为 查询条件,不可以有city_name = ‘’ 或者 like “”
city_name 可以作为group by 字段
city_name 直接查询没有值, select distinct city_name 或者 select city_name from t group by city_name 有值
如果想直接查询某个字段,比如名称、计算结果值等, 可以使用RAW 维度
特别说明: 官方文档说是可以节省空间,但是实际构建时, 构建结果, 这种方式构建结果,比正常占用的要大, 可能与 extendedcolumn(100) 这个100有关系,未验证
不过这种构建方式速度会加快很多,是肯定的
kylin的设计优化 主要在设计, 也就是 Advanced Setting 这里的设置
聚集组:用来控制哪些cuboid需要计算。
适用场景:不是只需要计算base cuboid的情况下,都需要聚集组。
注意事项:一个维度可以出现在多个聚集组中,但是build期间只会计算一次。
如果不设置聚集组,默认情况下只会计算 base cuboid。
聚集组不宜太多。
这一步说明 : 聚集组是可以根据需求设置多个, 把自己常用的组合组成确定的一个聚集组, 可以大大优化查询效率
衍生维度:维表中可以由主键推导出值的列可以作为衍⽣维度。
使用场景:以星型模型接入时。例如用户维表可以从user_id推导出用户的姓名,年龄,性别。
优化效果:维度表的N个维度组合成的cuboid个数会从2的N次方降为2。
这一步说明: 衍生维度不参与维度组合,所以衍生维度多少并不会增加构建的复杂度和大小
强制维度:所有cuboid必须包含的维度,不会计算不包含强制维度的cuboid。
适用场景:可以将确定在查询时一定会使用的维度设为强制维度。例如,时间维度。
优化效果:将一个维度设为强制维度,则cuboid个数直接减半。
层次维度:具有一定层次关系的维度。
使用场景:像年,月,日;国家,省份,城市这类具有层次关系的维度。
优化效果:将N个维度设置为层次维度,则这N个维度组合成的cuboid个数会从2的N次方减少到N+1。
这一步说明: 简单说明下层次的意思,就是在 group by 的时候 group by city_id,district_id 和 group by district_id 是一个意思, 有层级关系,所以可以这么设置
联合维度:将几个维度视为一个维度。
适用场景:
1 可以将确定在查询时一定会同时使用的几个维度设为一个联合维度。
2 可以将基数很小的几个维度设为一个联合维度。
3 可以将查询时很少使用的几个维度设为一个联合维度。
优化效果:将N个维度设置为联合维度,则这N个维度组合成的cuboid个数会从2的N次方减少到1。
查询频率越高的维度在Rowkey中的顺序需要越靠前。
Encoding 默认dict, 当维度基数特别大的时候, 会报错, 需要调整为 其他的编码方式 比如"fixed_length"、"integer"等等
Length fixed_length等编码方式需要设置长度, 这里需要注意的是,长度不能设置短于实际数据长度,否则会导致数据被截断
当一个字段又作维度,又做度量时,也不能使用dict 需要使用其他编码方式 比如"fixed_length"、"integer"等等
Shard By 这个设置为 true 时, 会按照这个字段来分片, 选择高基维会加快构建, 后面会有详细说明
目前有 MapReduce 和 spark
关于选择之后影响哪几部分 下面会有详细说明
这里说下优劣势 :
MapReduce
构建速度适用于 大批量的, 多复杂构建如 count(distinct)
构建相对稳定, 不容易报错
构建速度相对较慢
spark
构建速度适用于 小批量的, 如 sum, max这种
不太稳定, 内存不够容易报错
构建速度很快
这一步主要失针对 count(distinct) 这种计算的
当表是 增量表时 class 选择 org.apache.kylin.dict.GlobalDictionaryBuilder
当表是 全量表是 calss 选择 org.apache.kylin.dict.global.SegmentAppendTrieDictBuilder
两者区别
默认的 Global 是全局的字典, 可以保证在各个地方都能字典一致, 所以分区构建时必须采用, 否则会导致计算值不一致
但是这个 会随着时间的增加 而增长, 会越来越大, 越来越慢
Segment 不是全局的, 所以不能增量构建时适用,适用于全量构建, 构建速度快, 且不会随时间而增大
为全局 lookup 表而设计,提供不同的存储类型
如果有超过一个的 COUNT DISTINCT 或 TopN 度量, 你可以将它们放在更多列簇中,以优化与HBase 的I/O。
这一步将数据从源Hive表提取出来(和所有join的表一起)并插入到一个中间平表。
如果Cube是分区的,Kylin会加上一个时间条件以确保只有在时间范围内的数据才会被提取。
这一步说明:
从hive里面取表,所以依赖hive,且是一个MapReduce任务,更换spark引擎对此无影响,当然,这步的查询spark并无多少优势,所以不需要用spark来优化
分区构建的分区字段 一定要是分区表的分区字段,特别是大表的时候,否则这步的查询将非常耗时
在之前的一步之后,Hive在HDFS上的目录里生成了数据文件:有些是大文件,有些是小文件甚至空文件。
这种不平衡的文件分布会导致之后的MR任务出现数据倾斜的问题:有些mapper完成得很快,但其他的就很慢
这一步说明:
这步是为了解决数据倾斜问题, 正常情况下是采用 DISTRIBUTE BY RAND()这种方式
可以通过 “Advanced Setting” -> “Rowkeys” -> “Shard By” -> true 来指定一个列为分片字段, 可以预先分类,大大提升后续的构建速度,优化cube的存储空间
指定为分片的列的特点 : 1.高基数的维度列 2.出现在很多的cuboid
在这一步骤Kylin运行MR任务来提取使用字典编码的维度列的唯一值。
实际上这步另外还做了一些事情:通过HyperLogLog计数器收集cube的统计数据,用于估算每个cuboid的行数
这一步说明:
这一步是后续计算的基石,如果这一步很慢,就是设计过于复杂,考虑重新设计
这个也对我们提出了要求,尽量减少构建的维度,可以加快构建的速度
特别说明: 度量方式 EXTENDED_COLUMN, 正是通过转化维度为度量的方式, 减少了这一步,及其之后的构建时间
超高基数列(Ultra High Cardinality,UHC)
有了前一步提取的维度列唯一值,Kylin会在内存里构建字典
第 4, 和第5 步 说明:
如果唯一值集合很大,Kylin可能会报出类似"字典不支持过高基数",“无法读取过高基字典”,“Failed to read big resource /dict/”,
则需要更改其他的编码方式 比如"fixed_length"、"integer"等等
或者切换构建引擎, 会更改构建的dict
如果这两种种方式解决不了,那只能手动从后台清理出错的dict,再重新构建, 这是个bug 与 KYLIN-4153有关, 在kylin 2.6.4修复。
kylin会将字典所有的值都加载进内存, 导致对堆内存的消耗非常可观,所以使用字典类型就不再合适了
如果一个数据集中有多个UHC,最好还使用kylin的高级特性聚合组来对维度进行分组,
将某一个UHC和必须和这个UHC一起使用的维度分在一个聚合组中,避免两个或者多个UHC同时出现在一个分组中,导致cube膨胀
第6 和 第7 步快速且轻量, 不耗时
这一步用Hive的中间表构建基础的cuboid,是"逐层"构建cube算法的第一轮MR计算。
Mapper的数目与第二步的reducer数目相等
这些步骤是"逐层"构建cube的过程,每一步以前一步的输出作为输入,然后去掉一个维度以聚合得到一个子cuboid
通常来说,从N维到(N/2)维的构建比较慢,因为这是cuboid数量爆炸性增长的阶段
过(N/2)维构建的步骤,整个构建任务会逐渐变快
这个步骤使用一个新的算法来构建cube:"逐片"构建(也称为"内存"构建)。
它会使用一轮MR来计算所有的cuboids,但是比通常情况下更耗内存
说明:
第8 、 第9 和第10 步 在使用 spark引擎的时候 被 “Build Cube with Spark” 所代替
第10 步 可以通过 增加内存的方式来提升构建速度, 具体参数见参数优化
这一步启动一个MR任务来将cuboid文件(序列文件格式)转换为HBase的HFile格式
这一步使用HBase API来讲HFile导入region server,这是轻量级并快速的一步
在导入数据到HBase后,Kylin在元数据中将对应的cube segment标记为ready
将中间宽表从Hive删除。这一步不会阻塞任何操作,因为在前一步segment已经被标记为ready
当我们构建的时候, 只对某几个聚合的方式有需求,其他的聚合方式不关心的时候, 可以采用指定聚合组的方式
举例说明: 当有个 全量表 t_all (A,B,C,D)
我们只关心 A,B,C 和 A,B,D两个组合对应的结果集
即
select A,B,C,count(*) from t_all group by A,B,C
和
select A,B,D,count(*) from t_all group by A,B,D
解决方案: 这个时候我们就可以指定聚合组为这两个组合, 这样就排除了其他的组合
优化结果: 构建和查询效率都大大提高
当我们构建的时候, 对一个表有多个sql需求的时候, 这个表又比较大, 有的sql又比较单一, 可以采用增加单一cube的方式
举例说明: 当有个 分区表 t_part (A,B,part) 、 分区字段 part
除了正常的
select A,count(distinct B) from t_part group by A 这种sql
还有个特别的查询
select max(part) from t_part
这个查询对性能要求就比较高,这个分区表又比较大,这又是个跨分区的查询,因为没有聚合的特性, 所以也没有办法指定聚合组
解决方案: 新建一个只有 part字段的 cube, 维度, 聚合组,绑定维度均为part 的一个cube
优化结果: 这样就极大的增加了这个sql的查询效率,虽然增加了一个cube,但是这个cube 很简单, 构建也很快, 影响不大
在Advanced Setting -> Advanced ColumnFamily 这步设置时
如果有超过一个的 COUNT DISTINCT 或 TopN 度量, 你可以将它们放在更多列簇中, 可以提升查询效率
在Advanced Setting -> Rowkeys 这步设置时
可以通过按住 ID 下数字的位置 拖动字段的顺序, 来优化rowkey的设置
例如 查询sql
select count(*) from t_table
where a = '1'
and b = '2'
and c = '99999'
当 c 字段 不在聚合组中的时候, 查询时非常慢的,甚至于超过集群扫描条数上限
这时候只要把 c 字段 加入聚合组即可
这个时候只需要
clone cube -> build cube_clone -> disable 原cube -> purge 原cube -> 修改 原cube -> build 原cube -> disable cube_clone -> drop cube_clone
这个好处就是可以不更改原来的cube名称, 也就不需要更改workflow
由于需要更改model 这个时候clone cube 就不可以了,
这时候只需要
new 新model -> new 新cube -> build 新cube -> disable 原cube -> drop 原cube
这样的方法就是需要更改原来的cube了,需要更改workflow, 当然如果不想更改, 可以采用类似1 的操作
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。