导读:本期是《深入浅出Apache Spark》系列分享的第四期分享,第一期分享了Spark core的概念、原理和架构,第二期分享了Spark SQL的概念和原理,第三期则为Spark SQL解析层的原理和优化案例。本次分享内容主要是Spark SQL分析层的原理和优化的案例,且此优化案例是对于理解分析层原理很重要的。
本期介绍会围绕下面五点展开:
-
前情提要
-
Spark SQL 分析层原理
-
优化案例
-
总结
-
Q&A
►►►
前情提要
首先介绍数新智能与Spark有深度关系的两个产品。
赛博数智引擎,即CyberEngine,它可以帮助用户管理、部署、运维各种组件。该引擎旨在打造一款云原生的数据服务底座,同时支持各种任务的调度,包括存储等各方面的管理和运维工作。
赛博数据平台,包括数据治理、数据开发、数据探索、数据查询等各种能力,其中Spark是它支持的重要数据引擎之一。
上一讲主要介绍了Spark SQL解析层的优化。Spark SQL 解析层实际上是一条SQL执行生命周期中的第一个阶段,首先它需要被解析成一棵抽象语法树。解析后的抽象语法树由于缺少与元数据的绑定,所以我们无法知道UnresolvedAttribute是一个数据库表的列,还是Parquet文件中的一个元数据字段;我们也无法知道或者是一UnresolvedRelation是一张数据库表,还是HDFS上的文件目录。这些分析依赖于Spark SQL的分析层,也就是本次要分享的内容。
►►►
Spark SQL 分析层原理
1. Spark SQL分析层原理
刚才回顾了解析层,或者说是Spark里面的Parser,它能够把输入的SQL 文本转换成一棵解析后的抽象语法树,那么下一步就需要分析层Analyzer,即分析器对抽象语法树进行分析,把抽象语法树跟元数据信息进行绑定,知道数据的位置信息、元数据信息等等,之后才能有机会真正地查询、执行或者修改它。
分析器分析的过程依赖于一些元数据的组件,如SessionCatalog ,在SQL组件中属于元老级的组件。在Spark 2.5版本中引入的Data Source V2中一个很重要的组件叫CatalogManager,其具有用户注册机制,可以让用户注册自己的Catalog。可以理解为用户通过使用Spark内置的SessionCatalog,就可以拥有自己的Catalog。在多个Catalog注册的情况下,可以实现多个数据源之间的联邦,拥有更丰富的业务场景,更加灵活。
有些人觉得Spark内置的SessionCatalog对于Hive的支持会有一些局限,那么就可以用CatalogManager的方式去实现。 不管是老的SessionCatalog,还是新的CatalogManager,实际上最重要的是对Catalog、数据库、表、字段等元数据信息的管理。当然这里提到的表只是从Catalog的角度抽象的一个概念,实际上它未必是一个真的表,例如一个以Kafka作为数据源的Catalog,你可以把Kafka里面的一个Topic抽象成一个表,或者也可以根据这个逻辑把Topic看作是一个数据库。总之,这是一个很灵活、很便利的新扩展,是一个为了帮助分析器获取元数据信息的组件。
在分析层中除了解决元数据信息的绑定之外,还需要去解决一些其他的问题,如内置函数的绑定。比如在SQL里面包含一些函数,这些函数有些是无参数的,有些是带有多个参数的。那么这些函数是不是都是Spark本身就支持的呢?如果输入的是一个ClickHouse的函数呢?因为有些函数肯定是Spark不支持或不认识的,这是Spark在分析过程中首先要去分析的内容,它不能跳过分析直接去执行这个函数。
对函数的分析过程,Spark依赖于FunctionRegistry这个函数注册表组件,函数注册表里面绑定了一些Spark支持的内置函数。如果用户想要实现一些Spark没有但想要扩展的功能的时候,Spark也提供了用户自定义函数的支持,有新旧两套接口去实现UDF。当用户自己去实现UDF的时候,实际上是注册到整个Spark的元数据体系里面,或者说是函数的体系里面,分析器首先会从函数注册表里去查找相关函数,来确保SQL