《深入浅出Apache Spark》系列③:Spark SQL解析层优化策略与案例解析

导读:本系列是Spark系列分享的第三期。第一期分享了Spark Core的一些基本原理和一些基本概念,包括一些核心组件。Spark的所有组件都围绕Spark Core来运转,其中最活跃的一个上层组件是Spark SQL。第二期分享则专门介绍了Spark SQL的基本架构和原理。从第三期开始,后续的分享都围绕着Spark SQL展开,尤其是Spark SQL的优化。Spark作为一个常用的批处理大数据引擎,在各大公司的这个业务线上,存在于离线计算及一些机器查询的场景,而这些场景下最常用的方式就是兼具易用性和学习门槛低等特点的 Spark SQL。今天的分享是关于解析层及其优化,解析层处于Spark SQL处理流程的第一个阶段,和后续将要分享的优化内容相比,较为简单且易于大家理解。

本次分享主要分为五个部分:

  • 产品介绍

  • Spark SQL解析层原理

  • 优化案例

  • 总结

  • Q&A环节

一、产品介绍

首先介绍数新网络与Spark SQL相关的两个主要产品。

第一个是CyberEngine,也叫Cyber数智引擎。Cyber数智引擎旨在构建一个基于云原生的数据湖底座,可以支持用户更好地去分析和挖掘数据,提升自身在市场和商业上的竞争力。Spark自从开源以来很快成为大数据领域的事实标准,CyberEngine支持对Spark SQL的管理。数新网络基于Spark SQL实现了统一的SQL查询平台,即CyberSQL。

另一个Spark相关产品是CyberData。CyberData是一个数据开发平台,基于批流一体、湖仓一体、数智一体,支持公有云、私有云、混合云,并且支持各种大数据文件格式,包括结构化、半结构化和非结构化数据,在此基础上,提供了各种数据治理、数据服务、数据调度和数据开发的能力。

二、Spark解析层原理

1. Spark SQL执行流程

Spark SQL的执行流程经过了解析层、优化层、执行计划层,直到最后成为真正可执行的物理进程(例如JVM进程或Native进程)。执行流程的第一步就是解析层,解析层中的Spark SQL Parser作为最前端的组件,该组件封装了很多子组件,其中很多是基于 ANTLR 实现的。在此基础上,Spark SQL 实现了对 SQL 的解析。

2.ANTLR4编译生成的核心接口和抽象实现

ANTLR4 对SQL语言提供支持,首先需要定义语法模板。ANTLR4语法模板的以.g4作为文件后缀名。例如上图中,简要截取了Spark SQL自定义的SqlBaseLexer.g4和SqlBaseParser.g4这两个.g4文件。在早期,只存在一个.g4文件,即SqlBaseParser.g4文件,该文件包含了词法分析的定义和语法分析的模板。后来Spark社区为了对其在定义上进行解耦,以及便于易于维护,将其分为两个文件。SqlBaseParser.g4文件,需要引用词法分析里定义的一些变量和函数,包括一些token(例如SELECT关键字、ANTLR4的GC文件中定义的函数和变量名)。

首先介绍词法分析,即左边绿色文件的主要内容。该文件包含一个members作用域,定义了很多在Parser代码中复用的变量和函数,此外文件还包含了一些Token定义(例如SELECT、FROM等关键字),在上图中已省略。其次介绍语法分析,即右边蓝色文件主要内容,内容中options引用了左边文件的词法分析的内容,members作用域定义了一些变量和函数,其中还包含了语法定义(如DQL、DEL、DML、Spark SQL自定义语法等等)。

以上是SqlBaseParser.g4文件的摘要。为了便于分享展示,从2000行代码中挑选了最易于理解、最关键的语法定义片段。下图展示的是SQL查询语句的语法定义,其中包括了singleStatement、statement、query、queryOrganization等语法块。ANTLR4对其进行编译之后,会生成一些接口和抽象类实现,开发者针对这些接口和抽象类,可以实现自定义的操作。‍

