kylin基础概念和基础性能优化
1. 教材(只有基本介绍和操作)
Apache Kylin权威指南.pdf
官网公众微信号(ApacheKylin)
2. 核心概念
度量: 度量是具体考察的聚合数量值,例如:销售数量、销售金额、人均购买量。计算机一点描述就是在SQL中就是聚合函数。
例如:select cate,count(1),sum(num) from fact_table where date>’20161112’ group by cate;
count(1)、sum(num)是度量
维度: 维度是观察数据的角度。例如:销售日期、销售地点。计算机一点的描述就是在SQL中就是where、group by里的字段
例如:select cate,count(1),sum(num) from fact_table where date>’20161112’ group by cate;
date、cate是维度
3. 应用与实践
1.1、kylin公司分享(kylin2.0功能介绍)
http://video.pae.baidu.com/show/videoindex?src=http%3A%2F%2Fm.v.qq.com%2Fpage%2Fu%2Ff%2Fc%2Fu0396tk9hfc.html%3Fptag%3Dbaidu.3g&log_loc=http%3A%2F%2Fv.qq.com%2Fx%2Fpage%2Fu0396tk9hfc.html&loc=http%3A%2F%2Fv.qq.com%2Fx%2Fpage%2Fu0396tk9hfc.html&title=%E6%9D%8E%E6%89%AC-Apache+Kylin+2.0%E6%9C%80%E6%96%B0%E5%8A%9F%E8%83%BD%E5%92%8C%E6%B7%B1%E5%BA%A6%E6%8A%80%E6%9C%AF%E8%A7%A3%E8%AF%BB&query=Apache+kylin%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B&duration=2920&lid=9029643596138362365&srcid=4185&poster=http%3A%2F%2Ft10.baidu.com%2Fit%2Fu%3D3481457922%2C1950467330%26fm%3D171%26s%3DC7C9B3550520F32ADA79C4580300D0F3%26w%3D496%26h%3D280%26img.JPEG&qq-pf-to=pcqq.group
1.2、百度外卖的实践总结
4. 安装教程(基于cdh)
http://blog.csdn.net/a920259310/article/details/77771917
5. 深度优化(搜狐内部课程)
1、 kylin job调度::2、Kylin cube构建原理及优化
http://my.tv.sohu.com/pl/9019985/90815107.shtml
2、Kylin cube构建原理及优化::3、kylin cubing算法选择
http://my.tv.sohu.com/us/259563347/90816849.shtml
4、kylin Hybrid介绍和使用::5、kylin query原理和优化
http://my.tv.sohu.com/us/259563347/90817015.shtml
6. 度量优化
A、 拓展字段(Extended Column)
(1)、实践证明该优化会导致cube变大,影响查询性能
(2)、拓展字段限制
11、并且code字段必须来自事实表(fact_tabe),这个是kylin操作上的限制。
12、拓展字段(name)必须和原始字段(code)一对一。否则查询name字段是空的。
例如:下列查询acccode和class_name就不是一对一的关系,而是通过m_consume_type的acccode字段关联,再找到class_code、class_name。就会出现name查询出来是空的情况。
SELECT b. acccode as acccode,m.class_name as dscrp, SUM(b.opfare) AS sums
FROM
m_rec_consume_copy b
LEFT JOIN m_consume_type m ON b.acccode=m.acccode
WHERE
1=1
GROUP BY b.class_code1,m.class_name
ORDER BY sums DESC
(3)、详细说明
https://blog.bcmeng.com/post/kylin-dimension.html#extended-column
在OLAP分析场景中,经常存在对某个id进行过滤,但查询结果要展示为name的情况,比如user_id和user_name。这类问题通常有三种解决方式:
a. 将ID和Name都设置为维度,查询语句类似select name, count(*) from table where id = 1 group by id,name。这种方式的问题是会导致维度增多,导致预计算结果膨胀;
b. 将id和name都设置为维度,并且将两者设置为联合。这种方式的好处是保持维度组合数不会增加,但限制了维度的其它优化,比如ID不能再被设置为强制维度或者层次维度;
c. 将ID设置为维度,Name设置为特殊的Measure,类型为Extended Column。这种方式既能保证过滤id且查询name的需求,同时也不影响id维度的进一步优化。
所以此类需求我们推荐使用 Extended Column。
7. Kylin - 剪枝优化(维度优化)
怎么确定维度
Where 查询条件、group by条件都是维度。Sql测试已经证明
Kylin里面设置的维度顺序,不影响统计的进行(无论什么顺序,只要维度里面有,sql都可以查询)
剪枝方法
http://baijiahao.baidu.com/s?id=1579212035193751949&wfr=spider&for=pc
http://blog.csdn.net/weixin_36630761/article/details/78086603
http://bigdata.51cto.com/art/201705/538648.htm
http://lxw1234.com/archives/2017/04/849.htm
优缺点:
A、 联合维度:有效剪枝。跨联合的查询会把多个联合维度查询出来,再合并。(根据查询业务分组,就能有效剪枝,并且没有关联多个的查询,从而效率高)
B、 必要维度:join条件、查询必须带上的条件,作为必要维度。(多个必要维度时,生成的维度组合可能是不包括必要维度组合本身的。在查询中出现了按照必要维度查询不了的情况【这里可能是kylin的一个bug,必要维度组合本身不产生维度,但是sql解析的时候认为产生了所以会匹配成功,然后报错,并且挡住了其他可能支持这个查询的cube的匹配】)多个必要维度可以用联合维度代替。如果维度组(聚合组)的维度包含必要维度所有列,则查询必要维度就可以进行,因为可以通过必要维度和其他维度组合后的结果来汇总必要维度的查询结果。
C、 派生维度:把字典表的多个维度字段,不用当作维度构建;而是通过字典表的主键来查询,然后再通过字典表去找到维度。当字典表主键和维度字段不是一对一的时候,还需要二次聚合。这个能剪枝,但是影响查询效率。维度选择的页面(Derived维度看到的是外键列而不是Derived的列);
D、层级维度:相当于把单个维度的变成了,带上父级的维度;去掉了一些单独的层级维度。能剪枝。(必须是查询对各个层级都有查询要求,采用层级维度;否则应该使用联合维度)
E、 维度聚合组:给聚合分组,属于不同组的不会组合(各组内部才能随意组合,组和组之间不组合)。
维度顺序
其次,ID决定了这个维度在数组中执行查找时该维度对应的第一个维度,例如在上例中time的ID就是1,location对应的ID就是2,product对应的ID为3,这个顺序是非常重要的,一般情况我们会将mandatory维度放置在rowkey的最前面,而其它的维度需要将经常出现在过滤条件中的维度放置在靠前的位置,假设在上例的三维数组中,我们经常使用time进行过滤,但是我把time的ID设置为3(location的ID=1,product的ID=2),这时候如果从数组中查找time大于’2016-01-01’并且小于’2016-01-31’,这样的查询就需要从这样的最小的key=<min(location)、min(product)、‘2016-01-01’>扫描到最大的key=<max(location)、max(product)、‘2016-01-31’>,但是如果把time的ID设置为1,扫描的区间就会变成key=<‘2016-01-01’、min(location)、min(product)>到key=<‘2016-01-31’、max(location)、max(product)>,Kylin在实现时需要将Cube的数组存储在Hbase中,然后按照hbase中的rowkey进行扫描,假设min(location)=’BeiJing’、max(location)=’ZhengZhou’, min(product)=’aaaa’,max(product)=’zzzz’,这样在第一种情况下hbase中需要扫描的rowkey范围是[BeiJing-aaaa-2016-01-01, ZhengZhou-zzzz-2016-01-31],而第二种情况需要扫描的rowkey范围是[2016-01-01-BeiJing-aaaa, 2016-01-31-ZhengZhou-zzzz].可以看出第二种情况可以减少扫面的rowkey,查询的性能也就更好了。但是在kylin中并不会存储原始的成员值(例如HangZhou、2016-01-01这样的值),而是需要对它们进行编码,是否需要编码则有后面两个设置项决定。
8. Rowkey优化
Rowkey设置项说明
1、 Encoding:维度编码,指定了该维度的值应该使用何种方式进行编码,选用合适的编码能够有效减少维度对空间是使用,在大数据量情况下效果明显。
2、 维度的编码(dict、boolean、date、time、integer、fix_length、fix length_hax)。
3、 fix_length则意味着在实际存储到hbase的rowkey时使用该维度的前Length个字符作为它的值,一般情况下是不建议设置Length的,只有当cardinality比较大时并且只需要取前N个字节就可以表示这个维度时才建议设置Length=N。
4、 Shard By:按维度对数据进行分片,默认Cuboid的数据分片策略是随机的,并且只能设置一个维度为Share By。
5、 如果Cuboid中的某些行的Shard By Dimension的值是相同的,那么这些行的数据最终将会分配到同一个分片中。
RowKey顺序优化
和Hbase 的RowKey优化类似
1.在查询的过程中,被用作过滤条件的维度可能放在其他维度的前面
2.经常出现的维度应该放在前面
3.基数比较大的维度应该放在前面
维度字典(优缺点)
Dictionary表示需要为这个维度建立字典树。因为每一个维度的dictionary都会保存在内存中,如果字典树占用很大的内存会影响kylin的使用甚至导致OOM,对于dictionary的编码使用的是字典树,它的原理实际上是为每一个维度成员赋予一个整数的id,实际存储的时候存储的是这个id的二进制值(使用int最多占用4个字节),并且保证每一个id的顺序和维度成员的顺序相同的,例如aaa的id=1,aab的id=2,aac的id=3,这样在查询的时候就可以直接根据column>aaa转换成id>1,方便hbase coprocessor的处理。
9. 精确去重
精确去重(维度统计实现方式)
没有设置精确去重,但是如果有按照学号统计的维度(并且有count()度量),下面这个sql也是能执行的。这样就在一些场景下不用使用全局表去实现精确去重
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_copy b ;
特别说明
如果cube中已经把outid作为一个维度,则不能再将其作为全局字典(kylin上的操作限制)。(按照上一节说的,如果有此维度就已经能count(distinct())获取精确去重值;不需要全局字典再去重这种低效的方式)。
精确去重(在cube里设置count_distinct的方式)很消耗资源,并且占用空间大,不论是否是全局字典表的方式。
非全局字典精确去重验证
-- 数据库验证的sql
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_view b ;
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_view b
where b.opdt >='2017-01-01' AND b.opdt <'2017-02-01';
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_view b
where b.opdt >='2017-02-01' AND b.opdt <'2017-04-01';
-- kylin验证的sql::说明没有全局字典的情况下精确去重的度量在跨分区查询时是错误的
--错误: 和sql中的第三个一致
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_copy b ;
--正确
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_copy b
where b.opdt >='2017-01-01' AND b.opdt <'2017-02-01';
--正确
SELECT COUNT(DISTINCT(b.outid))
FROM m_rec_consume_copy b
where b.opdt >='2017-02-01' AND b.opdt <'2017-04-01';
----------
验证结果说明:没有全局字典的情况下精确去重的度量在跨分区查询时是错误的
其他说明
----------
1.5版本的说明 (需要全局字典表,才能精确去重)
http://lxw1234.com/archives/2016/08/712.htm
2.1版本的说明 (来自kap-manual-zh-cn.pdf文档,需要验证)不需要全局字典表,也能精确去重。
实际验证结果是:不是全局表的情况下去重结果是错误的。
全局字典表
1.5.3版本的情况:
非全局字典表最大容量为500万,(可以通过参数 kylin.dictionary.max.cardinality修改默认值)。
全局字典表最大容量为Integer.MAX_VALUE,即21亿多。还是有上限。
全局字典表使用,不使用会影响kylin查询结果准确性
(如果是分区cube,每个分区会构建自己的字典表在对应的字段上,导致统计的时候字典表编码或者顺序不一致,去重复统计的值就是错误的)
全局字典(使用案例)
http://bigdata.51cto.com/art/201705/539360.htm
2.1版本的情况:(来自kap-manual-zh-cn.pdf文档,需要验证)
普通字典容量也到21亿了,
10. 配置优化
粒度优化
粒度优化对应的是提高Cube的并发度,其设置是在自定义属性中的
一共有三个属性可以提高并发度。
1.kylin.hbase.region.cut(共使用几个分区)
2.kylin.hbase.region.count.min(最少使用几个分区)
3.kylin.hbase.region.count.max(最多使用几个分区)
根据相对应的情况调高最少使用分区,降低最大使用分区,能够有效增加系统的并行度。
Cube Size
最后设置CubeSize,该项的设置会对cuboid转换成hfile这一步的计算产生影响,并且影响hbase中表的分区大小,可选值为SMALL、MEDIUM和LARGE,在kylin-1.1版本之后可以在配置文件可以设置这三个配置的分区大小,默认情况下SMALL=10GB,MEDIUM=20GB,LARGE=100GB,在计算完全部的cuboid之后会统计所有cuboid文件中key和value的大小,然后根据这个大小和用户的CubeSize配置决定划分多少region,然后执行一个MR任务计算每一个region的hfile,由于kylin在创建hfile的时候都是通过预分区的方式(通过计算出每一个分区临界值的key),然后批量load到htable的,所以不会导致region的分裂和合并,所以我们还是建议将CubeSize设置为SMALL,并且配置中将small的配置设置为5GB,这样可以提高生成hfile这一步的速度(每一个region负责一个region,减小分区的大小会增加reducer的个数)。