大数据 -164 Apache Kylin Cuboid 剪枝实战:Derived 维度与膨胀率控制

TL;DR
场景:维度多导致 Cuboid 爆炸、构建慢、存储膨胀率飙升。
结论:用 Cuboid 剪枝 + Derived 维度;用 CubeStatsReader/GUI 核查体积与命中,优先删“永不命中/近似冗余”的 Cuboid。
产出:可执行命令、判定阈值与优化思路、版本适配矩阵、常见错误速查卡。
版本矩阵
Cuboid 剪枝优化
Cuboid 特指 Kylin 中在某一种维度组合下所计算的所有数据,以减少 Cuboid 数量为目的的优化统称为 Cuboid 剪枝。在没有采取任何优化措施的情况下,Kylin 会对每一种维度的组合进行预计算。
如果有 4 个维度,可能最终会有 2^4 = 16 个 Cuboid 需要计算
如果有 10 个维度,那么没有经过任何优化的 Cube 就存在 2^10 = 1024 个 Cuboid
如果有 20 个维度,那么 Cube 中总共会存在 2^20 = 1048576 个 Cuboid 过多的 Cuboid 数量对构建引擎、存储引擎压力是非常巨大的,因此,在构建维度数量较多的 Cube 时候,尤其要注意 Cube 的剪枝优化。
Cube 的剪枝优化是一种试图减少额外空间占用的方法,这种方法的前提是不会明显影响查询时间,在做剪枝优化的时候:
需要选择跳过那些多余的 Cuboid
有的 Cuboid 因为查询样式的原因永远不会被查询到,因此显得多余
有的 Cuboid 的能力和其他 Cuboid 接近,因此显得多余
Kylin 提供了一系列简单的工具来帮助他们完成 Cube 的剪枝优化。
检查 Cuboid 数量
ApacheKylin 提供了一个简单的工具,检查 Cube 中哪些 Cuboid 最终被预计算了,称这些 Cuboid 被物化的 Cuboid,该工具还能给出每个 Cuboid 所占空间的估计值。由于该工具需要在对数据进行一定阶段的处理之后才能估算 Cuboid 的大小,一般来说在 Cube 构建完毕之后再使用该工具。
使用如下的命令行工具去检查这个 Cube 中的 Cuboid 状态:
执行之后的结果如下图所示:
对应的截图如下图:
估计 Cuboid 大小的精度(HII Precision)
总共的 Cuboid 数量
Segment 的总行数估计
Segment 的大小估计,Segment 的大小决定 Mapper、Reducer 的数量、数据分片数量等
所有的 Cuboid 及它的分析结果都以树状的形式打印了出来
在这颗树上,每个节点代表一个 Cuboid,每个 Cuboid 都由一连串 1 和 0 的数字组成
数字串的长度等于有效维护度的数量,从左到右每个数字依次代表 RowKeys 设置中的各个维度,如果数字为 0,则代表这个 Cuboid 中不存在相应的维度,如果数字为 1,则代表这个 Cuboid 中存在相应的维度
除了最顶端的 Cuboid 之外,每个 Cuboid 都有一个父亲 Cuboid,且都比父亲 Cuboid 少了一个“1”,其意义是这个 Cuboid 就是由它的父亲节点减少一个维度聚合而来的(上卷)
最顶端的 Cuboid 成为 Base Cuboid,它直接由源数据计算而来,Base Cuboid 的具体信息,包括该 Cuboid 的输出中除了 0 和 1 的数字串以外,后面还有每个 Cuboid 的具体信息,包括该 Cuboid 行数的估计值、该 Cuboid 大小的估计值,以及这个 Cuboid 的行数与父亲节点的对比(Shrink 值)
所有 Cuboid 行数的估计值之和应该等于 Segment 的行数估计值,所有 Cuboid 的大小估计值应该等于该 Segment 的大小估计值,每个 Cuboid 都是在它的父亲节点的基础上进一步聚合而成的
检查 Cube 大小
在 WebGUI 的 Model 页面选择一个 READ 状态为 Cube,光标移动到该 Cube 的 CubeSize 列时,WebGUI 会提示 Cube 的源数据大小,以及当前 Cube 的大小除以数据源大小的比例,称为膨胀率(Expansion Rate)。
我们可以在页面上看到 Cube 的大小信息,如下图所示:
一般来说,Cube 的膨胀率应该在 0%-1000%之间,如果一个 Cube 的膨胀率超过 1000%,那么应该查找当中的原因,膨胀率高可能有以下几个方面的原因:
Cube 中的维度数量较多,且没有进行很好的 Cuboid 剪枝优化,导致 Cuboid 数量极多
Cube 中存在较高基数的维度(基数的维度是指维度中有多少个不同的值),导致包含这类维度的每个 Cuboid 占用的空间都很大,这些 Cuboid 累积造成整体 Cube 体积变大。
存在占用空间大的度量,例如 Count Distinct,因此需要 Cuboid 的每一行中都为其保存了一个较大度量数据,最坏的情况会导致 Cuboid 中每一行都有数十 KB,从而造成整个 Cube 的体积变大
对于 Cube 的膨胀率居高不下的情况,需要结合实际数据进行分析,优化。
使用衍生维度
一个维度可以是普通维度或者衍生维度(Derived)将维度表的维度设置为衍生维度,这个维度不会参与计算,而是使用维度表的主键(或事实表的外键)来替代它。Kylin 会在底层记录维表主键与其他维度之间的映射关系,以便在查询时能够动态的将维度表的主键翻译成这些非主键维度,并进行实时聚合。创建 Cube 的时候,这些维度如果指定为衍生维度,Kylin 将会排除这些维度,而是使用维度表的主键来代替它们创建 Cuboid,后续查询的时候,再基于主键的聚合结果,在进行一次聚合。使用衍生角度会有效减少 Cube 中的 Cuboid 数量,但在查询的时候会增加聚合的时间。
不适合的场景:
如果从维度表主键到某个维度表所需要的聚合工作量非常大,此时作为一个普通的维度表聚合更合适,否则会影响 Kylin 的查询性能。
案例 1-定义衍生维度及对比
基本介绍
有以下时间日期维表:
编写 SQL
备注信息:日期维度代表 dim_date 中两个字段,dayofyear、dayofmonth、不能是 year、month。
测试数据
dim_date 里,少放几条数据(机器太弱了跑不动):
上传数据
写入如下的数据:
写入的数据如下图所示:
执行如下的脚本:
执行结果如下图所示:
Cube 设计
对应的 SQL:
基本的执行流程如:创建项目 - 指定数据源 - 定义 Model- 定义 Cube - 查询
加载数据源
之前已经操作过很多次了,这里就简单一些写了,添加日期维度表:
创建 Model,wzk_test_model_5,选择如下的连表关系:
维度按照按照如下图的配置进行:
度量还是按原来的:
剩下的部分默认即可。
构建 Cube
我们分别构建刚才创建的两个 Cube:
构建结果
构建的结果如下图所示:
wzk_test_kylin_cube_5
wzk_test_kylin_cube_5_2
检查 Cube 的 Cuboid 数量
我们刚才创建了两个 Cube 如下图所示:
wzk_test_kylin_cube_5
查看 wzk_test_kylin_cube_5:
对应的截图如下所示:
wzk_test_kylin_cube_5_2
查看 wzk_test_kylin_cube_5_2:
查询结果如下:
错误速查
其他系列
🚀 AI 篇持续更新中(长期更新)
AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI 研究-127 Qwen2.5-Omni 深解:Thinker-Talker 双核、TMRoPE 与流式语音🔗 AI模块直达链接
💻 Java 篇持续更新中(长期更新)
Java-174 FastFDS 从单机到分布式文件存储:实战与架构取舍 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务已完结,Dubbo 已完结,MySQL 已完结,MongoDB 已完结,Neo4j 已完结,FastDFS 正在更新,深入浅出助你打牢基础!🔗 Java模块直达链接
📊 大数据板块已完成多项干货更新(300 篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接
版权声明: 本文为 InfoQ 作者【武子康】的原创文章。
原文链接:【http://xie.infoq.cn/article/815dc17552ada2065286f6c86】。文章转载请联系作者。







评论