“
作者:阿里云 EMR 开源大数据 OLAP 团队,
StarRocks 社区数据湖分析团队 ”
前言
随着 数字产业化和产业数字化成为经济驱动的重要动力,企业的数据分析场景越来越丰富,对数据分析架构的要求也越来越高。新的数据分析场景催生了新的需求,主要包括三个方面:
-
用户希望用更加低廉的成本,更加实时的方式导入并存储任何数量的关系数据(例如,来自业务线应用程序的运营数据库和数据)和非关系数据(例如,来自移动应用程序、IoT 设备和社交媒体的运营数据库和数据)
-
用户希望自己的数据资产受到严密的保护
-
用户希望数据分析的速度变得更快、更灵活、更实时
数据湖的出现很好的满足了用户的前两个需求,它允许用户导入任何数量的实时获得的数据。用户可以从多个来源收集数据,并以其原始形式存储到数据湖中。数据湖拥有极高的水平扩展能力,使得用户能够存储任何规模的数据。同时其底层通常使用廉价的存储方案,使得用户存储数据的成本大大降低。数据湖通过敏感数据识别、分级分类、隐私保护、资源权限控制、数据加密传输、加密存储、数据风险识别以及合规审计等措施,帮助用户建立安全预警机制,增强整体安全防护能力,让数据可用不可得和安全合规。
为了进一步满足用户对于数据湖分析的要求,我们需要一套适用于数据湖的分析引擎,能够在更短的时间内从更多来源利用更多数据,并使用户能够以不同方式协同处理和分析数据,从而做出更好、更快的决策。本篇文章将向读者详细揭秘这样一套数 据湖分析引擎的关键技术,并通过 StarRocks 来帮助用户进一步理解系统的架构。
之后我们会继续发表两篇文章,来更详细地介绍极速数据湖分析引擎的内核和使用案例:
-
代码走读篇 :通过走读 StarRocks 这个开源分析型数据库内核的关键数据结构和算法,帮助读者进一步理解极速数据湖分析引擎的原理和具体实现。
-
Case Study 篇 :介绍大型企业如何使用 StarRocks 在数据湖上实时且灵活的洞察数据的价值,从而帮助业务进行更好的决策,帮助读者进一步理解理论是如何在实际场景落地的。
什么是数据湖
什么是数据湖,根据 Wikipedia 的定义,“A data lake is a system or repository of data stored in its natural/raw format, usually object blobs or files”。通俗来说可以将数据湖理解为在廉价的对象存储或分布式文件系统之上包了一层,使这些存储系统中离散的 object 或者 file 结合在一起对外展现出一个统一的语义,例如关系型数据库常见的“表”语义等。
在数据湖这个概念出来之前,已经有很多企业或组织大量使用 HDFS 或者 S3 来存放业务日常运作中产生的各式各样的数据(例如一个制作 APP 的公司可能会希望将用户所产生的点击事件事无巨细的记录)。因为这些数据的价值不一定能够在短时间内被发现,所以找一个廉价的存储系统将它们暂存,期待在将来的一天这些数据能派上用场的时候再从中将有价值的信息提取出来。然而 HDFS 和 S3 对外提供的语义毕竟比较单一(HDFS 对外提供文件的语义,S3对外提供对象的语义),随着时间的推移工程师们可能都无法回答他们到底在这里面存储了些什么数据。为了防止后续使用数据的时候必须将数据一一解析才能理解数据的含义,聪明的工程师想到将定义一致的数据组织在一起,然后再用额外的数据来描述这些数据,这些额外的数据被称之为“元”数据,因为他们是描述数据的数据。这样后续通过解析元数据就能够回答这些数据的具体含义。这就是数据湖最原始的作用。
用一句不太准确的话描述数据湖,就是一个存储成本更廉价的“AP 数据库”。但是数据湖仅仅提供数据存储和组织的能力,一个完整的数据库不仅要有数据存储的能力,还需要有数据分析能力。因此怎么为数据湖打造一款高效的分析引擎,为用户提供洞察数据的能力,将是本文所要重点阐述的部分。下面通过如下几个章节一起逐步拆解一款现代的 OLAP 分析引擎的内部构造和实现:
-
怎么在数据湖上进行极速分析 -
现代数据湖分析引擎的架构
怎么在数据湖上进行极速分析
从这一节开始,让我们开始回到数据库课程,一个用于数据湖的分析引擎和一个用于数据库的分析引擎在架构上别无二致,通常我们认为都会分为下面几个部分:
-
Parser:将用户输入的查询语句解析成一棵抽象语法树
-
Analyzer:分析查询语句的语法和语义是否正确,符合定义
-
Optimizer:为查询生成性能更高、代价更低的物理查询计划
-
Execution Engine:执行物理查询计划,收集并返回查询结果
对于一个数据湖分析引擎而言,Optimizer 和 Execution Engine 是影响其性能两个核心模块,下面我们将从三个维度入手,逐一拆解这两个模块的核心技术原理,并通过不同技术方案的对比,帮助读者理解一个现代的数据湖分析引擎的始末。
RBO vs CBO
基本上来讲,优化器的工作就是对给定的一个查询,生成查询代价最低(或者相对较低)的执行计划。不同的执行计划性能会有成千上万倍的差距,查询越复杂,数据量越大,查询优化越重要。
(常见 CBO 实现架构)
Record Oriented vs Block Oriented
执行计划可以认为是一串 operator(关系代数的运算符)首尾相连串起来的执行流,前一个 operator 的 output 是下一个 operator 的 input。 传统的分析引擎是 Row Oriented 的,也就是说 operator 的 output 和 input 是一行一行的数据。
举一个简单的例子,假设我们有下面一个表和查询:
CREATE TABLE t (n int, m int, o int, p int);
SELECT o FROM t WHERE m < n + 1;
上述查询语句展开为执行计划的时候大致如下图所示:
通常情况下,在 Row Oriented 的模型中,执行计划的执行过程可以用如下伪码表示:
next: for: row = source.next() if filterExpr.Eval(row): // return a new row containing just column o returnedRow row for col in selectedCols: returnedRow.append(row[col]) return returnedRow
// first create an n + 1 result, for all values in the n column
projPlusIntIntConst.Next():
batch = source.Next()
for i < batch.n:
outCol[i] = intCol[i] + constArg
return batch
// then, compare the new column to the m column, putting the result into
// a selection vector: a list of the selected indexes in the column batch
selectLTIntInt.Next():
batch = source.Next()
for i < batch.n:
if int1Col < int2Col:
selectionVector.append(i)
return batch with selectionVector
// finally, we materialize the batch, returning actual rows to the user,
// containing just the columns requested:
materialize.Next():
batch = source.Next()
for s < batch.n:
i = selectionVector[i]
returnedRow row
for col in selectedCols:
returnedRow.append(cols[ col][i])
yield returnedRow
可以看到,Column Oriented 拥有更好的数据局部性和指令局部性,有利于提高 CPU Cache 的命中率,并且编译器更容易执行 SIMD 优化等。
Pull Based vs Push Based
-
基于数据驱动的 Push Based 模式,上游算子推送数据到下游算子 -
基于需求的 Pull Based 模式,下游算子主动从上游算子拉取数据。经典的火山模型就是 Pull Based 模式。
Push Based 的执行模式提高了缓存效率,能够更好地提升查询性能。
现代数据湖分析引擎的架构
通过上一节的介绍,相信读者已经对数据湖分析引擎的前沿理论有了相应了解。在本节中,我们以 StarRocks 为例,进一步介绍数据湖分析引擎是怎么有机的结合上述先进理论,并且通过优雅的系统架构将其呈现给用户。
Frontend
-
SQL Parse:将 SQL 文本转换成一个 AST(抽象语法树) -
Analyze:基于 AST 进行语法和语义分析 -
Logical Plan:将 AST 转换成逻辑计划 -
Optimize:基于关系代数,统计信息,Cost 模型对逻辑计划进行重写,转换,选择出 Cost “最低” 的物理执行计划 -
生成 Fragment:将 Optimizer 选择的物理执行计划转换为 BE 可以直接执行的 Fragment -
Coordinate:将 Fragment 调度到合适的 BE 上执行
Backend
BE 是 StarRocks 的后端节点,负责接收 FE 传下来的 Fragment 执行并返回结果给 FE。StarRocks 的 BE 节点都是完全对等的,FE 按照一定策略将数据分配到对应的 BE 节点。常见的 Fragment 工作流程是读取数据湖中的部分文件,并调用对应的 Reader (例如,适配 Parquet 文件的 Parquet Reader 和适配 ORC 文件的 ORC Reader等)解析这些文件中的数据,使用向量化执行引擎进一步过滤和聚合解析后的数据后,返回给其他 BE 或 FE。
总结
本篇文章主要介绍了极速数据湖分析引擎的核心技术原理,从多个维度对比了不同技术实现方案。为方便接下来的深入探讨,进一步介绍了开源数据湖分析引擎 StarRocks 的系统架构设计。希望和各位同仁共同探讨、交流。
附录
本次测试采用的 TPCH 100G 的标准测试集,分别对比测试了 StarRocks 本地表,StarRocks On Hive 和 Trino(PrestoSQL) On Hive 三者之间的性能差距。