Apache Kylin 介绍 上篇

834 阅读4分钟

提要

我之前从事过医疗相关平台的研发。该平台主要是通过接入各个社区医院,赋能医生进行电话随访任务。随着接入的社区医院越来越多,产品希望有一个统计分析的模块,主要统计各个接入的社区医院以及接入的城市整体外呼情况。由于平台架构,数据库当时主要是mysql,虽然做了数据分片,以及将原先单机模式的mysql架构扩展成读写分离的主从架构,但是对于实时获取统计分析的结果,尤其是大范围的统计结果时,确实有着不少压力。在这里我们就思考使用其他的开源产品,首选就是kylin了。由此我想做一个kylin相关的学习指南,帮助读者迅速入门。注意本文档中很多使用《Apache Kylin权威指南(第2版)》中的例子,其中也加入我的一些阅读所感与思考,和对部分知识进行重新归类以及知识点的补充。推荐读者阅读原书和官方文档。

背景

Apache软件基金会(Apache Software Foundation,ASF)的160多个顶级项目中,Apache Kylin是唯一一个来自中国的Apache顶级开源项目。Apache Kylin最初诞生于eBay中国研发中心,该中心坐落于上海浦东新区。2013年9月底该研发中心开始进行POC测试并组建团队。 2013年年初,在eBay内部使用的传统数据仓库及商业智能平台碰到了"瓶颈",传统架构只支持垂直扩展,通过在一台计算机上增加CPU和内存等资源来提升计算机的数据处理能力。相对于数据指数级的增长,单机扩展很快达到极限,不可避免地遇到了"瓶颈"。此外,Hadoop大数据平台虽然能存储和批量处理大规模数据,但与BI平台的连接技术还不够成熟,无法提供高效的交互式查询。于是为了解决传统数据仓库的性能瓶颈以及高效交互式查询,kylin就诞生了。这里提及一下这两点,后面我们将着重上述的两点介绍kylin。

理论知识

由于kylin学习过程中可能需要你有一点组合相关知识,这里复习一下高中数学排列组合相关公式以及概念。

一、排列

表示从n个非重复的数中,任意取出m个数(m <= n),按照一定的顺序排成一列,这个叫做从n个元素取出m个元素的一个排列。当 m = n 的时候我们称为全排列。用符号A(n,m)。

A(n,m) = n!/(n-m)!

如:我们从3个学生中,任意取出2个学生,按照一定顺序排成一列。会出现多少列?

按排列公式,A(3,2) = 3!/(3-2)!= 3*2*1/1 = 6 如果我们将3名学生按符号来代替则是数列a,b,c。我们任意取出2个数,根据计算有六种排列方式,排列方式如下。

(a,b)、(a,c)、(b,c)、(b,a)、(c,a)、(c,b)

二、组合

表示从n个非重复的数中,任意取出m个数(m <= n)并成一组,这个叫做从n个元素取出m个元素的一个组合。用符号c(n,m) 表示。

c(n,m) = A(n,m)/m! = n!/m!(n-m)!

如:我们从3个学生中,任意取出2个学生并成一组。则会出现的组合数。

按组合公式,c(3,2) = A(3,2)/2! = 3!/2!(3-2)! = 3*2*1/2*1*1 = 3 如果我们将3名学生按符号来代替则是数列a,b,c。任意取出2个数并成一组,根据计算有三种组合方式。组合方式如下。

(a,b)、(a,c)、(b,c)

三、组合总数

指从n个不同元素里依次取出0个,1个,2个,n个不同元素的所有组合数的总和。

c(n,0) + c(n,1) + c(n,2) + c(n,3) + ...... + c(n,n) = 2^n

如:书店里有4本书,请问从书店买书的所有可能?

按组合总数,c(4,0) + c(4,1) + c(4,2) + c(4,3) + c(4,4) = 4!/0!*(4-0)! +4!/1!*(4-1)! + 4!/2!*(4-2)! + 4!/3!*(4-3)! + 4!/4!*(4-4)! = 1 + 4 + 6 + 4 + 1 = 16

如果我们将4本书按符号来代替则是数列a,b,c,d。依次购买0本,1本,2本,3本,4本书的所有组合数的总和。组合方式如下。

()

