提要
在Apache kylin上篇和中篇中我们介绍了kylin学习之前的理论知识,kylin的诞生,和kylin所要立足解决的问题,以及kylin原理和架构。在下篇我们将着重介绍kylin的安装、使用、优化
。希望你能有所收获。注意本文档中很多使用《Apache Kylin权威指南(第2版)》中的例子,其中也加入我的一些阅读所感与思考,和对部分知识进行重新归类以及知识点的补充。推荐读者阅读原书和官方文档。
安装
环境准备
Apache Kylin依赖于Hadoop集群处理大量数据集。因此在安装Apache Kylin之前必须准备Hadoop环境。由于Apach Hadoop版本管理混乱,推荐安装Cloudera CDH或Hortonworks HDP等商业Hadoop发行版。这里推荐我之前写的文章,
ClouderManager环境搭建【CM安装】。
必要组件
准备好Hadoop环境之后,还需要安装一些应用以支持Apache Kylin的分析查询,其中必不可少的有YARN、HDFS、MapReduce、Hive、HBase、Zookeeper和其他一系列服务以保证Apache Kylin的运行稳定可靠。
操作
下载kylin安装包
注意:我用的 cdh6.x 版本安装 hadoop 环境,因此使用 apache-kylin-3.1.0-bin-cdh60 安装包。
# 切换到opt目录,准备kylin的安装目录
> sudo su
> cd /opt
> wget https://archive.apache.org/dist/kylin/apache-kylin-3.1.0/apache-kylin-3.1.0-bin-cdh60.tar.gz
复制代码
解压 tar 包,配置环境变量
注意:从 v2.6.1 开始, Kylin 不再包含 Spark 二进制包; 需要另外下载 Spark,然后设置 SPARK_HOME 系统变量到 Spark 安装目录。或者用脚本下载
> tar -zxvf apache-kylin-3.1.0-bin-cdh60.tar.gz
> cd apache-kylin-3.1.0-bin-cdh60
# 使用脚本安装spark
> $KYLIN_HOME/bin/download-spark.sh
# 可选创建kylin用户进行管理kylin
> useradd kylin
> useradd -d /opt/apache-kylin-3.1.0-bin-cdh60 -m kylin
复制代码
kylin tar 包目录介绍
注意: conf 配置文件可以参考
配置页面。
> ll
bin #shell 脚本,用于启动/停止 Kylin,备份/恢复 Kylin 元数据,以及一些检查端口、获取 Hive/HBase 依赖的方法等
conf #Hadoop 任务的 XML 配置文件
lib #供外面应用使用的 jar 文件,例如 Hadoop 任务 jar, JDBC 驱动, HBase coprocessor 等
meta_backups #执行 bin/metastore.sh backup 后的默认的备份目录;
README.md #相关文档介绍
sample_cube #用于创建样例 Cube 和表的文件。后续使用章节中我们将介绍其的使用
tomcat # 自带的 tomcat,用于启动 Kylin 服务
spark #自带的 spark,v2.6.1已经没有了
tool #用于执行一些命令行的jar文件
复制代码
启动
> $KYLIN_HOME/bin/kylin.sh start
...................................................[PASS]
KYLIN_HOME is set to /opt/apache-kylin-3.1.0-bin-cdh60
Checking HBase
...................................................[PASS]
Checking hive
...................................................[PASS]
Checking hadoop shell
...................................................[PASS]
Checking hdfs working dir
...................................................[PASS]
Retrieving Spark dependency...
Optional dependency spark not found, if you need this; set SPARK_HOME, or run bin/download-spark.sh
...................................................[PASS]
Retrieving Flink dependency...
...................................................[PASS]
Retrieving kafka dependency...
Couldn't find kafka home. If you want to enable streaming processing, Please set KAFKA_HOME to the path which contains kafka dependencies.
...................................................[PASS]
......
A new Kylin instance is started by root. To stop it, run 'kylin.sh stop'
Check the log at /opt/apache-kylin-3.1.0-bin-cdh60/logs/kylin.log
Web UI is at http://dev-hadoop1:7070/kylin
复制代码
注意:初始用户名和密码是 ADMIN/KYLIN。以及KYLIN启动会在HDFS上创建目录/kylin
使用
如果需要一些简单数据来快速体验Apache Kylin,也可以使用Apache Kylin自带的样例数据。运行“${KYLIN_HOME}/bin/sample.sh”来导入样例数据。
注意: 详细使用推荐阅读官网
快速开始,以及样例数据集章节。
优化
Apache Kylin的核心思想是根据用户的数据模型和查询样式对数据进行预计算,并在查询时直接利用预计算结果返回查询结果。由此Apache Kylin优化方向不是原始数据的优化,而是Cube的优化,如何构建出体积更小、查询速度更快的Cube就是优化的关键了。
cuboid 剪枝优化
在现实应用中,用户的维度数量一般远远大于4个。假设用户有10个维度,那么没做任何优化的Cube总共会存在210=1024个Cuboid,如果维度再多呢?于是通过减少构建 cuboid 的数量来达到减少 Cube 的目的,是一种不错的优化手段。
检查 cuboid 数量
Apache Kylin 提供了命令检查 cuboid 数量,bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader CUBE_NAME, CUBE_NAME 是我们在使用一节中创建的CUBE的名称,我创建的CUBE名称是 sales_segment 。
> $KYLIN_HOME/bin/kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader sales_segment
......
============================================================================
Statistics of sales_segment[20120101000000_20140101000000]
Cube statistics hll precision: 14
Total cuboids: 3
Total estimated rows: 16553
Total estimated size(MB): 0.07684016227722168
Sampling percentage: 100
Mapper overlap ratio: 1.0
Mapper number: 1
Length of dimension DEFAULT.KYLIN_SALES.PART_DT is 3
Length of dimension SELLER:DEFAULT.KYLIN_ACCOUNT.ACCOUNT_COUNTRY is 1
Length of dimension BUYER:DEFAULT.KYLIN_ACCOUNT.ACCOUNT_COUNTRY is 1
|---- Cuboid 111, est row: 7784, est MB: 0.04
|---- Cuboid 101, est row: 4406, est MB: 0.02, shrink: 56.6%
|---- Cuboid 110, est row: 4363, est MB: 0.02, shrink: 56.05%
----------------------------------------------------------------------------
复制代码
唯一值(cuboid) | 占有行数(row) | 占有大小(MB) | 对比(Shrink) |
---|---|---|---|
111 | 7784 | 0.04 | – |
101 | 4406 | 0.02 | 56.6% |
110 | 4363 | 0.02 | 56.05% |
唯一值(cuboid)
每个 cuboid 的唯一值都由一连串1或0的数字组成,数字串的长度等于有效维度的数量,从左到右的每个数字依次代表 Cube 的 设置中的各个维度。如果数字为0,则代表这个Cuboid中不存在相应的维度,如果数字为1,则代表这个Cuboid中存在相应的维度。
除了最顶端的Cuboid之外,每个Cuboid都有一个父Cuboid,且都比父Cuboid少了一个“1”。其意义是这个Cuboid是由它的父节点减少一个维度聚合得来的。最顶端的Cuboid称为Base Cuboid。
比如:111其实表示的是维度是三个维度上的组合,我们假设维度用 a、b、c表示。
维度 | 组合 | 唯一值 |
---|---|---|
3D(三维度) | [a、b、c] | 111 |
2D(二维度) | [a、b、] [a、、c] [、b、c] | 110、101、011 |
1D(一维度) | [a、、] [、b、] [、、c] | 100、010、001 |
0D(零维度) | [] | 000 |
注意:
- 这里有一个问题,为什么是三个维度的组合,最后查看cuboid的数量却是3呢?只有111、110、101呢?这个其实是后面我们所说的剪枝优化的作用了。
- 父节点和子节点的关系是少一个维度。也就是说当父节点对父与子节点进行聚合实际是可以得到子节点的结果的。只是效率较低。记住这一点是很重要的,后续我们将提及。
占有大小(MB)
占有大小其实是个估算值,大小估算是构建引擎自身用来指导后续子步骤的,如决定mapper和reducer数量、数据分片数量等的依据,虽然有的时候对Cuboid的大小的估计存在误差(因为存储引擎对最后的Cube数据进行了编码或压缩,所以无法精确预估数据大小),但是整体来说,对于不同Cuboid的大小估计可以给出一个比较直观的判断。
占有行数(row)
占有行数也是个估算值,由于没有编码或压缩时的不确定性因素,因此Segment中的行数估计会比大小估计来得更加精确一些。
对比(Shrink)
对比表示该Cuboid的行数与其父节点的对比(Shrink)。由于这些数值都是估计值,因此偶尔能够看到有些Cuboid的行数反而还超过其父节点、Shrink值大于100%的情况。在这棵“树”中,可以观察每个节点的Shrink值,如果该值接近100%,说明这个Cuboid虽然比它的父Cuboid少了一个维度,但是并没有比它的父Cuboid少很多行数据。换言之,即使没有这个Cuboid,在查询时使用它的父Cuboid,也不会花费太大的代价。由此该cuboid可以进行剪枝操作了。后续介绍必要维度就属于这种情况,这里提前提及一下。
空间与时间的平衡
上面提及父节点实际是可以转换成子节点的结果。如果只是从减少cubeid的数量进行优化。我们只要构建最顶端的Cuboid称为Base Cuboid就行了。也就不存在剪枝问题了。但是这就会产生一个新的问题,效率问题了。
面对一个特定的查询,使用精确匹配的Cuboid就好像是走了一条捷径,能帮助Kylin最快地返回查询结果。因此这里就需要有这空间与时间的平衡了。
在实际的Cube设计中,我们会考虑牺牲一部分查询样式的精确匹配,让它们使用不是完全精确匹配的Cuboid,在查询进行时再进行后聚合。甚至如果它的父Cuboid也没有被物化,Kylin可能会一路追溯到使用Base Cuboid来回答查询请求。再没有找到,就是上篇提及的查询下压了。
衍生维度
衍生维度就是不参与聚合的维度,该维度的聚合往往是通过实时二次聚合产生或是与其他字段有着相同意义。如事实表的外键和维度表的主键就是这种关系了(这只需要聚合一个就行了,为啥?因为完全一样,没必要都参与聚合默认就是衍生维度),其次就是
时间维度,如:日期维度表一般会有天、周、月、年 字段。年月日这种虽然比不上外键主键完全一样,但是也是有一定联系,我们可以通过二次聚合达到要求了。如 日 后面的周月年就可以使用衍生维度哈。达到减枝操作。
下面的例子,我们将 周、年 设置为衍生维度。主要天和周的运算单位为7 月和年的运算单位是12,不是太大。
聚合组
我们构建的事实表和维度表,存在各种字段,拆分了出部分衍生字段后。可能依然有一些维度针对聚合的数据没有用,我们可以将这些维度进行修剪选出若干维度组,而不是所有维度的组合都预计算。因此我们就根据聚合所需维度创建相应的维度组,
我们称这些相应的组合为相应的聚合组。如原先有n个维度,我们按聚合条件将其分成m维度和p维度,其中 m维度和p维度重复的维度组合只会计算一次。因此两个维度组合
之和总是小n维度组合。
必要维度
必要维度:某一个维度组,其中某个维度总是和其他维度组合使用,我们称这个维度为必要维度。比如时间维度我们聚合统计总是基于时间范围统计。这样在各个维度进行组合的时候就必须包含时间维度,由此我们可知
任意维度组合必须包含时间维度,这样就变成对不包含时间的维度进行组合,由此我们知道原先n个维度变成n-1个维度,组合的数量减少一半。
层级维度
层级维度维度之间有层级关系,比如区域维度中,国家、省、市之间的关系,存在一种顺序关系。我们就不可能抛开上级节点,单独查询下级节点。因为单独查下级节点可能存在重名的情况,我们必须限定上级节点保证重名情况[一年级一班,二年级一班],这种情形就限定了维度组合。回到区域,我们一般只会保留[国家] [国家+省] [国家+省+市]这三种组合,这样我们就将原先的8种组合限定成3种了。
联合维度
联合维度:我们总是同时查询几个维度,而这几个维度没有其他查询组合的可能,我们可以将这个维度看做一个维度。这样往往能将组合的个数降几个数量级,如事实表的外键和维度表的主键就是这种关系了
如原先我们有n个维度,但是我们总是同时查询m个维度,我们可以称这m个维度为联合维度。原先2^n 个维度组合的可能就变成2^(n-m+1)种维度了。
例子,比如我们只会存在 [按天、买方区域、tranceId] [按天、卖方区域、tranceId] [按周、买方区域、tranceId] [按周、卖方区域、tranceId]维度进行统计,比如三种维度正常组合理论上是8种维度,而针对业务,我们可能只需要保留若干层级如 国家省市 以及国家、省、市维度。