Kylin构建及调优基础知识

1. Kylin设计核心思想

在这里插入图片描述
业务的发展伴随着事实表的数据体量的增大,查询时间也越来越长,而另一方面,结果集的数据量却没有显著增长,指标的变化也并不频繁。我们希望所有的查询都能在秒级返回查询结果,于是,我们有了一个思路:为什么不能把所有的结果先算好,查询时直接从结果集中取出来呢?这也就是 kylin 设计的初衷。
kylin的核心思想是预计算。
好,现在这个组件已经有了一个准确的定位,那么接下来要解决的问题就是如何实现预计算,这套架子里究竟需要什么组件呢?

2. Kylin基本架构

以下即为 kylin 的插件式架构。
在这里插入图片描述
上图中,蓝色的框框是 kylin 系统的边界,里面是 kylin 的核心功能,蓝色框框外面的部分是 Kylin 的外围插件和适配器。

从模块上来看,大致分为以下几部分:

  1. Data Source Abstraction:数据源抽象层,目前离线的主流实现是 hive,实时的主流实现是 kafka。
  2. Cube Builder:也就是构建引擎,目前支持 MapReduce 和 Spark。
  3. Storage Abstraction:结果集存储抽象层,目前主流实现是 hbase,也可以以数据流的方式输出到其他大数据生态工具。
  4. Metadata:元数据管理,包括 model,cube,job 等元数据的信息,由于 Kylin 的结果表名和 rowkey 都是经过编码的,必须要通过元数据来映射,所以元数据非常关键,若元数据损坏,相对应的结果集也会不可用,表现为表损坏或查询时报错。
  5. Rest Server:通过 Restful API,JDBC/ODBC 的方式向外界提供接口。
  6. Query Engine:查询引擎,内置 Apache 开源 SQL 解析工具 Calcite,生成执行计划并执行物理查询计划。
  7. Routing:路由转换,实时查询情景下,路由指向数据存储层 Hbase,准实时查询情景下,路由指向数据源层 Hive,准实时情景一般是在结果集的数据满足不了查询需求时,Kylin会转而向数据源做查询,也就是所谓的“查询下压”。

从数据流上来看,大致分为以下几部分:

  1. 红线:离线任务数据流,从数据源 Hive 读取数据,经计算引擎 MapReduce 或 Spark 计算,生成结果集并存储到 Hbase,离线构建任务可以定时,构建任务可通过 Rest API 定时调度。
  2. 绿色实线:实时查询数据流,从客户端通过 Rest API 或 JDBC/ODBC,经 Rest Server 和 Query Engine 处理,由路由转发至 Hbase,秒级返回查询结果。
  3. 绿色虚线:准实时查询数据流,查询下压时,通过数据源直接汇总出查询结果,性能视计算复杂程度而定。

接下来,我们就要涉及到 Cube 构建的一些概念啦~~

3. 基本概念

在这里插入图片描述

  1. Cube / Segment / Cuboid :一个查询结果集为一个 Cube; 对于分区表来说,一个日期区间为一个 Segment,一个 Cube 可分为多个 Segment ;每个 Segment 中,有不同维度组合的小结果集,每个小结果集称为一个 Cuboid ,如A维度,B维度,A+B维度,就是3个不同的 Cuboid,同一个Cube 中,不同 Segment 中的 Cuboid 组合和个数都相同。
  2. 字典:可以把字典理解为维度值向整型数值的映射表,若一个维度值用了字典编码,Hbase 的 rowkey 中就会存储映射后的整数值以提高检索速度,字典内部数据是有序的,方便查找和筛选。字典分为两种:Global Dictionary 和 Segment Dictionary,区别是作用域不同,分别为整个 Cube 或一个 Segment。字典在运算时会加载到内存中,所以,对于一些基数比较高的维度,要慎用字典,防止查询时内存溢出。

那么,万事俱备,我们开始构建 Cube 吧~

4. Cube构建及优化

4.1 Cube构建及优化总览

构建Cube的过程设计可以说是 kylin 系统设计的精华,这7个步骤封装了 kylin 绝大多数的实现细节,呈现出来的是简洁精炼的构建步骤。
在这里插入图片描述
上图中,有7个步骤,可以分为三个阶段:前四步为构建阶段,5、6步为优化阶段,最后一步为总览。下面我们一个一个详细说一下。

4.2 Cube构建分步骤说明

4.2.1 Cube Info

在这里插入图片描述
在这一步中,我们需要设置的是 Cube 的基本信息,其中包括:

  1. Model Name:model 名。
  2. Cube Name: Cube 名,全局唯一,否则会创建失败。
  3. Notification Email List:发生了 Notification Events 时要通知的邮件列表,逗号分隔。
  4. Notification Events:发生什么事件时要邮件通知列表中的用户,分为 Success(构建成功)、Error(构建失败)、Discard(构建中止)。
  5. Description:描述。

