Kylin是什么?java
Apache Kylin™是一个开源的、分布式的分析型数据仓库,提供Hadoop/Spark 之上的 SQL 查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由 eBay 开发并贡献至开源社区。它能在亚秒内查询巨大的表。nginx
Apache Kylin™ 令使用者仅需三步,便可实现超大数据集上的亚秒级查询。web
- 定义数据集上的一个星形或雪花形模型
- 在定义的数据表上构建cube
- 使用标准 SQL 经过 ODBC、JDBC 或 RESTFUL API 进行查询,仅需亚秒级响应时间便可得到查询结果
若是没有Kylin算法
大数据在数据积累后,须要计算,而数据越多,算力越差,内存需求也越高,询时间与数据量成线性增加,而这些对于Kylin影响不大,大数据中硬盘每每比内存要更便宜,Kylin经过与计算的形式,以空间换时间,亚秒级的响应让人们爱不释手。sql
注:所谓询时间与数据量成线性增加:假设查询 1 亿条记录耗时 1 分钟,那么查询 10 亿条记录就需 10分钟,100 亿条记录就至少须要 1 小时 40 分钟。shell
http://kylin.apache.org/cn/数据库
Kylin 提供与多种数据可视化工具的整合能力,如 Tableau,PowerBI 等,令用户可使用 BI 工具对 Hadoop 数据进行分析apache
是一套面向应用程序开发的入口点,旨在实现针对 Kylin 平台的应用开发 工做。 此类应用程序能够提供查询、获取结果、触发 cube 构建任务、获取元数据以及获取 用户权限等等。另外能够经过 Restful 接口实现 SQL 查询。json
当 cube 准备就绪后,查询引擎就可以获取并解析用户查询。它随后会与系统中的其它 组件进行交互,从而向用户返回对应的结果。vim
在最初设计时曾考虑过将 Kylin 不能执行的查询引导去 Hive 中继续执行,但在实践后 发现 Hive 与 Kylin 的速度差别过大,致使用户没法对查询的速度有一致的指望,极可能大 多数查询几秒内就返回结果了,而有些查询则要等几分钟到几十分钟,所以体验很是糟糕。 最后这个路由功能在发行版中默认关闭。
Kylin 是一款元数据驱动型应用程序。元数据管理工具是一大关键性组件,用于对保存 在 Kylin 当中的全部元数据进行管理,其中包括最为重要的 cube 元数据。其它所有组件的 正常运做都需以元数据管理工具为基础。 Kylin 的元数据存储在 hbase 中。
这套引擎的设计目的在于处理全部离线任务,其中包括 shell 脚本、Java API 以及 MapReduce 任务等等。任务引擎对 Kylin 当中的所有任务加以管理与协调,从而确保每一项任务 都能获得切实执行并解决其间出现的故障。
vim /etc/profile #>>>注意地址指定为本身的 #kylin export KYLIN_HOME=/usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60 export PATH=$PATH:$KYLIN_HOME/bin #cdh export CDH_HOME=/opt/cloudera/parcels/CDH-6.2.0-1.cdh6.2.0.p0.967373 #hadoop export HADOOP_HOME=${CDH_HOME}/lib/hadoop export HADOOP_DIR=${HADOOP_HOME} export HADOOP_CLASSPATH=${HADOOP_HOME} export PATH=$PATH:$HADOOP_HOME/bin export PATH=$PATH:$HADOOP_HOME/sbin #hbase export HBASE_HOME=${CDH_HOME}/lib/hbase export PATH=$PATH:$HBASE_HOME/bin #hive export HIVE_HOME=${CDH_HOME}/lib/hive export PATH=$PATH:$HIVE_HOME/bin #spark export SPARK_HOME=${CDH_HOME}/lib/spark export PATH=$PATH:$SPARK_HOME/bin #kafka export KAFKA_HOME=${CDH_HOME}/lib/kafka export PATH=$PATH:$KAFKA_HOME/bin #<<< source /etc/profile
usermod -s /bin/bash hdfs su hdfs hdfs dfs -mkdir /kylin hdfs dfs -chmod a+rwx /kylin su
mkdir /usr/local/src/kylin cd /usr/local/src/kylin tar -zxvf apache-kylin-3.0.1-bin-cdh60.tar.gz cd /usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60
在CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar后添加
>>--- :/opt/cloudera/parcels/CDH/lib/hbase/lib/* <<---
cp /opt/cloudera/cm/common_jars/commons-configuration-1.9.cf57559743f64f0b3a504aba449c9649.jar /usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60/tomcat/lib
这2步不作会引发 Could not find or load main class org.apache.hadoop.hbase.util.GetJavaProperty
./bin/kylin.sh start #中止 ./bin/kylin.sh stop
访问端口7070
帐号密码:ADMIN / KYLIN
vim /etc/profile #>>>注意地址指定为本身的 #kylin export KYLIN_HOME=/usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60 export PATH=$PATH:$KYLIN_HOME/bin #cdh export CDH_HOME=/opt/cloudera/parcels/CDH-6.2.0-1.cdh6.2.0.p0.967373 #hadoop export HADOOP_HOME=${CDH_HOME}/lib/hadoop export HADOOP_DIR=${HADOOP_HOME} export HADOOP_CLASSPATH=${HADOOP_HOME} export PATH=$PATH:$HADOOP_HOME/bin export PATH=$PATH:$HADOOP_HOME/sbin #hbase export HBASE_HOME=${CDH_HOME}/lib/hbase export PATH=$PATH:$HBASE_HOME/bin #hive export HIVE_HOME=${CDH_HOME}/lib/hive export PATH=$PATH:$HIVE_HOME/bin #spark export SPARK_HOME=${CDH_HOME}/lib/spark export PATH=$PATH:$SPARK_HOME/bin #kafka export KAFKA_HOME=${CDH_HOME}/lib/kafka export PATH=$PATH:$KAFKA_HOME/bin #<<< source /etc/profile
usermod -s /bin/bash hdfs su hdfs hdfs dfs -mkdir /kylin hdfs dfs -chmod a+rwx /kylin su
mkdir /usr/local/src/kylin cd /usr/local/src/kylin tar -zxvf apache-kylin-3.0.1-bin-cdh60.tar.gz cd /usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60
在CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar后添加
vim /opt/cloudera/parcels/CDH/lib/hbase/bin/hbase >>--- :/opt/cloudera/parcels/CDH/lib/hbase/lib/* <<---
cp /opt/cloudera/cm/common_jars/commons-configuration-1.9.cf57559743f64f0b3a504aba449c9649.jar /usr/local/src/kylin/apache-kylin-3.0.1-bin-cdh60/tomcat/lib
这2步不作会引发 Could not find or load main class org.apache.hadoop.hbase.util.GetJavaProperty
Kylin根据本身的运行职责状态,能够划分为如下三大类角色
vim conf/kylin.properties >>---- #指定元数据库路径,默认值为 kylin_metadata@hbase,确保kylin集群使用一致 kylin.metadata.url=kylin_metadata@hbase #指定 Kylin 服务所用的 HDFS 路径,默认值为 /kylin,请确保启动 Kylin 实例的用户有读写该目录的权限 kylin.env.hdfs-working-dir=/kylin kylin.server.mode=all kylin.server.cluster-servers=cdh01.cm:7070,cdh02.cm:7070,cdh03.cm:7070 kylin.storage.url=hbase #构建任务失败后的重试次数,默认值为 0 kylin.job.retry=2 #最大构建并发数,默认值为 10 kylin.job.max-concurrent-jobs=10 #构建引擎间隔多久检查 Hadoop 任务的状态,默认值为 10(s) kylin.engine.mr.yarn-check-interval-seconds=10 #MapReduce 任务启动前会依据输入预估 Reducer 接收数据的总量,再除以该参数得出 Reducer 的数目,默认值为 500(MB) kylin.engine.mr.reduce-input-mb=500 #MapReduce 任务中 Reducer 数目的最大值,默认值为 500 kylin.engine.mr.max-reducer-number=500 #每一个 Mapper 能够处理的行数,默认值为 1000000,若是将这个值调小,会起更多的 Mapper kylin.engine.mr.mapper-input-rows=1000000 #启用分布式任务锁 kylin.job.scheduler.default=2 kylin.job.lock=org.apache.kylin.storage.hbase.util.ZookeeperJobLock <<----
全部Kylin节点
./bin/kylin.sh start #中止 ./bin/kylin.sh stop
yum -y install nginx vim /etc/nginx/nginx.conf >>---http中添加替换内容 upstream kylin { least_conn; server 192.168.37.10:7070 weight=8; server 192.168.37.11:7070 weight=7; server 192.168.37.12:7070 weight=7; } server { listen 9090; server_name localhost; location / { proxy_pass http://kylin; } } <<--- #重启 nginx 服务 systemctl restart nginx
访问任何节点的7070端口均可以进入kylin
访问nginx所在机器9090端口/kylin负载均衡进入kylin
帐号密码:ADMIN / KYLIN
自从 10 年前 Hadoop 诞生以来,大数据的存储和批处理问题均获得了妥善解决,而如何高速地分析数据也就成为了下一个挑战。因而各式各样的“SQL on Hadoop”技术应运而生,其中以 Hive 为表明,Impala、Presto、Phoenix、Drill、 SparkSQL 等紧随其后(何以解忧--惟有CV SQL BOY)。它们的主要技术是“大规模并行处理”(Massive Parallel Processing,MPP)和“列式存储”(Columnar Storage)。
大规模并行处理能够调动多台机器一块儿进行并行计算,用线性增长的资源来换取计算时间的线性降低。
列式存储则将记录按列存放,这样作不只能够在访问时只读取须要的列,还能够利用存储设备擅长连续读取的特色,大大提升读取的速率。
这两项关键技术使得 Hadoop 上的 SQL 查询速度从小时提升到了分钟。 然而分钟级别的查询响应仍然离交互式分析的现实需求还很远。分析师敲入 查询指令,按下回车,还须要去倒杯咖啡,静静地等待查询结果。获得结果以后才能根据状况调整查询,再作下一轮分析。如此反复,一个具体的场景分析经常须要几小时甚至几天才能完成,效率低下。 这是由于大规模并行处理和列式存储虽然提升了计算和存储的速度,但并无改变查询问题自己的时间复杂度,也没有改变查询时间与数据量成线性增加的关系这一事实。
假设查询 1 亿条记录耗时 1 分钟,那么查询 10 亿条记录就需 10分钟,100 亿条记录就至少须要 1 小时 40 分钟。 固然,能够用不少的优化技术缩短查询的时间,好比更快的存储、更高效的压缩算法,等等,但整体来讲,查询性能与数据量呈线性相关这一点是没法改变的。虽然大规模并行处理容许十倍或百倍地扩张计算集群,以指望保持分钟级别的查询速度,但购买和部署十倍或百倍的计算集群又怎能轻易作到,更况且还有 高昂的硬件运维成本。 另外,对于分析师来讲,完备的、通过验证的数据模型比分析性能更加剧要, 直接访问纷繁复杂的原始数据并进行相关分析其实并非很友好的体验,特别是在超大规模的数据集上,分析师将更多的精力花在了等待查询结果上,而不是在更加剧要的创建领域模型上。
**Apache Kylin 的初衷就是要解决千亿条、万亿条记录的秒级查询问题,其中的关键就是要打破查询时间随着数据量成线性增加的这个规律。根据OLAP分析,能够注意到两个结论: **
大数据查询要的通常是统计结果,是多条记录通过聚合函数计算后的统计值。原始的记录则不是必需的,或者访问频率和几率都极低。
聚合是按维度进行的,因为业务范围和分析需求是有限的,有意义的维度聚合组合也是相对有限的,通常不会随着数据的膨胀而增加。
**基于以上两点,咱们能够获得一个新的思路——“预计算”。应尽可能多地预先计算聚合结果,在查询时刻应尽可能使用预算的结果得出查询结果,从而避免直 接扫描可能无限增加的原始记录。 **
举例来讲,使用以下的 SQL 来查询 11月 11日 那天销量最高的商品:
select item,sum(sell_amount) from sell_details where sell_date='2020-11-11' group by item order by sum(sell_amount) desc
用传统的方法时须要扫描全部的记录,再找到 11月 11日 的销售记录,而后按商品聚合销售额,最后排序返回。
假如 11月 11日 有 1 亿条交易,那么查询必须读取并累计至少 1 亿条记录,且这个查询速度会随未来销量的增长而逐步降低。若是日交易量提升一倍到 2 亿,那么查询执行的时间可能也会增长一倍。
而使用预 计算的方法则会事先按维度 [sell_date , item] 计 算 sum(sell_amount)并存储下来,在查询时找到 11月 11日 的销售商品就能够直接排序返回了。读取的记录数最大不会超过维度[sell_date,item]的组合数。
显然这个数字将远远小于实际的销售记录,好比 11月 11日 的 1 亿条交易包含了 100万条商品,那么预计算后就只有 100 万条记录了,是原来的百分之一。而且这些 记录已是按商品聚合的结果,所以又省去了运行时的聚合运算。从将来的发展来看,查询速度只会随日期和商品数目(时间,商品维度)的增加而变化,与销售记录的总数再也不有直接联系。假如日交易量提升一倍到 2 亿,但只要商品的总数不变,那么预计算的结果记录总数就不会变,查询的速度也不会变。
预计算就是 Kylin 在“大规模并行处理”和“列式存储”以外,提供给大数据分析的第三个关键技术。
--建立数据库kylin_hive create database kylin_hive; --建立表部门表dept create external table if not exists kylin_hive.dept( deptno int, dname string, loc int ) row format delimited fields terminated by '\t'; --添加数据 INSERT INTO TABLE kylin_hive.dept VALUES(10,"ACCOUNTING",1700),(20,"RESEARCH",1800),(30,"SALES",1900),(40,"OPERATIONS",1700) --查看数据 SELECT * FROM kylin_hive.dept --建立员工表emp create external table if not exists kylin_hive.emp( empno int, ename string, job string, mgr int, hiredate string, sal double, comm double, deptno int) row format delimited fields terminated by '\t'; --添加数据 INSERT INTO TABLE kylin_hive.emp VALUES(7369,"SMITHC","LERK",7902,"1980-12-17",800.00,0.00,20),(7499,"ALLENS","ALESMAN",7698,"1981-2-20",1600.00,300.00,30),(7521,"WARDSA","LESMAN",7698,"1981-2-22",1250.00,500.00,30),(7566,"JONESM","ANAGER",7839,"1981-4-2",2975.00,0.00,20),(7654,"MARTIN","SALESMAN",7698,"1981-9-28",1250.00,1400.00,30),(7698,"BLAKEM","ANAGER",7839,"1981-5-1",2850.00,0.00,30),(7782,"CLARKM","ANAGER",7839,"1981-6-9",2450.00,0.00,10),(7788,"SCOTTA","NALYST",7566,"1987-4-19",3000.00,0.00,20),(7839,"KINGPR","ESIDENT",7533,"1981-11-17",5000.00,0.00,10),(7844,"TURNER","SALESMAN",7698,"1981-9-8",1500.00,0.00,30),(7876,"ADAMSC","LERK",7788,"1987-5-23",1100.00,0.00,20),(7900,"JAMESC","LERK",7698,"1981-12-3",950.00,0.00,30),(7902,"FORDAN","ALYST",7566,"1981-12-3",3000.00,0.00,20),(7934,"MILLER","CLERK",7782,"1982-1-23",1300.00,0.00,10) --查看数据 SELECT * FROM kylin_hive.emp
虽然 Kylin 使用 SQL 做为查询接口并利用 Hive 元数据,Kylin 不会让用户查询全部的 hive 表,由于到目前为止它是一个预构建 OLAP(MOLAP) 系统。为了使表在 Kylin 中可用,使用 “Sync” 方法可以方便地从 Hive 中同步表。
Kylin 的 OLAP Cube 是从星型模式的 Hive 表中获取的预计算数据集,这是供用户探索、管理全部 cube 的网页管理页面。由菜单栏进入Model 页面,系统中全部可用的 cube 将被列出。
若是是分区统计,须要关于历史cube的合并,
这里是全量统计,不涉及多个分区cube进行合并,因此不用设置历史多个cube进行合并
Auto Merge Thresholds:
- 自动合并小的 segments 到中等甚至更大的 segment。若是不想自动合并,删除默认2个选项
Volatile Range:
- 默认为0,会自动合并全部可能的cube segments,或者用 ‘Auto Merge’ 将不会合并最新的 [Volatile Range] 天的 cube segments
Retention Threshold:
- 默认为0,只会保存 cube 过去几天的 segment,旧的 segment 将会自动从头部删除
Partition Start Date:
- cube 的开始日期
暂时也不作任何设
置高级设定关系到立方体是否足够优化,可根据实际状况将维度列定义为强制维度、层级维度、联合维度
- Mandatory维度指的是总会存在于group by或where中的维度
- Hierarchy是一组有层级关系的维度,如国家、省份、城市
- Joint是将多个维度组合成一个维度
这里也暂时不作配置
Kylin 容许在 Cube 级别覆盖部分 kylin.properties 中的配置
经过Planner计划者,能够看到4个维度,获得Cuboid Conut=15,为2的4次方-1,由于所有没有的指标不会使用,因此结果等于15。
SELECT DEPT.DNAME,SUM(EMP.SAL) FROM EMP LEFT JOIN DEPT ON DEPT.DEPTNO = EMP.DEPTNO GROUP BY DEPT.DNAME
就是对数据模型作 Cube 预计算,并利用计算的结果加速查询,具体工做过程以下:
指定数据模型,定义维度和度量。
预计算 Cube,计算全部 Cuboid 并保存为物化视图。
执行查询时,读取 Cuboid,运算,产生查询结果。
因为 Kylin 的查询过程不会扫描原始记录,而是经过预计算预先完成表的关联、聚合等复杂运算,并利用预计算的结果来执行查询,所以相比非预计算的查询技术,其速度通常要快一到两个数量级,而且这点在超大的数据集上优点更明显。当数据集达到千亿乃至万亿级别时,Kylin 的速度甚至能够超越其余非预计算技术 1000 倍以上。
Cube(或 Data Cube),即数据立方体,是一种经常使用于数据分析与索引的技术;它能够对原始数据创建多维度索引。经过 Cube 对数据进行分析,能够大大加快数据的查询效率。
Cuboid 特指在某一种维度组合下所计算的数据。 给定一个数据模型,咱们能够对其上的全部维度进行组合。对于 N 个维度来讲,组合的全部可能性共有 2 的 N 次方种。对于每一种维度的组合,将度量作 聚合运算,而后将运算的结果保存为一个物化视图,称为 Cuboid。
全部维度组合的 Cuboid 做为一个总体,被称为 Cube。因此简单来讲,一个 Cube 就是许多按维度聚合的物化视图的集合。
下面来列举一个具体的例子:
假定有一个电商的销售数据集,其中维度包括 时间(Time)、商品(Item)、地点(Location)和供应商(Supplier),度量为销售额(GMV)。
- 那么全部维度的组合就有 2 的 4 次方 =16 种
- 一维度(1D) 的组合有[Time]、[Item]、[Location]、[Supplier]4 种
- 二维度(2D)的组合 有[Time,Item]、[Time,Location]、[Time、Supplier]、[Item,Location]、 [Item,Supplier]、[Location,Supplier]6 种
- 三维度(3D)的组合也有 4 种
- 零维度(0D)的组合有 1 种
- 四维度(4D)的组合有 1 种
咱们知道,一个N维的Cube,是由1个N维子立方体、N个(N-1)维子立方体、N*(N-1)/2个(N-2)维子立方体、......、N个1维子立方体和1个0维子立方体构成,总共有2^N个子立方体组成。
在逐层算法中,按维度数逐层减小来计算,每一个层级的计算(除了第一层,它是从原始数据聚合而来),是基于它上一层级的结果来计算的。好比,[Group by A, B]的结果,能够基于[Group by A, B, C]的结果,经过去掉C后聚合得来的;这样能够减小重复计算;当 0维度Cuboid计算出来的时候,整个Cube的计算也就完成了。
每一轮的计算都是一个MapReduce任务,且串行执行;一个N维的Cube,至少须要N次MapReduce Job。
算法优势:
此算法充分利用了MapReduce的优势,处理了中间复杂的排序和shuffle工做,故而算法代码清晰简单,易于维护;
受益于Hadoop的日趋成熟,此算法很是稳定,即使是集群资源紧张时,也能保证最终可以完成。
算法缺点:
当Cube有比较多维度的时候,所须要的MapReduce任务也相应增长;因为Hadoop的任务调度须要耗费额外资源,特别是集群较庞大的时候,反复递交任务形成的额外开销会至关可观;
因为Mapper逻辑中并未进行聚合操做,因此每轮MR的shuffle工做量都很大,致使效率低下。
对HDFS的读写操做较多:因为每一层计算的输出会用作下一层计算的输入,这些Key-Value须要写到HDFS上;当全部计算都完成后,Kylin还须要额外的一轮任务将这些文件转成HBase的HFile格式,以导入到HBase中去;
整体而言,该算法的效率较低,尤为是当Cube维度数较大的时候。
也被称做“逐段”(By Segment) 或“逐块”(By Split) 算法,从1.5.x开始引入该算法,该算法的主要思想是,每一个Mapper将其所分配到的数据块,计算成一个完整的小Cube 段(包含全部Cuboid)。每一个Mapper将计算完的Cube段输出给Reducer作合并,生成大Cube,也就是最终结果。如图所示解释了此流程。
与旧的逐层构建算法相比,快速算法主要有两点不一样:
Mapper会利用内存作预聚合,算出全部组合;Mapper输出的每一个Key都是不一样的,这样会减小输出到Hadoop MapReduce的数据量,Combiner也再也不须要;
一轮MapReduce便会完成全部层次的计算,减小Hadoop任务的调配。
Kylin将它所有的元数据(包括cube描述和实例、项目、倒排索引描述和实例、任务、表和字典)组织成层级文件系统的形式。然而,Kylin使用hbase来存储元数据,而不是一个普通的文件系统。若是你查看过Kylin的配置文件(kylin.properties),你会发现这样一行:
## The metadata store in hbase kylin.metadata.url=kylin_metadata@hbase
这代表元数据会被保存在一个叫做“kylin_metadata”的htable里。你能够在hbase shell里scan该htbale来获取它。
有时你须要将Kylin的Metadata Store从hbase备份到磁盘文件系统。在这种状况下,假设你在部署Kylin的hadoop命令行(或沙盒)里,你能够到KYLIN_HOME并运行:
./bin/metastore.sh backup
来将你的元数据导出到本地目录,这个目录在KYLIN_HOME/metadata_backps下,它的命名规则使用了当前时间做为参数:KYLIN_HOME/meta_backups/meta_year_month_day_hour_minute_second,如:meta_backups/meta_2020_06_18_19_37_49/
万一你发现你的元数据被搞得一团糟,想要恢复先前的备份:
./bin/metastore.sh reset
./bin/metastore.sh restore $KYLIN_HOME/meta_backups/meta_xxxx_xx_xx_xx_xx_xx
作完备份,删除一些文件,而后进行恢复测试,完美恢复,叮叮叮!
Kylin在构建cube期间会在HDFS上生成中间文件;除此以外,当清理/删除/合并cube时,一些HBase表可能被遗留在HBase却之后不再会被查询;虽然Kylin已经开始作自动化的垃圾回收,但不必定能覆盖到全部的状况;你能够按期作离线的存储清理:
${KYLIN_HOME}/bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete false
${KYLIN_HOME}/bin/kylin.sh org.apache.kylin.tool.StorageCleanupJob --delete true
完成后,中间HDFS上的中间文件和HTable会被移除。
若是不进行任何维度优化,直接将全部的维度放在一个汇集组里,Kylin就会计算全部的维度组合(cuboid)。
好比,有12个维度,Kylin就会计算2的12次方即4096个cuboid,实际上查询可能用到的cuboid不到1000个,甚至更少。 若是对维度不进行优化,会形成集群计算和存储资源的浪费,也会影响cube的build时间和查询性能,因此咱们须要进行cube的维度优化。
当你在保存cube时遇到下面的异常信息时,意味1个汇集组的维度组合数已经大于 4096 ,你就必须进行维度优化了。
或者发现cube的膨胀率过大。
但在现实状况中,用户的维度数量通常远远大于4个。假设用户有10 个维度,那么没有通过任何优化的Cube就会存在 2的10次方 = 1024个Cuboid;虽然每一个Cuboid的大小存在很大的差别,可是单单想到Cuboid的数量就足以让人想象到这样的Cube对构建引擎、存储引擎来讲压力有多么巨大。所以,在构建维度数量较多的Cube时,尤为要注意Cube的剪枝优化(即减小Cuboid的生成)。
衍生维度:维表中能够由主键推导出值的列能够做为衍⽣维度。
使用场景:以星型模型接入时。例如用户维表能够从userid推导出用户的姓名,年龄,性别。
优化效果:维度表的N个维度组合成的cuboid个数会从2的N次方降为2。
衍生维度用于在有效维度内将维度表上的非主键维度排除掉,并使用维度表的主键(实际上是事实表上相应的外键)来替代它们。Kylin会在底层记录维度表主键与维度表其余维度之间的映射关系,以便在查询时可以动态地将维度表的主键“翻译”成这些非主键维度,并进行实时聚合。
虽然衍生维度具备很是大的吸引力,但这也并非说全部维度表上的维度都得变成衍生维度,若是从维度表主键到某个维度表维度所须要的聚合工做量很是大,则不建议使用衍生维度。
聚合组(Aggregation Group)是一种强大的剪枝工具。聚合组假设一个Cube的全部维度都可以根据业务需求划分红若干组(固然也能够是一个组),因为同一个组内的维度更可能同时被同一个查询用到,所以会表现出更加紧密的内在关联。每一个分组的维度集合均是Cube全部维度的一个子集,不一样的分组各自拥有一套维度集合,它们可能与其余分组有相同的维度,也可能没有相同的维度。每一个分组各自独立地根据自身的规则贡献出一批须要被物化的Cuboid,全部分组贡献的Cuboid的并集就成为了当前Cube中全部须要物化的Cuboid的集合。不一样的分组有可能会贡献出相同的Cuboid,构建引擎会察觉到这点,而且保证每个Cuboid不管在多少个分组中出现,它都只会被物化一次。
对于每一个分组内部的维度,用户可使用以下三种可选的方式定义,它们之间的关系,具体以下。
强制维度(Mandatory)
强制维度:全部cuboid必须包含的维度,不会计算不包含强制维度的cuboid。
适用场景:能够将肯定在查询时必定会使用的维度设为强制维度。例如,时间维度。
优化效果:将一个维度设为强制维度,则cuboid个数直接减半。
若是一个维度被定义为强制维度,那么这个分组产生的全部Cuboid中每个Cuboid都会包含该维度。每一个分组中均可以有0个、1个或多个强制维度。若是根据这个分组的业务逻辑,则相关的查询必定会在过滤条件或分组条件中,所以能够在该分组中把该维度设置为强制维度。
层级维度(Hierarchy),
层级维度:具备必定层次关系的维度。
使用场景:像年,月,日;国家,省份,城市这类具备层次关系的维度。
优化效果:将N个维度设置为层次维度,则这N个维度组合成的cuboid个数会从2的N次方减小到N+1。
每一个层级包含两个或更多个维度。假设一个层级中包含D1,D2…Dn这n个维度,那么在该分组产生的任何Cuboid中, 这n个维度只会以(),(D1),(D1,D2)…(D1,D2…Dn)这n+1种形式中的一种出现。每一个分组中能够有0个、1个或多个层级,不一样的层级之间不该当有共享的维度。若是根据这个分组的业务逻辑,则多个维度直接存在层级关系,所以能够在该分组中把这些维度设置为层级维度。
联合维度(Joint),
联合维度:将几个维度视为一个维度。
适用场景:
优化效果:将N个维度设置为联合维度,则这N个维度组合成的cuboid个数会从2的N次方减小到1。
每一个联合中包含两个或更多个维度,若是某些列造成一个联合,那么在该分组产生的任何Cuboid中,这些联合维度要么一块儿出现,要么都不出现。每一个分组中能够有0个或多个联合,可是不一样的联合之间不该当有共享的维度(不然它们能够合并成一个联合)。若是根据这个分组的业务逻辑,多个维度在查询中老是同时出现,则能够在该分组中把这些维度设置为联合维度。
这些操做能够在Cube Designer的Advanced Setting中的Aggregation Groups区域完成,以下图所示。
聚合组的设计很是灵活,甚至能够用来描述一些极端的设计。假设咱们的业务需求很是单一,只须要某些特定的Cuboid,那么能够建立多个聚合组,每一个聚合组表明一个Cuboid。具体的方法是在聚合组中先包含某个Cuboid所需的全部维度,而后把这些维度都设置为强制维度。这样当前的聚合组就只能产生咱们想要的那一个Cuboid了。
再好比,有的时候咱们的Cube中有一些基数很是大的维度,若是不作特殊处理,它就会和其余的维度进行各类组合,从而产生一大堆包含它的Cuboid。包含高基数维度的Cuboid在行数和体积上每每很是庞大,这会致使整个Cube的膨胀率变大。若是根据业务需求知道这个高基数的维度只会与若干个维度(而不是全部维度)同时被查询到,那么就能够经过聚合组对这个高基数维度作必定的“隔离”。咱们把这个高基数的维度放入一个单独的聚合组,再把全部可能会与这个高基数维度一块儿被查询到的其余维度也放进来。这样,这个高基数的维度就被“隔离”在一个聚合组中了,全部不会与它一块儿被查询到的维度都没有和它一块儿出如今任何一个分组中,所以也就不会有多余的Cuboid产生。这点也大大减小了包含该高基数维度的Cuboid的数量,能够有效地控制Cube的膨胀率。
当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最少或最多被划分红多少个分区。
因为每一个Cube的并发粒度控制不尽相同,所以建议在Cube Designer 的Configuration Overwrites(上图所示)中为每一个Cube量身定制控制并发粒度的参数。假设将把当前Cube的kylin.hbase.region.count.min设置为2,kylin.hbase.region.count.max设置为100。这样不管Segment的大小如何变化,它的分区数量最小都不会低于2,最大都不会超过100。相应地,这个Segment背后的存储引擎(HBase)为了存储这个Segment,也不会使用小于两个或超过100个的分区。咱们还调整了默认的kylin.hbase.region.cut,这样50GB的Segment基本上会被分配到50个分区,相比默认设置,咱们的Cuboid可能最多会得到5倍的并发量。
Kylin会把全部的维度按照顺序组合成一个完整的Rowkey,而且按照这个Rowkey升序排列Cuboid中全部的行。
设计良好的Rowkey将更有效地完成数据的查询过滤和定位,减小IO次数,提升查询速度,维度在rowkey中的次序,对查询性能有显著的影响。
Row key的设计原则以下:
构建全量cube,也能够实现增量cube的构建,就是经过分区表的分区时间字段来进行增量构建
Kylin v1.6 发布了可扩展的 streaming cubing 功能,它利用 Hadoop 消费 Kafka 数据的方式构建 cube。
参考:http://kylin.apache.org/blog/2016/10/18/new-nrt-streaming/
前期准备:kylin v1.6.0 或以上版本 和 可运行的 Kafka(v0.10.0 或以上版本)的 Hadoop 环境
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic kylin_streaming_topic
cd $KYLIN_HOME ./bin/kylin.sh org.apache.kylin.source.kafka.util.KafkaSampleProducer --topic kylin_streaming_topic --broker cdh01.cm:9092,cdh02.cm:9092,cdh03.cm:9092
工具每一秒会向 Kafka 发送 100 条记录。直至本案例结束请让其一直运行。
登录 Kylin Web GUI,选择一个已存在的 project 或建立一个新的 project;点击 “Model” -> “Data Source”,点击 “Add Streaming Table” 图标
{"country":"CHINA","amount":41.53789973661185,"qty":6,"currency":"USD","order_time":1592485535129,"category":"TOY","device":"iOS","user":{"gender":"Male","id":"12d127ab-707e-592f-2e4c-69ad654afa48","first_name":"unknown","age":25}}
您须要为这个 streaming 数据源起一个逻辑表名;该名字会在后续用于 SQL 查询;这里是在 “Table Name” 字段输入 “STREAMING_SALES_TABLE” 做为样例。
您须要选择一个时间戳字段用来标识消息的时间;Kylin 能够从这列值中得到其余时间值,如 “year_start”,”quarter_start”,这为您构建和查询 cube 提供了更高的灵活性。这里能够查看 “order_time”。您能够取消选择那些 cube 不须要的属性。这里咱们保留了全部字段。
注意 Kylin 从 1.6 版本开始支持结构化 (或称为 “嵌入”) 消息,会将其转换成一个 flat table structure。默认使用 “_” 做为结构化属性的分隔符。
在 “Advanced setting” 部分,”timeout” 和 “buffer size” 是和 Kafka 进行链接的配置,保留它们。
在 “Parser Setting”,Kylin 默认您的消息为 JSON 格式,每个记录的时间戳列 (由 “tsColName” 指定) 是 bigint (新纪元时间) 类型值;在这个例子中,您只需设置 “tsColumn” 为 “order_time”;
有了上一步建立的表,如今咱们能够建立数据模型了。步骤和您建立普通数据模型是同样的,但有两个要求:
这里咱们选择 13 个 dimension 和 2 个 measure 列:
保存数据模型。
Streaming Cube 和普通的 cube 大体上同样. 有如下几点须要您注意:
保存 cube。
能够在 web GUI 触发 build,经过点击 “Actions” -> “Build”,或用 ‘curl’ 命令发送一个请求到 Kylin RESTful API:
curl -X PUT --user ADMIN:KYLIN -H "Content-Type: application/json;charset=utf-8" -d '{ "sourceOffsetStart": 0, "sourceOffsetEnd": 9223372036854775807, "buildType": "BUILD"}' http://localhost:7070/kylin/api/cubes/{your_cube_name}/build2
请注意 API 终端和普通 cube 不同 (这个 URL 以 “build2” 结尾)。
这里的 0 表示从最后一个位置开始,9223372036854775807 (Long 类型的最大值) 表示到 Kafka topic 的结束位置。若是这是第一次 build (没有之前的 segment),Kylin 将会寻找 topics 的开头做为开始位置。
在 “Monitor” 页面,一个新的 job 生成了;等待其直到 100% 完成。
点击 “Insight” 标签,编写 SQL 运行,例如:
select minute_start, count(*), sum(amount), sum(qty) from streaming_sales_table group by minute_start order by minute_start
一旦第一个 build 和查询成功了,您能够按照必定的频率调度增量 build。Kylin 将会记录每个 build 的 offsets;当收到一个 build 请求,它将会从上一个结束的位置开始,而后从 Kafka 获取最新的 offsets。有了 REST API 您可使用任何像 Linux cron 调度工具触发它:
crontab -e */5 * * * * curl -X PUT --user ADMIN:KYLIN -H "Content-Type: application/json;charset=utf-8" -d '{ "sourceOffsetStart": 0, "sourceOffsetEnd": 9223372036854775807, "buildType": "BUILD"}' http://localhost:7070/kylin/api/cubes/{your_cube_name}/build2
如今您能够观看 cube 从 streaming 中自动 built。当 cube segments 累积到更大的时间范围,Kylin 将会自动的将其合并到一个更大的 segment 中。
<dependencies> <dependency> <groupId>org.apache.kylin</groupId> <artifactId>kylin-jdbc</artifactId> <version>3.0.1</version> </dependency> </dependencies> <build> <plugins> <!-- 限制jdk版本插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class KylinJdbc { public static void main(String[] args) throws Exception { //Kylin_JDBC 驱动 String KYLIN_DRIVER = "org.apache.kylin.jdbc.Driver"; //Kylin_URL String KYLIN_URL = "jdbc:kylin://localhost:9090/kylin_hive"; //Kylin的用户名 String KYLIN_USER = "ADMIN"; //Kylin的密码 String KYLIN_PASSWD = "KYLIN"; //添加驱动信息 Class.forName(KYLIN_DRIVER); //获取链接 Connection connection = DriverManager.getConnection(KYLIN_URL, KYLIN_USER, KYLIN_PASSWD); //预编译SQL PreparedStatement ps = connection.prepareStatement("SELECT sum(sal) FROM emp group by deptno"); //执行查询 ResultSet resultSet = ps.executeQuery(); //遍历打印 while (resultSet.next()) { System.out.println(resultSet.getInt(1)); } } }