ANTLR4,SqlBaseParser.g4文件进行编译之后,会根据文件名生成SqlBaseParser抽象类。该抽象类封装了一些组件,其中有一个ParseTreeVisitor,即一个的访问者模式的树结构接口,在该接口上有一个抽象的实现,即AbstractParseTreeVisitor,在这个抽象的实现下,有一个更具体的子类SqlBaseParserBaseVisitor。然后在SqlBaseParserBaseVisitor的基础上,有一个更进一步的实现,即SqlBaseParserVisitor。其中关键点在于,ParseTreeVisitor接口里面中定义了visitChildren等方法,这些方法定义了树的父子层级的访问模式。SqlBaseParserVisitor继承了该接口,并定义了更多的抽象,例如visitSingleStatement,这其实就与SqlBaseParser.g4文件中定义的语法块名相关。这些抽象就需要第三方开发者(如Spark)来具体实现。SQL解析入口是SqlBaseParser,当Spark接收到SQL文本之后,先传递给SqlBaseParser,调用其方法,然后传递给ANTLR4去生成抽象语法树(AST)。以下两张图是对上述整个过程的总结。

3.Spark SQL解析核心实现类 

前文讲到了SqlBaseParserBaseVisitor,Spark在其最新代码中的实现是DataTypeAstBuilder。在此前的代码中,AstBuilder直接实现了SqlBaseParserBaseVisitor,后来为了代码的优雅性,其实现切换为了DataTypeAstBuilder,AstBuilder则是继承了DataTypeAstBuilder。DataTypeAstBuilder中实现了与类型相关的一些方法,例如类型访问、单独数据类型访问等等。

AstBuilder中有一个visitQuery方法,这是与SQL中SELECT查询语法最紧密的接口实现,这个方法会调用其他一些方法,最终返回LogicPlan类型。LogicPlan是Spark内部的逻辑计划表示,其本身是一个树形结构,可以理解为AST的一个具体实现。在visitQuery方法中,有一部分是withQueryResultClauses,这部分就是对查询结果从句的处理。下图展示了其关键代码。可以看到,其中有对ORDER BY、SORT BY、DISTRIBUTE BY、CLUSTER BY、窗口函数、OFFSET、LIMIT等语法的处理。

另外,在visitQuery方法中,还有一部分是withCTE,以下是其关键代码。CTE即公用的表表达式,比如针对一个表做了查询,且这个查询在整个SQL中需重复多次使用。那么在此类场景下,CTE语法就非常有用,可以把一个针对表的查询定义成表达式或变量以复用。

再介绍一下SqlBaseParser入口。SqlBaseParser的父类AbstractParser定义了parse函数,可以针对DDL、DML等类型的语法进行处理。首先进行词法分析(包括Token的划分),然后进行语法解析,返回解析后的结果,具体而言,子类会返回一个LogicPlan。

最后通过一个图来总结ANTLR4和Spark SQL的融合解析流程。左边是两个.g4文件之间的引用关系,经过ANTLR4编译构建之后,生成一些接口和抽象类。右边图例说明其具体实现是交给Spark SQL完成的。

三、优化案例

前文介绍了Spark SQL解析层的原理,接下来将围绕这些原理介绍一个优化案例。

本人在Spark 3.2版本向社区陆续贡献了两个语法PR。最早是在语法定义模板里修改了部分定义实现相应功能,增加了percentile_cont和percentile_disc这两个函数作为聚合函数和窗口函数的一些功能。

观察上图左边的代码可以看到,优化之前这两个函数(可作为聚合函数也可以作为窗口函数)的一些代码逻辑定义,处于表达式的模板定义之下。当时为了实现这两个函数的这些功能,做了如下操作。针对ANTLR编译之后生成的visitPercentile接口,在AstBuilder中进行了实现,包括解析层、分析层、优化层。这里只展示了解析层的内容。Spark选择了Scala语言来实现,对代码优雅性、代码质量要求非常高,这种实现引入了一些额外代码,总共约20-30行,被社区要求改进。观察到Spark的AstBuilder中,有一个较为通用的functionCall函数,以下展示了其具体代码。

把该代码与visitPercentile代码进行对比,可以发现很多重复代码,也是需要去改进的。因此,考虑复用此代码进行功能实现,对visitFunctionCall代码进行修改,针对要修改的两个函数做定制化处理。

