欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kylin构建Cube优化

程序员文章站 2024-03-22 16:10:04
...

Kylin 技术贴倾情奉献——夏天小厨原创】Apache Kylin官宣它的定位是一款千亿级OLAP引擎,在其高性能的背后,Cube的构建显得至关重要。因此优化Cube也成为数据分析必不可少的技能之一,那为什么要优化Cube呢?因为随着维度数的增加,Cuboid的数量会随其爆炸式递增,如果不优化Cube,不仅Build Cube时间会很漫长,而且Cube的膨胀率也会让你害怕,从而占用大量的磁盘空间。优化之后不仅能够节省集群资源,而且能够满足高速查询的需要。

为了减轻Cube构建的压力,减少Cuboid的数量以及Build N-Dimension Cuboid : level的层数,kylin开放了一系列的高级设置(即大家常见的Advanced Setting),帮助用户构建成真正需要的Cuboid,减少不必要的资源时间和空间上的浪费。但是再往清楚的说,kylin cube的优化实际上就是对维度的优化,将你未来查询时需要的维度放进去,对他们进行组合、编排,从而达到剪枝优化的目的。举个简单的例子,一个业务场景有20个维度,如果不进行优化剪枝,那么这个Cube中总共会存在2^20=1 048 576个Cuboid,但是优化之后就可大大减小,详细剪枝优化后的效果请听下面分解。

一、检查Cube状况

那么怎么判断你的Cube构建的是否合理呢?主要看两个指标:1、Cuboid的数量;2、Cube的大小(膨胀率);

1、检查Cuboid的数量

个人觉得这个地方需要掌握的理论知识没多少,我们只需要知道这此创建的Cube下属的Cuboid是否是细粒度的,即每种情况的cuboid都会计算到。如果有,那就应该去修改Cube了。使用命令

kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader  +   CubeName即可查询。

[aaa@qq.com ~]#  kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader iot_gas_cube
Statistics of IoT_Gas_Cube[0_52831]

Cube statistics hll precision: 14
Total cuboids: 15
Total estimated rows: 784602
Total estimated size(MB): 5.378857135772705
Sampling percentage:  100
Mapper overlap ratio: 1.0
Mapper number: 1
Length of dimension CSERVER.IOT_GAS_TABLE.REAL_TIME is 2
Length of dimension CSERVER.IOT_GAS_TABLE.PS is 2
Length of dimension CSERVER.IOT_GAS_TABLE.PQ is 2
Length of dimension CSERVER.IOT_GAS_TABLE.DEVICEID is 1
Length of dimension CSERVER.IOT_GAS_TABLE.LOCATION is 1
Length of dimension CSERVER.IOT_GAS_TABLE.ENERGYTYPE is 1
|---- Cuboid 111111, est row: 53128, est MB: 0.41
    |---- Cuboid 101111, est row: 53523, est MB: 0.38, shrink: 100.74%
        |---- Cuboid 100111, est row: 52862, est MB: 0.35, shrink: 98.77%
            |---- Cuboid 100011, est row: 46234, est MB: 0.3, shrink: 87.46%
        |---- Cuboid 101011, est row: 53047, est MB: 0.37, shrink: 99.11%
    |---- Cuboid 110111, est row: 52616, est MB: 0.38, shrink: 99.04%
        |---- Cuboid 110011, est row: 52448, est MB: 0.36, shrink: 99.68%
    |---- Cuboid 111011, est row: 53015, est MB: 0.39, shrink: 99.79%
    |---- Cuboid 111100, est row: 52691, est MB: 0.38, shrink: 99.18%
        |---- Cuboid 101100, est row: 53006, est MB: 0.35, shrink: 100.6%
            |---- Cuboid 100100, est row: 53298, est MB: 0.33, shrink: 100.55%
            |---- Cuboid 101000, est row: 51465, est MB: 0.33, shrink: 97.09%
        |---- Cuboid 110100, est row: 52540, est MB: 0.35, shrink: 99.71%
            |---- Cuboid 110000, est row: 51720, est MB: 0.33, shrink: 98.44%
        |---- Cuboid 111000, est row: 53009, est MB: 0.37, shrink: 100.6%