4.2.2 Dimensions

在这里插入图片描述
设置 Cube 所需的维度,查找表中的维度可以设置为 normal 或 derived,设置为 derived 的维度不会在 rowkey 中出现,而是用其他 normal 维度通过一层映射得到。

4.2.3 Measures

在这里插入图片描述
这一步骤主要选择 Cube 中要构建的指标。
所有 Cube 都会计算一个默认的指标 COUNT,即数行数,除此之外,我们还可以定义其他指标:

  1. SUM:求和。
  2. MIN:最小值。
  3. MAX:最大值。
  4. COUNT:计数。
  5. COUNT_DISTINCT:去重计数,有精确计算和模糊计算两种。一般来说,计算越精确,构建时资源消耗越多,查询时响应速度越慢;计算越模糊,构建时资源消耗越少,查询时响应速度越快。精确计算的 COUNT_DISTINCT 会存储为 bitmap,模糊计算的 COUNT_DISTINCT 会存储为其他的数据结构(如HyperLogLog),无论是哪种数据结构,都会占用一定的存储空间,若数据量大,占用的空间可能会在M级别,所以,若有多个去重指标,最好把它们存储在不同的列簇中,防止 Hbase 检索速度过慢。
  6. TOP_N:前 N 位。适用于以下场景:
select dimA, measure 
from table_name 
where dimB = 'b' and dimC = 'c'
order by measure 
limit N;

在不用 TOP_N 的情况下,查询引擎会从 Hbase 中查出所有符合条件的行,并依据其中的某个指标对所有列做排序。例如下面的场景,经过 TOP_N 优化后,Hbase 中数据存储的形式会从这样:

Base Cuboid 的 RowKeySUM(PRICE)
20120218_00_seller0000001291.58
20120218_00_seller0000002365.18
20120218_00_seller0000003135.29
20120218_00_seller1000000272.31
20120218_01_seller0000001172.52

变成这样:

base cuboid 的 RowKeyTop_N Measure
20120218_00sellerOO 10091:1092.21, seller0005002:1090.35,…sellerOOO 1789:891.37
20120218_01seller0003012:xx.xx
20120218 02seller0004001:xx.xx
20120218 50seIler000699: xx.xx

经 TOP_N 优化后存储结构节省了检索的计算成本,免去了排序的计算成本,可提高查询性能,但带来的问题是列簇的空间占用增加,Cube 的体积会变大。且子 Cuboid 的 TOP_N 指标是从父 TOP_N 的指标聚合出来的,会有一定程度的误差。
7) EXTENDED_COLUMN:引申列。适用于筛选时指定某些 id,但显示时却要显示成 name 时的场景,即把一个维度作为另一个维度的引申列。(后续补充引申列的查询方法和存储结构
8) PERCENTILE:分位数。查询时该函数的语法与 hive 类似,例如 percentile(measure_a, 0.5),即计算 measure_a 的二分位数,即中位数。

4.2.4 Refresh Setting

在这里插入图片描述
这一步骤主要是表的刷新机制和生命周期设置,分为以下几项:

  1. Auto Merge Thresholds:自动合并 Segments,可以设多级。若不合并,查询引擎需要在对各 Segments 查询后,对结果做一个合并。所以合并 Segment 在一定程度上可以提高查询效率。但是 Segment 是 Cube 构建和刷新的最小单位,合并后就无法对原有的某一个 Segment 单独做刷新操作。
  2. Volatile Range:最近 N 天的 Segments 不作合并,适用于因数据延迟导致最近 N 天数据会有波动,需要刷新 Segments 的情况。
  3. Retention Threshold:生命周期,自动删除 N 天以前的 Segment。
  4. Partition Start Date:起始日期,默认 1970-01-01。

4.3 Cube 构建前优化策略

前四步走完,相当于 Cube 的构建步骤基本完成了,以下的步骤,更确切地说是对 Cube 的优化,以提升构建速度或查询性能。

4.3.1 Advanced Settings

4.3.1.1 Aggregation Groups

在这里插入图片描述
Aggregation Groups 直译过来是聚合组。就是指定 Cube 中哪些维度会同时出现,若 Cube 中有两个维度没有同时出现在任何一个聚合组中,Cube 构建时就不会生成同时包含这两个维度的 Cuboid,聚合组是一个强大的剪枝工具。主要包含以下几项:

  1. Max Dimension Combination:查询时会涉及到的最大维度个数。设置后,多于该维度个数的 Cuboid 将不会被构建。
  2. Includes:聚合组里包含哪些维度。
  3. Mandatory Dimensions:在该聚合组中,有哪些维度是查询时必选的。
  4. Hierarchy Dimensions:哪些维度之间有层级关系,如 国家 -> 省 -> 市。
  5. Joint Dimensions:哪些维度之间几乎是一对一的。
    注意:若某维度被设置为 Mandatory Dimensions,该维度将不允许出现在 Hierarchy Dimensions 或 Joint Dimensions 中。