优化后,在语法层使得原来增加的6-7行代码变为只需一行代码;而针对visitFunctionCall,只需要变动2行代码。从代码角度来说,相比优化前的近30行代码,总共仅需变动3行代码,这样的优化更为合理且代码也更为优雅。在图片中可以看到整个优化过程,就是通过复用代码,让代码更加的精巧和优雅。从这个优化可以看出,一个软件尤其是大型软件的性能优势其实都是日积月累起来的。

四、总结

本次分享介绍了Spark SQL解析层的原理。主要包括Spark SQL与ANTLR4之间的协作关系、ANTLR4生成的接口和抽象类、Spark SQL的具体实现类、Spark SQL的解析入口和解析流程等,最后通过一个优化案例介绍了Spark解析层的优化。Spark SQL经过ANTLR4的语法校验和类型校验后,通过parse方法解析得到抽象语法树,并将其交给分析层处理,那么关于分析层优化将在下一期分享继续介绍,之后也会有更多性能相关优化,欢迎大家继续关注。

五、Q&A环节

Q1:如何计算一个Spark SQL的资源消耗,从而对比不同SQL的性价比?

A1:现在 SparkSQL基本上大多数组件都是有度量系统的,Spark 内部的Spark Core,Spark SQL 里都有一个度量子架构,其中可以定义很多监控指标,或者称为度量信息。比如一个读数据的scan 相关的算子,在算子里面就会去计算读了多少字节、读了多少行、读了多少时间等。这些 metrics 也可以由用户自定义,通过这些 metrics 信息可以进行性能比较。另一方面,Spark SQL 目前也是支持基于TPC-DS数据集进行性能压测或性能对比。

Q2:怎么去评价SQL优化效果?

A2:评价SQL 的优化效果,主要看优化的目的是什么。如果优化目的是提高稳定性,比如优化之前这个 SQL 经常出现跑不出来、跑失败,优化后能跑出来就达到了预期的优化效果。还有一种是如果优化目的是希望能跑得更快,那么就用时间来评价,所以评价标准主要取决于自己的实际需求。

Q3:Spark向量化技术越来越多,老师怎么看?是不是未来的Spark作业都要使用Native引擎?

A3:Spark 使用Scala,其本质也是用JVM 运行的。对于JVM类语言,其天生最大的一个优势或者说在商业上最成功的一个点,就是语言的平台无关性。熟悉大数据运维的同学肯定有这样的体会,对于一些用 Java 语言开发的大数据组件,包括Spark、Flink、Hadoop、MR 这些组件,它们在任何硬件系统和操作系统上都可以跑。那对公司的商业层面来说,它的运维代价、部署代价、维护代价都很低,而且学习成本也很低,这些其实也是代表着公司的一个核心竞争力。那现在为什么很多公司会追求向量化?一方面是现在数据体量越来越大,也就意味着任务的执行可能耗时会更多,就可能导致对于硬件 CPU 的占用更多。对于大公司来说,尤其是本身就有云提供能力的厂商,他们都有自己的运维团队,花费的成本还是相对可控的。但是对于一些中小公司来说,就会使用付费的云服务,价格会更昂贵,那成本就会更高。在追求降本增效的环境下,对于大数据引擎,包括Spark及其他采用Java开发的大数据组件而言,它们在Native层面上的优化尝试日益增多。其实就是指通过深入挖掘计算机硬件和指令集的性能潜力,来实现成本降低与效率提升的双重目标。我认为还是要围绕公司架构,如果是ToC的业务,那么去做向量化或者native,这种更接近底层硬件的性能优化问题不大;但如果公司是ToB 的,大数据产品或者技术要输出到不同的公司客户,而不同客户又选择了不同的操作系统和不同的 CPU 架构,那这可能就会成为这个公司的噩梦。所以从长远看不管是 Spark 的向量化,还是原生的基于JVM方式的 Spark,两种方式各有优劣,针对不同的目的都会有其存在的价值。

Q4:ANTLR4有没有什么好的学习书籍推荐?

A4:作为一个搞开源的人,我建议可以去看ANTLR4官网,能够理解官网的全部内容,会比任何书都更有价值。

Q5:ANTLR4和Calcite的区别?

