分享

flink实践:图解flink sql应用提交方式(一)

问题导读:
1、Flink Sql解析器是什么?
2、Flink Planner 和 Blink Planner如何理解?
3、Calcite的 parse 解析模块是基于什么实现?
4、SqlSelect和SqlDelete用途是什么?



前言

大家好,我是土哥。

这已经是我为读者写的第21篇 Flink系列文章了。

上周有粉丝在群里问,在流计算平台编写完Flink sql后,为什么通过一键提交按钮,就可以将sql提交到yarn集群上面了?

2021-10-13_191452.jpg

由于现在各大厂对业务分层特别清晰,平台方向和底层技术开发会被单独划分,所以好多大数据同学编写完 Flink Sql 后,只需通过提交按钮将其提交到集群上,对背后的提交原理也许不太清楚。

2021-10-13_191524.jpg

下面土哥将为大家揭开这层神秘的面纱,挖掘 Flink Sql 背后的提交原理和源码设计。(硬核文章,建议收藏!)
熟悉平台
故事

小笨猪阿土刚入职某大数据公司担任实习生,然后主管交给阿土一个任务,让其熟悉公司的 Flink 流计算平台。


阿土登录流计算平台后,看到平台上面可以编写 Sql 语法,于是就写了一个简单的 sql。
2021-10-13_191615.jpg

他发现旁边有个效验功能、于是就点击了一下,这时平台弹出 SQL 语法效验正确。阿土心中暗暗自喜,看来我的 sql 功底还是不错嘛。

SQL 语法效验完成后,阿土点击提交按钮,流计算平台提示,SQl 语法效验正确,已成功提交集群。

Flink sql 代码居然提交到yarn集群上了???

2021-10-13_191644.jpg
小笨猪阿土感到很惊讶,sql 就这样直接提交到集群了哇,这时候小笨猪的导师猴哥过来了,看到小笨猪的操作后,表扬了几句。

阿土,完成的不错啊,已经可以提交 sql 代码啦。但是你可别小看这简单的提交,这背后的门路可不浅呦。

这样吧,你好好探索一下这个sql提交的原理,然后写一篇分析报告,在咱们组分享一下。

啊......啊......

小笨猪阿土听到猴哥的要求后,一下就蔫了。从此之后,阿土就和 Flink sql走在了一起。

刚开始阿土很懵,于是就开始搜查 Flink sql 相关文章,过了几天,终于理清了一些思路。小笨猪将其流程总结为以下几个点:

  •     Flink Sql解析器
  •     Flink Planner 和 Blink Planner
  •     Blink Sql提交流程

1. Flink Sql解析器

1.1、了解Calcite

为方便用户使用 Flink 流计算组件,Flink 社区设计了四种抽象,在这些抽象中,Sql API 属于Flink的最上层抽象,是 Flink 的一等公民,这就方便用户或者开发者直接通过 Sql 编写来提交任务。

2021-10-13_191729.jpg
但经过阿土的调查后 发现,Flink sql 在提交任务时,并不是向 DataStream API 那样,直接被转为 StreamGraph,经过优化生成 JobGraph 提交到集群的,而是需要对编写的 Sql 进行解析、验证、优化等操作,在这中间,社区引入了一个强大的解析器,那就是Calcite。

阿土好好调研了一番Calcite

Calcite属于Apache旗下的一个动态数据管理框架,具备很多数据库管理系统的功能,它可以对SQL进行 SQL 解析,SQL 校验,SQL 查询优化,SQL 生成以及数据连接查询等操作,它不存储元数据和基本数据,不包含处理数据的算法。而是作为一个中介的角色,将上层SQL和底层处理引擎打通,将其SQL转为底层处理引擎需要的数据格式。

它不受上层编程语言的限制,前端可以使用 SQL、Pig、Cascading 等语言,只要通过 Calcite 提供的 SQL Api 将它们转化成关系代数的抽象语法树即可,并根据一定的规则和成本对抽象语法树进行优化,最后推给各个数据处理引擎来执行。

所以 Calcite 不涉及物理规划层,它通过扩展适配器来连接多种后端的数据源和数据处理引擎,如 Hive,Drill,Flink,Phoenix等。

1.2、Calcite执行步骤

小笨猪阿土简单画了一下Calcite的执行流程,主要涉及5个部分 SQL解析、SQL校验、SQL查询优化、SQL生成、执行等。
2021-10-13_191805.jpg
在这个流程中,Calcite各阶段扮演的角色如下:

  •     SQL解析。通过 JavaCC 实现,使用 JavaCC 编写 SQL 语法描述文件,将 SQL 解析成未经校验的 AST 语法树。
  •     SQL校验。通过与元数据结合验证 SQL 中的 Schema、Field、 Function 是否存在,输入输出类型是否匹配等。
  •     SQL优化。对上个步骤的输出( RelNode ,逻辑计划树)进行优化,使用两种规则:基于规则优化 和 基于代价优化,得到优化后的物理执行计划。
  •     SQL生成。将物理执行计划生成为在特定平台/引擎的可执行程序,如生成符合 MySQL 或 Oracle 等不同平台规则的 SQL 查询语句等。
  •     执行。执行是通过各个执行平台执行查询,得到输出结果。

其中,Calcite再与其他处理引擎结合时,到SQL优化阶段就已经结束。所以流程图简化为:

2021-10-13_191839.jpg
2. Flink Planner 和 Blink Planner

