首先要明白什么是即席查询。即席查询是用户根据自己的需求,灵活的选择查询条件,系统根据用户的选择生成相应的统计报表。普通查应用查询是定制开发的,即席查询是用户自定义查询条件
1. OLAP分类
1.1 MOLAP
-
M即表示多维(Multidimensional)。大多数MOLAP产品均对原始数据进行预计算,得到用户可能需要的所有结果,将其存储到优化过的多维数组存储中, 能够稳定地快速响应,具有高性能。 -
但高性能并不是没有代价的。首先,MOLAP需要进行预计算,这会花去很多时间。如果每次写入增量数据后均要进行全量预计算,显然是低效率的,因此支持仅对增量数据进行迭代计算非常重要。其次,如果业务发生需求变更,需要进行预定模型之外新的查询操作,现有的MOLAP实例就无能为力了,只能重新进行建模和预计算。 -
因此,MOLAP适合业务需求比较固定,数据量较大的场景。
1.2 ROLAP
-
R即表示关系型(Relational)。与MOLAP相反,ROLAP无需预计算,直接在构成多维数据模型的事实表和维度表上进行计算。更具可扩展性,增量数据导入后,无需进行重新计算,用户有新的查询需求时只需写好正确的SQL语句既能完成获取所需的结果。 -
但ROLAP的不足也很明显,尤其是在数据体量巨大的场景下,用户提交SQL后,获取查询结果所需的时间无法准确预知,可能秒回,也可能需要花费数十分钟甚至数小时。本质上,ROLAP是把MOLAP预计算所需的时间分摊到了用户的每次查询上,肯定会影响用户的查询体验。 -
相比MOLAP,ROLAP的使用门槛更低,在完成星型或雪花型模型的构建,创建对应schema的事实表和维度表并导入数据后,用户只需会写出符合需求的SQL,就可以得到想要的结果。相比创建“数据立方体”,显然更加方便。
1.3 HOLA
- H表示混合型(Hybrid),MOLAP和ROLAP各有优缺点,而且是互斥的。如果能够将两者的优点进行互补,那么是个更好的选择。对于查询频繁而稳定但又耗时的那些SQL,通过预计算来提速;对于较快的查询、发生次数较少或新的查询需求,像ROLAP一样直接通过SQL操作事实表和维度表。。
2. 概述
2.1 定义
Apache Kylin 是一个开源的分布式分析引擎,提供 Hadoop/Spark 之上的 SQL 查询接口 及多维分析(OLAP)能力以支持超大规模数据,最初由 eBay Inc 开发并贡献至开源社区。 它能在亚秒内查询巨大的 Hive 表。用空间换时间,预计算,是一个MOLAP系统
Apache Kylin? 令使用者仅需三步,即可实现超大数据集上的亚秒级查询。
- 定义数据集上的一个星形或雪花形模型
- 在定义的数据表上构建cube
- 使用标准 SQL 通过 ODBC、JDBC 或 RESTFUL API 进行查询,仅需亚秒级响应时间即可获得查询结果
2.2 Kylin架构
- REST Server Rest服务层。入口点,可以提供查询、获取结果、触发 cube 构建任务、获取元数据以及获取用户权限等等,另外可以通过 Restful 接口实现 SQL 查询。
- Query Engine 查询引擎层。当 cube 准备就绪后,查询引擎就能够获取并解析用户查询。把SQL转化为认识的代码
- Routing 路由层。Hive 与 Kylin 的速度差异过大,导致用户无法对查询的速度有一致的期望,很可能大 多数查询几秒内就返回结果了,而有些查询则要等几分钟到几十分钟,因此体验非常糟糕。 最后这个路由功能在发行版中默认关闭。
- Metadata 元数据。是一款元数据驱动型应用程序,元数据管理工具保存 Kylin 中的所有元数据,其中包括最为重要的 cube 元数据。 Kylin 的元数据存储在 hbase 中。
- Cube Build Engine Cube构建引擎。处理所有离线任务,其中包括 shell 脚本、Java API 以及 Map Reduce 任务等等。
2.3 工作原理和过程
Apache Kylin的工作原理本质上是MOLAP(多维立方体分析),即对数据模型做Cube预计算,并利用计算的结果加速查询
-
指定数据模型,定义维度和度量 -
预计算Cube,计算所有Cuboid并保存为物化视图
Kylin 的数据模型本质上是将二维表(Hive 表)转换为 Cube,然后将 Cube 存储到 HBase 表中,也就是两次转换。
- 第一次转换,其实就是传统数据库的 Cube 化,Cube 由 CuboId 组成,下图每个节点都被称为一个 CuboId,CuboId 表示固定列的数据数据集合,比如“ AB” 两个维度组成的 CuboId 的数据集合等价于以下 SQL 的数据集合:
select A, B, sum(M), sum(N) from table group by A, B
- 第二次转换,是将 Cube 中的数据存储到 HBase 中,转换的时候 CuboId 和维度信息序列化到 rowkey,度量列组成列簇。在转换的时候数据进行了预聚合。下图展示了 Cube 数据在 HBase 中的存储方式。
2.4 特点
-
标准 SQL 接口:Kylin 是以标准的 SQL 作为对外服务的接口。 -
支持超大数据集: Kylin 对于大数据的支撑能力可能是目前所有技术中最为领先的。 早在 2015 年 eBay 的生产环境中就能支持百亿记录的秒级查询,之后在移动的应用场景中 又有了千亿记录秒级查询的案例。 -
亚秒级响应:Kylin 拥有优异的查询相应速度,这点得益于预计算,很多复杂的计算, 比如连接、聚合,在离线的预计算过程中就已经完成,这大大降低了查询时刻所需的计算量, 提高了响应速度。 -
可伸缩性和高吞吐率:单节点 Kylin 可实现每秒 70 个查询,还可以搭建 Kylin 的集 群。 -
BI 工具集成,ODBC、JDBC、RestAPI、Zepplin插件 -
安装 Kylin 前需先部署好 Hadoop、Hive、Zookeeper、Hbase、Spark,
2.4 和Druid 比较
| Kylin | Druid |
---|
优点 | 1、支持数据规模超大(HBase),精确去重 2、易用性强,支持标准SQL 3、性能很高,查询速度很快 | 1、支持的数据规模大(本地存储+DeepStorage–HDFS) 2、性能高,列存压缩,预聚合加上倒排索引以及位图索引,秒级查询 3、是一个实时处理时序数据的Olap数据库,因为它的索引首先按照时间分片,查询的时候也是按照时间线去路由索引,可以通过kafka实时导入数据 | 缺点 | 1、灵活性较弱,不支持adhoc查询;且没有二级索引,过滤时性能一般。 2、处理方式复杂,需要定义Cube预计算;当维度超过20个时,存储可能会爆炸式增长;且无法查询明细数据了;维护复杂 3、实时性很差,很多时候只能查询前一天或几个小时前的数据。 | 1、灵活性适中,虽然维度之间随意组合,但不支持adhoc查询,不能自由组合查询,且丢失了明细数据 2、易用性较差,不支持join,不支持更新,sql支持很弱(有些插件类似于pinot的PQL语言),只能JSON格式查询;对于去重操作不能精准去重。 3、处理方式复杂,需要流处理引擎将数据join成宽表,维护相对复杂;对内存要求较高。 | 适用场景 | 1. 适合对实时数据需求不高,但响应时间较高的查询,且维度较多,需求较为固定的特定查询;而不适合实时性要求高的adhoc类查询。 2. Hadoop/HBase 做计算和存储,使用 SQL 查询,提供 JDBC/ODBC 驱动与常见 BI 工具集成 | 1. 适合那种数据量大,对实时性要求高且响应时间短,以及维度较少且需求固定的简单聚合类查询(sum,count,TopN),多以storm和flink组合进行预处理;而不适合需要join、update和支持SQL和窗口函数等复杂的adhoc查询。 2. 有自己独立的分布式集群,能够实时摄入数据,有自己的查询接口(与BI兼容性较弱),通常多用于实时要求高的场景 |
3. Cube 构建原理
3.1 维度和度量
-
维度 :即观察数据的角度。比如员工数据,可以从性别角度来分析,也可以更加细化, 从入职时间或者地区的维度来观察。维度是一组离散的值,比如说性别中的男和女,或者时 间维度上的每一个独立的日期。因此在统计时可以将维度值相同的记录聚合在一起,然后应 用聚合函数做累加、平均、最大和最小值等聚合计算。 -
度量:即被聚合(观察)的统计值,也就是聚合运算的结果。比如说员工数据中不同性 别员工的人数,又或者说在同一年入职的员工有多少。
3.2 Cube 和 Cuboid
? 给定一个数据模型,我们可以对其上的所有维度进行聚合,对于 N 个维度来说,组合的所有可能性共有 2^n 种。对于每一种维度的组合,将度量值做聚合计算,然后将结果保存 为一个物化视图,称为 Cuboid。所有维度组合的 Cuboid 作为一个整体,称为 Cube。
下面举一个简单的例子说明,假设有一个电商的销售数据集,其中维度包括时间[time]、 商品[item]、地区[location]和供应商[supplier],度量为销售额。那么所有维度的组合就有 2^4 = 16 种,如下图所示:
-
一维度(1D)的组合有:[time]、[item]、[location]和[supplier]4 种; -
二维度(2D)的组合有:[time, item]、[time, location]、[time, supplier]、[item, location]、 [item, supplier]、[location, supplier]3 种; -
三维度(3D)的组合也有 4 种; -
最后还有零维度(0D)和四维度(4D)各有一种,总共 16 种。
注意:每一种维度组合就是一个 Cuboid,16 个 Cuboid 整体就是一个 Cube。
3.3 Cube 存储原理
3.4 Cube构建方法
可以在property中设置
3.4.1 逐层构建算法 layer
每一轮的计算都是一个 MapReduce 任务,且串行执行;一个 N 维的 Cube,至少需要 N 次 MapReduce Job。
总体而言,该算法的效率较低,尤其是当 Cube 维度数较大的时候。
? 在逐层算法中,按维度数逐层减少来计算,每个层级的计算(除了第一层, 它是从原始数据聚合而来),是基于它上一层级的结果来计算的。比如,[Group by A, B]的 结果,可以基于[Group by A, B, C]的结果,通过去掉 C 后聚合得来的;这样可以减少重复计 算;当 0 维度 Cuboid 计算出来的时候,整个 Cube 的计算也就完成了。一般来说是多个MR任务
算法优点:
-
此算法充分利用了 MapReduce 的优点,处理了中间复杂的排序和 shuffle 工作,故而 算法代码清晰简单,易于维护; -
受益于 Hadoop 的日趋成熟,此算法非常稳定,即便是集群资源紧张时,也能保证最 终能够完成。
算法缺点:
-
当 Cube 有比较多维度的时候,所需要的 MapReduce 任务也相应增加;由于 Hadoop 的任务调度需要耗费额外资源,特别是集群较庞大的时候,反复递交任务造成的额外开销会 相当可观; -
由于 Mapper 逻辑中并未进行聚合操作,所以每轮 MR 的 shuffle 工作量都很大,导致效率低下。 -
对 HDFS 的读写操作较多:由于每一层计算的输出会用做下一层计算的输入,这些 Key-Value 需要写到 HDFS 上;当所有计算都完成后,Kylin 还需要额外的一轮任务将这些 文件转成 HBase 的 HFile 格式,以导入到 HBase 中去;
3.4.2 快速构建算法(inmem)
该算 法的主要思想是,每个 Mapper 将其所分配到的数据块,计算成一个完整的小 Cube 段(包 含所有 Cuboid)。每个 Mapper 将计算完的 Cube 段输出给 Reducer 做合并,生成大 Cube,
与逐层构建算法相比,快速算法主要有两点不同:
-
Mapper 会利用内存做预聚合,算出所有组合;Mapper 输出的每个 Key 都是不同的, 这样会减少输出到 Hadoop MapReduce 的数据量,Combiner 也不再需要; -
一轮 MapReduce 便会完成所有层次的计算,减少 Hadoop 任务的调配。
4. Cube构建优化
4.1 检查问题Cube
? 在Web GUI的Model页面选择一个READY状态的Cube,当我们把光标移到该Cube的Cube Size列时,Web GUI会提示Cube的源数据大小,以及当前Cube的大小除以源数据大小的比例,称为膨胀率(Expansion Rate)。
? 一般来说,Cube的膨胀率应该在0%~1000%之间,如果一个Cube的膨胀率超过1000%,那么Cube管理员应当开始挖掘其中的原因。通常,膨胀率高有以下几个方面的原因。
-
Cube中的维度数量较多,且没有进行很好的Cuboid剪枝优化,导致Cuboid数量极多; -
Cube中存在较高基数的维度,导致包含这类维度的每一个Cuboid占用的空间都很大,这些Cuboid累积造成整体Cube体积变大;
4.2 并发粒度优化
? 当Segment中某一个Cuboid的大小超出一定的阈值时,系统会将该Cuboid的数据分片到多个分区中,以实现Cuboid数据读取的并行化,从而优化Cube的查询速度。构建引擎根据Segment估计的大小,以及参数
- kylin.hbase.region.cut 的设置决定Segment在存储引擎中总共需要几个分区来存储,如果存储引擎是HBase,那么分区的数量就对应于HBase中的Region数量。kylin.hbase.region.cut的默认值是5.0,单位是GB,也就是说对于一个大小估计是50GB的Segment,构建引擎会给它分配10个分区。
- kylin.hbase.region.count.min(默认为1)和kylin.hbase.region.count.max(默认为500)两个配置来决定每个Segment最少或最多被划分成多少个分区。
4.3 使用聚合组(Aggregation group)
聚合组(Aggregation Group)是一种强大的剪枝工具。根据业务需求划分成若干组(当然也可以是一个组)
- 强制维度(Mandatory),强制维度自己也不能单独出现。比如规定有A,那么所有能够提供查询的组里必须有A
- 层级维度(Hierarchy),年-月-日,限定月的时候必须带上年不然没有意义。有A必有B
- 联合维度,这些联合维度要么一起出现,要么都不出现。
4.4 使用衍生维度(derived dimension)
实际上就是把预计算的时间分摊到查询的时候,如果从维度表主键到某个维度表维度所需要的聚合工作量非常大,则不建议使用衍生维度。
? 衍生维度用于在有效维度内将维度表上的非主键维度排除掉,并使用维度表的主键(其实是事实表上相应的外键)来替代它们。Kylin 会在底层记录维度表主键与维度表其他维度之间的映射关系,以便在查询时能够动态地将维度表的主键“翻译”成这些非主键维度,并进行实时聚合。
4.5 Row Key优化
Kylin 会把所有的维度按照顺序组合成一个完整的 Rowkey,并且按照这个 Rowkey 升序 排列 Cuboid 中所有的行。
- 被用作过滤的维度放在前边。
- 基数大的维度放在基数小的维度前边。 当逐层构建的时候,三层(1101、1110)到两层(11)的聚合,会选择cuboid小的(1101),所以基数大的维度向前调,能够更好聚合
5. 创建项目流程
- 登陆系统 并 创建工程 (项目名和描述)
- 选择加载数据的方式(Hive表 或者 Kafka流),并同步数据
- 创建Model(名称和描述),选择事实表、维度表,及join字段和方式(left、inner等);选择维度信息,度量信息;添加分区信息及过滤条件
- 创建Cube ,添加真正的维度字段(将来会影响 Cuboid 的个数,并且只能从 model 维度字段里面选择),选择维度表的维度字段和类型(normal 和 Derived),如果是3个正常维度cuboid个数是2^3 -1 = 7个。添加真正度量值字段(将来预计算的字段值,只能从 model 度量值里面选择),动态更新相关、高阶设置、property设置、Cube信息展示,配置完成。可以查看cube的执行计划和底层执行的SQL
- 构建Cube触发预计算,查看Build进度和详细执行情况
#!/bin/bash
cube_name cube_name=$1
if [ -n "$2" ]
then
do_date=$2
else
do_date=`date -d '-1 day' +%F` fi
start_date_unix=`date -d "$do_date 08:00:00" +%s`
start_date=$(($start_date_unix*1000))
curl -X PUT -H "Authorization: Basic QURNSU46S1lMSU4=" -H 'Content-Type: application/json' -d '{"startTime":'$start_date', "endTime":'$stop_date', "buildType":"BUILD"}' http://hadoop102:7070/kylin/api/cubes/$cube_name/build
6. 使用注意事项
- 只能按照构建 Model 的连接条件来写 SQL,创建Model时用的是什么join就只能用什么join
- 查询时事实表在前,维度表在后
- 只能按照构建 Cube 时选择的维度字段分组统计
- 只能统计构建 Cube 时选择的度量值字段
|