A5:我的理解是, Calcite 相比于 ANTLR4,它的功能会更多,它提供了一些优化规则方面的一些处理。ANTLR4其实只是一个解析层的东西,解析出来的东西如果不去进一步处理就没有任何价值,但 Calcite解析完之后,它还附带了一些比较基础的一些优化规则等。从这个角度来说,如果一个公司想要去开发一门语言,基于Calcite也许会比用ANTLR4的开发周期更短。

Q6:Spark的发展方向是什么?流批一体吗?

A6:目前Spark、Flink 都在向着流批一体的方向发展,其实Spark 的优势是在于批处理,而Flink则是在流的部分。因为Flink面对的业务场景较少,则市场占有率就会比较少,所以通过推出流批一体也可以来扩大市场。Spark社区在面对Flink 在批处理上的挑战时,也会去和Flink 在流的市场上做一些争夺,总之二者在这种商业角逐下,很多方面可以相互借鉴。

Q7在数据量大时Spark易出现超出内存被Kill的情况,Shuffle时同样都有溢写到磁盘的功能,为什么 MR 很少出现问题?

A7:因为 MR 不怎么用内存,如果把MR 的JVM内存设置得比较小,也会出现被 Kill 的问题。至于Spark 容易超出内存被Kill,这个问题是因为可能与第三方资源管理(比如Yarn、K8S)有关。

Q8:SQL 解析是否提供了一些对外的接口?例如公司需要分析离线任务的血缘关系,是否有一些接口能深入解析过程拿到表名的?

A8:现在 Spark SQL 的这些解析层的组件,就是作为公共 API 方式存在的。Spark 社区为了便于用户使用,也在积极维护接口的向前兼容性,这其实是考虑到用户只是去做一层解析的使用场景,所以你完全可以这么使用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/468832.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安全的时钟启动

Note:文章内容以 Xilinx 系列 FPGA 进行讲解 1、什么是安全启动时钟 通常情况下,在MMCM/PLL的LOCKED信号抬高之后(由0变为1),MMCM/PLL就处于锁定状态,输出时钟已保持稳定。但在此之前,输出时钟会…

【mongodb】数据库的安装及连接初始化简明手册

NoSQL(NoSQL Not Only SQL ),意即"不仅仅是SQL"。 在现代的计算系统上每天网络上都会产生庞大的数据量。这些数据有很大一部分是由关系数据库管理系统(RDBMS)来处理。 通过应用实践证明,关系模型是非常适合于客户服务器…

丹韵红墙成红毯至美背景!冠珠华脉「雍华京韵」于M essential大秀绽放京韵时尚

东方美学代表品牌M essential近日于上海科学会堂举办十周年大秀,并发布品牌全新2024/25冬春系列。冠珠瓷砖作为国风新韵合作品牌,以高定岩板华脉「雍华京韵」系列的宫墙丹韵打造红毯背景墙,中国高定岩板与中国高级时装作品碰撞着“中国美”的…

工程认证与Spring Boot:计算机课程管理的新探索

摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于工程教育认证的计算机课程管理平台的开发全过程。通过分析基于工程教育认证的计算机课程管理平台管理的不足,创建了一个计算机管理基于工程教育认…

excel功能

统计excel中每个名字出现的次数 在Excel中统计每个名字出现的次数,您可以使用COUNTIF函数或数据透视表。以下是两种方法的详细步骤: 方法一:使用COUNTIF函数 准备数据:确保您的姓名列表位于一个连续的单元格区域,例如…

【flask开启进程,前端内容图片化并转pdf-会议签到补充】

flask开启进程,前端内容图片化并转pdf-会议签到补充 flask及flask-socketio开启threading页面内容转图片转pdf流程前端主js代码内容转图片-browser端browser端的同步编程flask的主要功能route,def 总结 用到了pdf,来回数据转发和合成,担心flask卡顿,响应差,于是刚好看到threadi…

聊一聊Spring中的自定义监听器

