优化 Cube 构建
本教程是关于如何一步步优化 cube build 的样例。
在这个场景中我们尝试优化一个简单的 Cube,用 1 张 fact 和 1 张 lookup 表 (日期 Dimension)。在真正的调整之前,请从 优化 Cube Build 中大体了解关于 Cube build 的过程
基准是:
- 一个 Measure:平衡,总是计算 Max,Min 和 Count
- 所有 Dim_date (10 项) 会被用作 dimensions
- 输入为 Hive CSV 外部表
- 输出为 HBase 中未压缩的 Cube
使用这些配置,结果为:13 分钟 build 一个 20 Mb 的 cube (Cube_01)
Cube_02:减少组合
第一次提升,在 Dimensions 上使用 Joint 和 Hierarchy 来减少组合 (cuboids 的数量)。
使用月,周,工作日和季度的 Joint Dimension 将所有的 ID 和 Text 组合在一起
定义 Id_date 和 Year 作为 Hierarchy Dimension
这将其大小减至 0.72 MB 而时间减至 5 分钟
Kylin 2149,理想情况下,这些 Hierarchies 也能够这样定义:
* Id_weekday > Id_date
* Id_Month > Id_date
* Id_Quarter > Id_date
* Id_week > Id_date
现在,还不能对同一 dimension 一起使用 Joint 和 Hierarchy。
Cube_03:输出压缩
下一次提升,使用 Snappy 压缩 HBase Cube:
另一个选项为 Gzip:
压缩输出的结果为:
Snappy 和 Ggzip 的区别在时间上少于 1% 但是在大小上有 18% 差别
Cube_04:压缩 Hive 表
时间分布如下:
按概念分组的详细信息 :
67 % 用来 build / process flat 表且遵守 30% 用来 build cube
大量时间用在了第一步。
这种时间分布在有很少的 measures 和很少的 dim (或者是非常优化的) 的 cube 中是很典型的
尝试在 Hive 输入表中使用 ORC 格式和压缩(Snappy):
前三步 (Flat Table) 的时间已经提升了一半。
其他列式格式可以被测试:
- ORC
- 使用 Snappy 的 ORC 压缩
但结果比使用 Sequence 文件的效果差。
请看:Shaofengshi in MailList 关于这个的评论
第二步是重新分配 Flat Hive 表:
是一个简单的 row count,可以做出两个近似值
* 如果其不需要精确,fact 表的 row 可以被统计→ 这可以与步骤 1 并行执行 (且 99% 的时间将是精确的)
- 将来的版本中 (KYLIN-2165 v2.0),这一步将使用 Hive 表数据实现。
Cube_05:Hive 表 (失败) 分区
Rows 的分布为:
Table | Rows |
---|---|
Fact Table | 3.900.00 |
Dim Date | 2.100 |
build flat 表的查询语句 (简单版本):
```sql
SELECT
,DIM_DATE.X
,DIM_DATE.y
,FACT_POSICIONES.BALANCE
FROM FACT_POSICIONES INNER JOIN DIM_DATE
ON ID_FECHA = .ID_FECHA
WHERE (ID_DATE >= '2016-12-08' AND ID_DATE < '2016-12-23')
```
这里存在的问题是,Hive 只使用 1 个 Map 创建 Flat 表。重要的是我们要改变这种行为。解决方案是在同一列将 DIM 和 FACT 分区
- 选项 1:在 Hive 表中使用 id_date 作为分区列。这有一个大问题:Hive metastore 意味着几百个分区而不是几千个 (在 Hive 9452 中有一个解决该问题的方法但现在还未完成)
- 选项 2:生成一个新列如 Monthslot。
为 dim 和 fact 表添加同一个列
现在,用这个新的条件 join 表来更新数据模型
生成 flat 表的新查询类似于:
```sql
SELECT *
FROM FACT_POSICIONES **INNER JOIN** DIM_DATE
ON ID_FECHA = .ID_FECHA AND MONTHSLOT=MONTHSLOT
```
用这个数据模型 rebuild 新 cube
结果,性能更糟了 :(。尝试了几种方法后,还是没找到解决方案
问题是分区没有被用来生成几个 Mappers
(我和 ShaoFeng Shi 检查了这个问题。他认为问题是这里只有很少的 rows 而且我们不是使用的真实的 Hadoop 集群。请看这个 tech note)。
结果摘要
调整进度如下:
* Hive 输入表压缩了
* HBase 输出压缩了
* 应用了 cardinality (Joint,Derived,Hierarchy 和 Mandatory) 减少的技术
* 为每一个 Dim 个性化 Dim 编码器并选择了 Dim 在 Row Key 中最好的顺序
现在,这里有三种类型的 cubes:
* 在 dimensions 中使用低 cardinality 的 Cubes(如 cube 4,大多数时间用在 flat 表这一步)
* 在 dimensions 中使用高 cardinality 的 Cubes(如 cube 6,大多数时间用于 Build cube,flat 表这一步少于 10%)
* 第三种类型,超高 cardinality (UHC) 其超出了本文的范围
Cube 6:用高 cardinality Dimensions 的 Cube
在这个用例中 72% 的时间用来 build Cube
这一步是 MapReduce 任务,您可以在 > 看 YARN 中关于这一步的日志
Map – Reduce 的性能怎样能提升呢? 简单的方式是增加 Mappers 和 Reduces (等于增加了并行数) 的数量。
注意: YARN / MapReduce 有很多参数配置和适应您的系统。这里的重点只在于小部分。
(在我的系统中我可以分配 12 – 14 GB 和 8 cores 给 YARN 资源):
- yarn.nodemanager.resource.memory-mb = 15 GB
- yarn.scheduler.maximum-allocation-mb = 8 GB
- yarn.nodemanager.resource.cpu-vcores = 8 cores
有了这些配置我们并行列表的最大理论级别为 8。然而这里有一个问题:“3600 秒后超时了”
参数 mapreduce.task.timeout (默认为 1 小时) 定义了 Application Master (AM) 在没有 ACK of Yarn Container 的情况下发生的最大时间。一旦这次通过了,AM 杀死 container 并重新尝试 4 次 (都是同一个结果)
问题在哪? 问题是 4 个 mappers 启动了,但每一个 mapper 需要超过 4 GB 完成
- 解决方案 1:增加 RAM 给 YARN
- 解决方案 2:增加在 Mapper 步骤中使用的 vCores 数量来减少 RAM 使用
- 解决方案 3:您可以通过 node 为 YARN 使用最大的 RAM(yarn.nodemanager.resource.memory-mb) 并为每一个 container 使用最小的 RAM 进行实验(yarn.scheduler.minimum-allocation-mb)。如果您为每一个 container 增加了最小的 RAM,YARN 将会减少 Mappers 的数量。
在最后两个用例中结果是相同的:减少并行化的级别 ==>
* 现在我们只启动 3 个 mappers 且同时启动,第四个必须等待空闲时间
* 3 个 mappers 将 ram 分散在它们之间,结果它们就会有足够的 ram 完成 task
一个正常的 “Build Cube” 步骤中您将会在 YARN 日志中看到相似的消息:
如果您没有周期性的看见这个,也许您在内存中遇到了瓶颈。
Cube 7:提升 cube 响应时间
我们尝试使用不同 aggregations groups 来提升一些非常重要 Dim 或有高 cardinality 的 Dim 的查询性能。
在我们的用例中定义 3 个 Aggregations Groups:
1. “Normal cube”
2. 使用日期 Dim 和 Currency 的 Cube(就像 mandatory)
3. 使用日期 Dim 和 Carteras_Desc 的 Cube(就像 mandatory)
比较未使用 / 使用 AGGs:
使用多于 3% 的时间 build cube 以及 0.6% 的 space,使用 currency 或 Carteras_Desc 的查询会快很多。