(a)、(b)、(c)、(d)

(a,b)、(a,c)、(a,d)、(b,c)、(b,d)、(c,d)

(a,b,c)、(a,b,d)、(a,c,d)、(b,c,d)

(a,b,c,d)

介绍

自2006年hadoop诞生以来,大数据的存储和批处理问题得到了妥善解决,而如何高速地分析数据也就成为下一个挑战。于是各种"SQL-on-Hadoop"技术应运而生,其中以Hive为代表,Impala、Presto、Phoenix、Drill、Spark SQL等紧随其后,它们的主要技术是“大规模并行处理”(Massively Parallel Processing,MPP)和"列式存储"(Columnar Storage)。

并行处理

大规模并行处理可以调动多台机器进行并行计算,用线性增加资源来换取计算时间的线性下降。

列式存储

列式存储则将记录按列存放,不仅在访问时可以只读取需要的列,更可以利用存储设备擅长连续读取的特点,大大提高读取的速率。这两项关键技术使得Hadoop上的SQL查询速度从小时级提高到了分钟级。

传统的数据库是关系型的,且是按行来存储的,如下图。

姓名地址学校年龄
张三安徽省合肥市合肥学院18
李四安徽省阜阳市阜阳师范-
张三安徽省铜陵市-16
王二麻安徽省芜湖市--

如上图,我们发现这种按行存储都就是格式固定,每一行都一样,即使你不用,也必须空到那里,而不能没有,这样的空行也是需要占用一定的存储空间的,如果这样的空行占比较大的话,势必带来较大的存储空间的浪费。

于是我们将数据按列的方式进行存储,将原来每一列的数据,分为一行来存储。这样行式的存储中空行的数据在列式方式存储就不存在了,节约磁盘空间。如下。

主键列名列值
1姓名张三
1地址安徽省合肥市
1学校合肥学院
1年龄18
2姓名李四
2地址安徽省阜阳市
2学校阜阳师范
3姓名张三
3地址安徽省铜陵市
3年龄16

注意:为啥主键可以重复呢?其实这里列存储只是会存储3行数据,只是表格展示容易产生误解。

如果以语言中的概念来解释行存储和列式存储,行存储更像定义的Object,格式固定,列式更像一个hashmap,随意添加key-value。

然而分钟级别的查询响应仍然与交互式分析的现实需求相差很远。这是因为大规模并行处理和列式存储虽然提高了计算和存储的速度,但并没有改变查询问题本身的时间复杂度,也没有改变查询时间与数据量呈线性增长的关系这一事实。假设查询1亿条记录耗时1分钟,那么查询10亿条记录就需要10分钟,查询100亿条就至少需要1小时40分钟。

其他优化方法

优化技术可以缩短查询的时间,比如更快的存储、更高效的压缩算法和索引技术等,但总体来说,查询性能与数据量呈线性相关这一事实无法改变。虽然大规模并行处理允许十倍或者百倍地扩张计算集群,以期保持分钟级别的查询速度,但购买和部署十倍、百倍的计算集群又很难做到,更何况还需要高昂的硬件运维成本。

解决传统数据仓库的性能瓶颈

Apache Kylin的初衷就是解决千亿、万亿条记录的秒级查询问题,其中的关键就是打破查询时间随着数据量呈线性增长的这一规律。仔细思考大数据olap[on-line analytical processin],我们可以注意到两个事实。

● 大数据查询要的一般是统计结果,是多条记录经过聚合函数计算后的统计值。原始的记录则不是必需的,或者被访问的频率和概率极低。

● 聚合是按维度进行的,而维度的聚合可能性是有限的,一般不随数据的膨胀而线性增长。

基于以上两点,我们得到一个新的思路——"预计算",不是并行处理,也不是列式存储。

什么是预计算

尽量多地预先计算聚合结果,在查询时刻也尽量使用预计算的结果得出查询结果,从而避免直接扫描可能无限增长的原始记录。

举个例子:

SELECT item, SUM(sell_amount)
FROM sell_details
WHERE sell_date='2016-10-01'
GROUP BY item
ORDER BY SUM(sell_amount) DESC