从分析结果的下半部分可以看到,所有的Cuboid及它的分析结果都以树状的形式打印了出来。在这棵树中,每个节点代表一个Cuboid,每个Cuboid都由一连串1或0的数字组成,如果数字为0,则代表这个Cuboid中不存在相应的维度;如果数字为1,则代表这个Cuboid中存在相应的维度。除了最顶端的Cuboid之外,每个Cuboid都有一个父亲Cuboid,且都比父亲Cuboid少了一个“1”。其意义是这个Cuboid就是由它的父亲节点减少一个维度聚合而来的(上卷)。最顶端的Cuboid称为Base Cuboid,它直接由源数据计算而来。
2、检查Cube的大小

另外一种比较直观的方法就是通过在kylin 的web界面去查看Cube是否构建的较好,将光标放到cube size栏就能出现相关的信息,如下图所示:

Kylin构建Cube优化

大家可以看出来我的这个Cube的膨胀率只有324.18%。一般来说,Cube的膨胀率应该在0%~1000%之间,如果一个Cube的膨胀率超过1000%,那么Cube管理员应当开始挖掘其中的原因。通常,膨胀率高有以下几个方面的原因。

    (1) Cube中的维度数量较多,且没有进行很好的Cuboid剪枝优化,导致Cuboid数量极多;

    (2) Cube中存在较高基数的维度,导致包含这类维度的每一个Cuboid占用的空间都很大,这些Cuboid累积造成整体Cube体积变大;

    (3) 存在比较占用空间的度量,例如Count Distinct,因此需要在Cuboid的每一行中都为其保存一个较大的寄存器,最坏的情况将会导致Cuboid中每一行都有数十KB,从而造成整个Cube的体积变大;

   因此,对于Cube膨胀率居高不下的情况,管理员需要结合实际数据进行分析,可灵活地运用接下来介绍的优化方法对Cube进行优化。(这段话来自Apache Kylin 权威指南

二、Cube构建优化方法

1、聚合组(Aggravation Group)

【聚合组概念】:是根据业务的现有维度组合,划分出具有强依赖性的维度组,说白了就是按照需求将维度分组,这些组合称为聚合组。在聚合组内,各维度之间的组合会预计算,但聚合组之间并不交叉预计算,从而减少Cuboid的数量。

【优化效果】:举个例子,业务场景有4个维度,分别为ABCD,如果聚合组含有的维度为ABCD的话,它的Cuboid为2^4=16个。但是此时如果AB是一个聚合组,BC是一个聚合组,那么Cuboid的个数就是2^2+2^2=8个,相当于缩减了一半。即原来2^(K+M+N)个Cuboid可以减少到2^K+2^M+2^N个。

注意:一个维度可以出现在多个聚集组中,但是build期间只会计算一次,且聚合组不宜过多。

2、强制维度(Mandatory Dimensions)

其实将剩下几个模块列成和聚合组是一级的标题,有点欠缺,因为聚合组里面含有的优化方式,就是接下来我们要将的三种。但是为了大家能够直观的看各种优化方式,我们暂且就这么写,但是在概念上一定要区分清楚。

【强制维度】:如果将一个维度设置成强制维度,那么所有的Cuboid都会含有这个维度,换句话说kylin 只会预计算含有这个维度的Cuboid。大家可能还是不太理解,强制维度到底能干嘛,这么说吧,如果你之后每次查询 group by时都要带上某个维度,那么这个维度就可以设置为强制维度,换句话说,比如你将A维度设置成强制维度, 你支持group by没写上A,则会出错。

【优化效果】:那么Mandatory Dimensions到底有什么好处呢?它能将Cuboid的数量减少一半。如下图所示

【使用场景】:Group by时肯定会存在的维度,例如时间/区域等。

Kylin构建Cube优化

3、层次维度(Hierarchy Dimensions)

【层次维度】:具有上下级层次关系的维度,例如时间维度 年—>月—>日,和地区维度 国家(country)—>省份(province)—> 城市(city)。

【优化效果】:如果有三个维度A,B,C 设置为层次维度,那么Cuboid数量将由2^3减为3+1(ABC、AB、A、空)。如下图所示

【使用场景】:Group by时只会出现以下三种情况:

  1. group by country, province, city(等同于 group by country, city 或者group by city)
  2. group by country, province(等同于group by province)
  3. group by country。

如果跳过上一级,直接访问下一级例如 group by province,city,则会直接出错。

Kylin构建Cube优化

4、联合维度(Joint Dimensions)

【联合维度】:如果将几个维度被当做联合维度,那么构建的Cuboid,要么都包含这几个维度,要不都不含有。换句话说就是把这几个维度当做一个维度来看。

【优化效果】:将多个维度细化成一个维度,如下图所示

【使用场景】:假如有ABC三个维度,但是在查询的时候只会出现Group by A,B,C,而不会出现Group A,Group by B,Group by A、B等等这种情况,维度联合查询。

Kylin构建Cube优化

三、Rowkey优化方法

Apache Kylin使用HBase做为Cube的存储引擎。HBase是Hadoop上的Key-Value数据库,支持按Key的随机查询与写入,这个Key在HBase中称为Rowkey;为了能够支持按多个维度进行查询,Kylin需要将多个维度值以某种次序组成Rowkey。排在Rowkey靠前部分的维度,将比排在靠后部分的维度更易于做筛选(可以直接使得HBase Scan Range大幅缩小),因此查询效率更高。除了各维度在Rowkey上的次序外,维度的编码方法对于空间占用及查询性能也有着显著的影响。

在Cube调优页面的Rowkey模块,可以查看到Rowkey的基础信息和查询统计。基础信息包含基数、字段类型、编码以及是否为shardby 。查询统计包含维度出现的频次、作为过滤条件出现的次数占比、作为聚合条件出现的占比。并且,基数、出现频次、过滤百分比及聚合百分比都支持排序,用户可从多个角度对Rowkey进行优化

  1. 按照基数降序排列,基数较大的Rowkey可以放置基数小的前面,例如时间维度一般放在前面;

  2. 按照过滤出现次数占比排序,比例较高的Rowkey放置过滤次数较少的维度前面。

  3. 按照访问频率,访问频率高的Rowkey放置频率较低维度前面。

Rowkey编码方式详解

  1. Dict编码:使用字典将长的值映射成短的ID,适合中低基数的维度,默认推荐编码。但由于字典要被加载到Kylin内存中,在超高基情况下,可能引起内存不足的问题。
  2.  Fixed_Length编码:适用于超高基场景,将选取字段的前N个字节作为编码值,当N小于字段长度,会造成字段截断,当N较大时,造成RowKey过长,查询性能下降。只适用于varchar或nvarchar类型。
  3. Fixed_Length_Hex编码:适用于字段值为十六进制字符,比如1A2BFF或者FF00FF,每两个字符需要一个字节。只适用于varchar或nvarchar类型.
  4.  Integer编码:将数值类型字段直接用数字表示,不做编码转换。Integer编码需要提供一个额外的参数“Length”来代表需要多少个字节。Length的长度为1到8,支持的整数区间为[ -2^(8*N-1), 2^(8*N-1)]
  5. Date编码:将日期类型的数据使用三个字节进行编码,支持的格式包括yyyyMMdd、yyyy-MM-dd、yyyy-MM-dd HH:mm:ss、yyyy-MM-dd HH:mm:ss.SSS,其中如果包含时间戳部分会被截断。
  6. Time编码:对时间戳字段进行编码,支持范围为[ 1970-01-01 00:00:00, 2038/01/19 03:14:07],毫秒部分会被忽略。time编码适用于time, datetime, timestamp等类型。
  7.   Boolean编码:用一个byte表示布尔值,适用于字段值为:  true, false,1, 0等