阿土看完Calcite的原理后,开始想,那Calcite是怎么在Flink中扮演的角色呢?

这时猴哥过来给阿土说,单纯的看一些理论文章,是搞不清楚底层设计实现的,阿土啊,你可以看看源码。

听了猴哥的一番话后,阿土开始啃起了Flink1.13.2的Flink Sql源码

2.1 Flink Planner和Blink Planner


在1.9.0版本以前,社区使用Flink Planner作为查询处理器,通过与Calcite进行连接,为Table/SQL API提供完整的解析、优化和执行环境,使其SQL被转为DataStream API的 Transformation,然后再经过StreamJraph -> JobGraph -> ExecutionGraph等一系列流程,最终被提交到集群。

在1.9.0版本,社区引入阿里巴巴的Blink,对FIink TabIe & SQL模块做了重大的重构,保留了 Flink Planner 的同时,引入了 Blink PIanner,没引入以前,Flink 没考虑流批作业统一,针对流批作业,底层实现两套代码,引入后,基于流批一体理念,重新设计算子,以流为核心,流作业和批作业最终都会被转为transformation。

2.2 Blink Planner与Calcite关系

在之后的版本,为了实现Flink流批一体的愿景,通过Blink Planner与Calcite进行对接,对接流程如下:

  •     在Table/SQL 编写完成后,通过Calcite 中的parse、validate、rel阶段,以及Blink额外添加的convert阶段,将其先转为Operation;
  •     通过Blink Planner 的translateToRel、optimize、translateToExecNodeGraph和translateToPlan四个阶段,将Operation转换成DataStream API的 Transformation;
  •     再经过StreamJraph -> JobGraph -> ExecutionGraph等一系列流程,SQL最终被提交到集群。

小笨猪根据查询后的资料以及查看Flink 1.13.2版本源码后,画出如下SQL执行流程图。

2021-10-13_191907.jpg
3. Blink Sql提交流程(源码分析)

阿土根据对源码的分析后,发现无论是Flink SQL执行DDL操作、还是DQL操作或者DML操作、最终都可以将其总结为两个阶段:

    SQL 语句到 Operation 过程,即Parse阶段;
    Operation 到 Transformations 过程,即Translate阶段。

3.1、Parse阶段

在Parse阶段一共包含parse、validate、rel、convert部分
2021-10-13_191941.jpg

Calcite的 parse 解析模块是基于javacc实现的。javacc是一个词法分析生成器和语法分析生成器。词法分析器于将输入字符流解析成一个一个的token,以下面这段SQL语句为例:

示例1 :
2021-10-13_192013.jpg

在 parse 部分,上面的SQL语句最后会被解析为如下一组token:

2021-10-13_192046.jpg

接下来语法分析器会以词法分析器解析出来的token序列作为输入来进行语法分析。分析过程使用递归下降语法解析,LL(k)。

其中,第一个L表示从左到右扫描输入;第二个L表示每次都进行最左推导(在推导语法树的过程中每次都替换句型中最左的非终结符为终结符。类似还有最右推导);

k表示的是每次向前探索(lookahead)k 个终结符。

分析所依赖的的词法法则定义在一个parser.jj文件中。
2021-10-13_192120.jpg

在经过词法分析和语法分析后,一段 SQL 语句会被解析成一颗抽象语法树(Abstract Syntax Tree,AST),树的节点类型在 Calcite 中以 SqlNode 来表示,不同节点以不同子类型的SqlNode来表示。

同样以上面的SQL为例,在这段SQL中:

  •     id, score, T 等为 SqlIdentifier,表示一个字段名或表名的标识符;
  •     select和cast()为SqlCall,表示一个行为或动作,其中cast()为一个SqlBasicCall,表示一个函数调用,具体调用的是什么函数,由其内部的SqlOperator决定,比如这里是一个二元操作符“<”,对应SqlBinaryOperator,operator的名字是“<”,类别是SqlKind.LESS_THAN;
  •     int 为 SqlDataTypeSpec,表示一个类型定义;
  •     'hello'和 10 为SqlLiteral,表示一个常量;

在Calcite中,所有的操作都是一个SqlCall, 如查询是一个 SqlSelect, 删除是一个 SqlDelete 等,它们都是 SqlCall 的子类型。select的查询条件等为 SqlCall 中的参数。示例1 的 SQL 语句最终生成的语法树形式如下:
2021-10-13_193123.jpg

如果把示例1中的直接从一个表查询数据,改为从两张表的关联结果中查询数据,例如:

示例2:
2021-10-13_193153.jpg

则相应的AST形式如下:
2021-10-13_193220.jpg

其中只有FROM子树部分由原来的SqlIdentifier节点变成了一棵SqlJoin子树,其他部分与示例1相同所以在图中省略了。

2021-10-13_194600.jpg
对经过parser解析出的AST进行有效性验证,验证的方面主要包括以下两方面:

  •     表名、字段名、函数名是否正确,如在某个查询的字段在当前SQL位置上是否存在或有歧义(当前可见的多个数据源中同时存在该名称的字段)
  •     特定类型操作自身的合法性,如group by聚合中的聚合函数是否存在嵌套调用,使用AS重命名时,新名字是否是x.y的形式等



作者:麒思妙想

来源:https://mp.weixin.qq.com/s/ak9s2gUw6On7WwoiduEhYQ


最新经典文章,欢迎关注公众号



没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条