传统的方法需要扫描所有的记录,找到10月1日的销售记录,然后按商品聚合销售额,最后排序返回。假如10月1日有1亿条交易,那么查询必需读取并累计至少1亿条记录,且查询速度会随将来销量的增加而逐步下降,如果日交易量提高至2亿条,那查询执行的时间可能会增加一倍。

预计算的方法则会事先按维度[sell_date,item]计算SUM(sell_amount)并将其存储下来,在查询时找到10月1日的销售商品就可以直接排序返回了。

基于维度[sell_date,item]计算SUM(sell_amount)并将其存储下的数据如下:

时间(维度)商品(维度)销售额(度量)
2016-10-01衣服300
2016-10-01帽子600
2016-10-01600
2016-10-02衣服700
2016-10-02帽子900
2016-10-02400
2016-10-03衣服300
2016-10-03帽子100
2016-10-03200
2016-10-04衣服300
2016-10-04帽子400
2016-10-04900
......

我们查询时尽量使用预计算的结果得出查询结果。而不是对原始数据进行检索。

时间(维度)商品(维度)销售额(度量)
2016-10-01衣服300
2016-10-01帽子600
2016-10-01600

由此"预计算"就是Kylin在"大规模并行处理"和"列式存储"之外,提供给大数据分析的第三个关键技术。

注意:预计算的维度,需要是结构化的数据如:时间、颜色集合等。非是即否,要么存于集合之中,要么存在集合之外。

高效交互式查询

以SQL的形式高效查询

Apache Kylin使用Apache calcite做SQL语法分析,并且Apache Kylin深度定制了calcite。Apache calcite是一个开源的SQL引擎,它提供了标准SQL语言解析、多种查询优化和连接各种数据源的能力。calcite项目在Hadoop中越来越引人注目,并被众多项目集成为SQL解析器。

在Apache Kylin一条查询的执行过程主要分成四个部分:词法分析、逻辑执行计划、物理执行计划和执行。以如下SQL语句为例:

SELECT TEST_CAL_DT.WEEK_BEG_DT, SUM(TEST_KYLIN_FACT.PRICE) 
FROM TEST_KYLIN_FACT AS FACT
INNER JOIN EDW.TEST_CAL_DT as DT ON FACT.CAL_DT = DT.CAL_DT
WHERE FACT.CAL_DT > '2017-01-01'
GROUP TEST_CAL_DT.WEEK_BEG_DT
词法分析

在词法分析阶段,calcite将该查询拆分成包含关键词识别的字符段,如图

词法分析结果展示

逻辑执行计划

calcite根据词法分析的结果,生成一个逻辑执行计划,如图

逻辑执行计划

物理执行计划

calcite会基于规则对逻辑执行计划进行优化,在优化的过程中根据这些规则[翻译后的逻辑计划]将算子转换为对应的物理执行算子[kylin中定义的对象]。

物理算子转换

calcite会基于规则对逻辑执行计划进行优化,在优化的过程中根据这些规则将算子转化为对应的物理执行算子。而Apache Kylin则在其中增加了一些优化策略。首先,在每一个优化规则中将对应的物理算子转换成Apache Kylin自己的OLAPxxxRel算子。然后根据每一个算子中保持的信息构造本次查询的上下文OLAPContext。之后再根据本次查询中使用的维度列、度量信息等查询是否有满足本次查询的cuboid,如果有则将其保存在OLAPContext的realization中。如下图

优化后的物理执行计划

执行

calcite会根据这个执行计划动态生成执行代码。并且根据之前记录在OLAPContext中的realization信息,到HBase中读取相对应的已经构建好的cuboid数据,用以回答查询。如下图

SQL的编译执行

查询下压

在Apache Kylin中的查询,只有预先针对查询内的维度和度量进行建模并构建cube才能够回答查询。因此在Apache Kylin中针对于无法击中cube的查询。会执行查询下压,查询下压的本质是将无法用cube回答的查询路由到hive或spark这类查询引擎,用以回答该查询。如下图

查询下压的实现方式展示

注意:查询下压的默认是关闭的

交互式查询

用户可以从上方查询系统发送SQL来进行查询分析。Kylin提供了多样的REST API、JDBC/ODBC接口,提供给应用系统进行交互式查询。

参考文献&学习资源

书籍 :Apache Kylin权威指南(第2版)

简书 :行式存储VS列式存储