4.3.1.2 Rowkeys

在这里插入图片描述
rowkey 的优化分为以下几个方面:

  1. Hbase 中 rowkey 的维度顺序。《Apache Kylin 权威指南》中给出了一个维度评分的公式,维度评分越高,越应该放在前排:
维度打分 = 维度出现在过滤条件中的概率 * 用该维度过滤时可以过滤掉的记录数
  1. 维度编码。维度编码有以下几种:
    a) boolean:布尔型。
    b) dict:字典型,一般把字符串映射为整型,rowkey 中存储映射后的整型数值,字典在运算时会加载到内存中,若维度基数过高,可能会导致内存溢出。此时应考虑换成其他数据编码。
    c) fixed_length:定长,若维度值长度不等,编码时会对其进行截断或补位,适用于电话号码等定长维度。
    d) fixed_length_hex:16进制定长编码,用途尚不明确
    e) integer:整型编码。

  2. 是否按某维度分片。一般来说,数据分片策略可近似地认为是随机的,若设置时按某维度进行分片,可能会提高查询效率,但如果这个分片的维度基数过高,查询时可能会造成 Hbase 过大的压力,甚至会影响到 Kylin 的可用性。此优化项需谨慎使用。

  • 官方推荐单台 Hbase 机器的 region 数量在 100 个左右,若超过太多,可能会影响查询性能。
4.3.1.3 Mandatory Cuboids

在这里插入图片描述
必须出现的 Cuboid,支持文件导入。
还有一种方式可以指定要构建的 Cuboid,就是把这个 Cuboid 中出现的所有维度放到一个聚合组里,再把这些维度全部设置为 Mandatory Dimensions。

4.3.1.4 Cubing Engine

目前有两种 Cubing Engine 可供选择:MapReduce 和 Spark,前者速度慢,但稳定,后者速度快,但有内存占用过高,导致系统不稳定的风险。
一般来说,若有 COUNT_DISTINCT 指标,我们会优先考虑稳定性,选择 MapReduce,否则我们优先考虑速度,选择 Spark。

4.3.1.5 Column Family

一般来说,COUNT_DISTINCT 指标会单独放到一个列簇里面,其他指标会放到另一个列簇里面。若同时有多个 COUNT_DISTINCT 指标,需要根据每个指标列占用空间的大小,评估是否要把不同的 COUNT_DISTINCT 指标放到不同的列簇当中。

4.3.2 Overview Settings

其他自定义配置项,此处省略。

4.4 Cube 构建后优化策略

4.4.1 Cube 优化判断指标

一个足够优化的 Cube,需要包含常查询的 Cuboid,删除不常查询的 Cuboid,即在满足查询性能的前提下,占用的空间足够小,只物化高频查询的 Cuboid。基于这一点,我们有一个指标,称为膨胀率。

膨胀率 (Expansion Rate) = Cube数据大小 / 源数据大小

膨胀率一般在0 ~ 1000%,若超过这个阈值,这个 Cube 很可能需要优化。例如下面这个 Cube:
在这里插入图片描述
膨胀率已超过1000%,所以我们要对其进行优化。

4.4.2 Cube 构建后优化方法

在 Cube 已经构建好以后,又如何进行优化呢?
这时我们就要用到 Cube Planner 这个工具啦,Cube Planner 是内嵌在 Kylin 中的一个剪枝工具,可以统计出每个 Cuboid 的命中次数,进而把各个 Cuboid 做冷热分级,Cube Planner 的统计结果会可视化成下面这张旭日图:
在这里插入图片描述
上图中,左边是优化前的 Cube,我们会发现,这个 Cube 之所以膨胀率会超过1000%,是因为它物化了很多从来没被使用过的 Cuboid,右边是推荐的 Cuboid 组合,我们发现 Cube Planner 在优化后会把没被命中过的 Cuboid 删除,优化 Cube 在空间上的占用,还会新增一些 Cuboid,在时间上优化 Cube 的查询性能。
鼠标悬浮在每个 Cuboid 上时,Kylin 还会显示出该 Cuboid 的相关信息:

  1. Name:各维度是否出现,按 rowkey 排序。
  2. ID:cuboid ID。
  3. Query Count:命中数,也包括子 Cuboid 没被物化时,由此 Cuboid 计算得出的查询命中数。
  4. Exactly Match Count:精确命中数。
  5. Row Count:行数。
  6. Rollup Rate:子cuboid行数 / 父cuboid行数。

4.5 一个优化的案例分享

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值