前言 通过一个简单的自定义的监听器,从源码的角度分一下Spring中监听的整个过程,分析监听的作用。 一、自定义监听案例 1.1定义事件 package com.lazy.snail;import lombok.Getter; import org.springframework.context.ApplicationEvent;/*** Class…

VMWareTools安装及文件无法拖拽解决方案

文章目录 1 安装VMWare Tools2 安装vmware tools之后还是无法拖拽文件解决方案2.1 确认vmware tools安装2.2 客户机隔离2.3 修改自定义配置文件2.4 安装open-vm-tools-desktop软件 1 安装VMWare Tools 打开虚拟机VMware Workstation,启动Ubuntu系统,菜单…

ADC前端控制与处理模块--AD7606_Module

总体框架 AD7606_Module主要由3个模块组成组成,AD7606_Data_Pkt和AD7606_Drive以及AD7606_ctrl。 1.AD7606_Data_Pkt主要作用是把AD芯片数据组好数据包,然后发送给上位机; 2.AD7606_Drive主要负责和芯片的交互部分 3.AD7606_ctrl控制模块的作…

Unity 插件 - Project窗口资源大小显示

Unity 插件 - Project窗口资源大小显示 🍔功能🌭安装 🍔功能 💡.显示Project Assets 和Packages下所有文件的大小(右侧显示) 💡.统计选中文件夹及其子文件夹下所有文件的大小并显示&#xff08…

HTB:Photobomb[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行端口开放扫描 再次使用nmap对靶机开放端口进行脚本、服务扫描 使用ffuf进行简单的子域名扫描 使用浏览器直接访问该域名 选取一个照片进行下载,使用Yakit进行抓包 USER_FLAG:a9afd9220ae2b5731…

ssm教室信息管理系统+vue

系统包含:源码论文 所用技术:SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习,获取源码看文章最下面 需要定制看文章最下面 目 录 目 录 III 1 绪论 1 1.1 研究背景 1 1.2目的和意义 1 1.3 论文结构安排 2 2 相关技术 3 …

详解Java之Spring MVC篇二

目录 获取Cookie/Session 理解Cookie 理解Session Cookie和Session的区别 获取Cookie 获取Session 获取Header 获取User-Agent 获取Cookie/Session 理解Cookie HTTP协议自身是“无状态”协议,但是在实际开发中,我们很多时候是需要知道请求之间的…

量子计算及其在密码学中的应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 量子计算及其在密码学中的应用 量子计算及其在密码学中的应用 量子计算及其在密码学中的应用 引言 量子计算概述 定义与原理 发展…

当财政支持减弱时,国有企业如何实现降本增效?

当财政支持减弱时,国有企业如何实现降本增效? 随着市场环境的不断变化和上级市场化政策要求的不断推进,部分国有企业面临着双重压力,一方面,市场的快速变革要求企业不断创新、提升竞争力;另一方面&#xff…

引入 axios,根据 api 文档生成调用接口

起步 | Axios Docs 安装 axios npm install axios 生成 api 调用接口【可选】 https://github.com/ferdikoomen/openapi-typescript-codegen 安装 npm install openapi-typescript-codegen --save-dev 然后执行生成代码 # http://localhost:8805/api/user/v3/api-docs&a…

ElasticSearch的Python Client测试

一、Python环境准备 1、下载Python安装包并安装 https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe 2、安装 SDK 参考ES官方文档: https://www.elastic.co/guide/en/elasticsearch/client/index.html python -m pip install elasticsearch一、Client 代…

在双显示器环境中利用Sunshine与Moonlight实现游戏串流的同时与电脑其他任务互不干扰

我和老婆经常会同时需要操作家里的电脑,在周末老婆有时要用电脑加班上网办公,而我想在难得的周末好好地Game一下(在客厅用电视机或者平板串流),但是电脑只有一个,以往我一直都是把电脑让给老婆,…

【第六节】windows汇编开发工具-RadAsm与Masm

一、介绍RadAsm和Masm相关概念 1.1 什么是Win32Asm? Win32Asm是一种基于32位汇编语言的编程语言,专门用于在Windows操作系统下进行开发。Win32Asm的全称是“Windows下的32位汇编语言编程”,它使用微软的MASM(Microsoft Macro Ass…

EHOME视频平台EasyCVR视频融合平台支持哪些摄像机接入?监控摄像头镜头的种类有哪些?

在现代安防监控领域,视频融合平台扮演着至关重要的角色,它们不仅能够整合不同品牌和型号的摄像机,还能提供稳定可靠的视频流传输和高效的视频管理功能。EasyCVR视频融合平台以其卓越的兼容性和灵活性,逐渐成为构建复杂监控网络的首…