Spark SQL兼容Hive及扩展

来源:互联网 发布:linux系统中文版下载 编辑:程序博客网 时间:2024/04/29 09:44

前言

     相比于Shark对Hive的过渡依赖,Spark SQL在Hive兼容层面仅依赖HQL Parser、Hive Metastore和Hive SerDes。也就是说,从HQL被解析成抽象语法树(AST)起,就全部由Spark SQL接管了,执行计划生成和优化都由Catalyst负责。本文接下来对于Spark SQL在兼容Hive过程中对于Catalog,SqlParser,Analyzer等一系列的具体兼容方式进行具体解析。

一、基础类解析

1.1 Catalog

    Spark中的DataSet和Dataframe API支持结构化分析。结构化分析的一个重要的方面是管理元数据。这些元数据可能是一些临时元数据(比如临时表)、SQLContext上注册的UDF以及持久化的元数据(比如Hivemeta store或者HCatalog)。

 Spark的早期版本是没有标准的API来访问这些元数据的。用户通常使用查询语句(比如show tables)来查询这些元数据。这些查询通常需要操作原始的字符串,而且不同元数据类型的操作也是不一样的。

    这种情况在Spark 2.0中得到改变。Spark 2.0中添加了标准的API(称为catalog)来访问Spark SQL中的元数据。这个API既可以操作Spark SQL,也可以操作Hive元数据。

    Catalog类中提供了多种元数据访问API,Catalog是一个抽象类,它的实现类是CatalogImpl,CatalogImpl提供了面向用户的内部实现。

    SparkSession中现在直接对CatalogImpl进行维护,如下所示。


1.1.1 CatalogImpl

    CatalogImpl是Catalog抽象类的唯一实现,它维护了一个SessionCatalog的引用,且是直接将SessionState中的SessionCatalog拿过来。



1.2 SessionCatalog

    SessionCatalog是一个Spark Session使用的内部catalog,这个内部catalog作为一个外部metastore的代理(eg. Hive MetaStore)提供服务,同时它还可以管理归属于一个SparkSession的临时表和函数。

    注意,SessionCatalog和Catalog的实现类CatalogImpl中的内容是完全一致的,因为CatalogImpl中维护的sessionCatalog成员变量就是一个真正的SesssionCatalog。

    SessionCatalog本身是一个实现类,可以直接用于构造实例使用,同时它还有一个继承类HiveSessionCatalog,专门用于管理Hive数据源的MetaStore

1.2.1 SessionCatalog

    SessionCatalog的构造参数如下:ExternalCatalog,GlobalTempViewManager,FunctionRegistry,SQLConf,Configuration,ParserInterface,FunctionResourceLoader



除此之外,SessionCatalog还维护了以下几个成员变量:tempTables,currentDb,tableRelationCache


 从SessionCatalog的成员变量可以了解,SessionCatalog的外部系统metastore主要是通过ExternalCatalog实现,它对于单SparkSession的临时表管理主要通过它的一些内容可变的成员变量来维护。关于ExternalCatalog后面会有具体描述。

1.2.2 HiveSessionCatalog

    HiveSessionCatalog继承了Spark的默认SessionCatalog,并调整了一些成员的类型,以及新增了一些成员变量。

    HiveSessionCatalog中,它的externalCatlog类型转换为ExternalCatalog的子类HiveExternalCatalog,同时增加了一个成员变量HIveMetastoreCatalog(注意,这个成员之后会完整集成到HiveExternalCatalog中)。


1.2.2.1 HiveMetastoreCatalog

    HiveMetastoreCatalog是HiveSessionCatalog的一个成员变量,是之前的版本中和Hive metastore进行交互遗留下来的产物,之后会逐渐全部融合到HiveExternalCatalog中,目前它还承担了一部分工作,例如创建数据源中的表。这里就不对它做具体描述。

1.3 ExternalCatalog

    ExternalCatalog是系统Catalog的接口,提供访问function、partition和database的一系列方法。只作用为非临时的item,它的实现类必须是线程安全的,因为它会同时被多个线程访问。ExternalCatalog为Spark提供了和外部系统交互的能力。它的实现类在处理database不存在情况时,需要抛出NoSuchDatabaseException异常。和Catalog一样,ExternalCatalog同样提供了许多元数据访问的方法。

    ExternalCatalog有三个实现类,去除测试类后实际上是两个具体实现类:HiveExternalCatalog和InMemoryCatalog。

1.3.1 HiveExternalCatalog

    HiveExternalCatalog继承了ExternalCatalog的所有元数据访问方法,它为Spark提供了与Hive MetaStore的交互能力。具体实现方法是,HiveExternalCatalog会通过hadoop相关的配置文件来实例化一个ClientForMetadata,所有的元数据访问方法都是通过这个client来和hive交互。



1.3.2 InMemoryCatalog

    InMemoryCatalog现在是实验性的功能,是一个不需要外部系统的伪实现类,在这里就不过多描述了。



1.4 SharedState

    SharedState是SparkSession中定义的一个基于给定SQLContext来维护跨Session的所有状态的一个类。它的类成员如下图所示



1.5 SessionState

    SessionState是基于一个特定SparkSession维护所有单个session作用域的所有状态,它的类成员如下图所示。SessionState维护了SparkSQL中大部分的核心类,如SqlParser、Analyzer、Optimizer等等。这些具体类的实现类型根据当前Spark Application的模式会有所不同,具体请看SessionSateBuilder类。



1.6 BaseSessionStateBuilder

    BaseSessionStateBuilder,顾名思义,适用于构造SessionState的类。Spark对它的注释如下:


 BaseSessionStateBuilder定义所有Session所需的状态,并且在session的build方法调用时会真正去创建一个SessionState。开发人员可以用过提供自定义的组件版本或是使用Analyzer、Optimizer和Planner的hook函数来修改builder类。同时在构建新的SessionState时,BaseSessionStateBuilder可以接收一个parent session state来对其的成员进行集成。

    BaseSessionStateBuilder提供的成员变量和方法如下所示,我们可以与SessionState中的成员进行对比,基本上BaseSessionStateBuilder提供的方法都是在SessionState中存在的成员变量。



BaseSessionStateBuilder的非测试实现类有两种,HiveSessionStateBuilder和SessionStateBuilder,对于它们的实例化时的判断请参考2.1 初始化流程。

1.6.1 HiveSessionStateBuilder

    HiveSessionStateBuilder可以构建出一个能识别Hive数据源的SessionState。HiveSessionStateBuilder类对它的父类BaseSessionStateBuilder中的一些方法和成员变量进行了覆盖。



1.6.1.1 新增HiveExternalCatalog

    HiveSessionStateBuilder将SharedState中的externalCatalog提取出来,作为自身的一个类型为HiveExternalCatalog的externalCatalog成员变量存在



1.6.1.2 覆盖resourceLoader成员变量

    resourceLoader是一个用于加载用户定义的函数对应的资源和jar包的成员变量



1.6.1.3 覆盖catalog成员变量

    我们可以对HiveSessionStateBuilder的catalog和BaseSessionStateBuilder的catalog初始化方法进行比较

HiveSessionStateBuilder的catalog初始化:


BaseSessionStateBuilder的catalog初始化:


1.6.1.4 覆盖analyzer方法

    analyzer方法的覆盖,主要是为Analyzer中添加了一些针对Hive的解析规则。Analyzer的主要功能是解析Unresolved LogicalPlan。



1.6.1.5 覆盖planner方法

    planner方法的覆盖,主要是为SparkPlanner中添加一些针对Hive的解析规则,例如HiveTableScans等。SparkPlanner的主要功能是将Logical Plan解析成为Physical Plan。



1.6.1.6 覆盖newBuilder方法

    返回一个新的HiveSessionStateBuilder



1.5.2 SessionStateBuilder

    SessionStateBuilder是BaseSessionStateBuilder的一个具体实现,没有绑定任何特定外部数据源,它所作的唯一覆盖操作就是newBuilder方法,和HiveSessionStateBuilder不同,返回一个SessionStateBuilder。

    可以认为SessionStateBuilder是Spark的一个默认实现,HiveSessionStateBuilder是Spark针对Hive数据源的特定实现。

二、实践

2.1 初始化流程

2.1.1 初始化SparkSession

    在每一个Spark Application中,我们首先要新建一个SparkSession来创建对Spark集群的唯一连接。SparkSession在创建过程中能获取到所有的配置文件,包括是否连接Hive,Hive集群的对应配置。

    注意Spark中的SessionState和ShareState都是lazy变量,只有当第一次使用时才会进行初始化。



2.1.2 初始化SessionState

    SparkSession初始化时一定会调用getOrCreate方法,这个方法调用过程中会将所有的配置文件写入到SessionState的conf中。



调用SparkSession中的sessionState方法,该方法中通过SparkSession.instantiateSessionState来对SessionState进行初始化,注意此时参数为SparkSession.sessionStateClassName(sparkContext.conf)


在调用sessionStateClassName方法中,Spark会根据当前配置是使用Hive还是原生Spark SQL来选择性的初始化SessionBuilder的类名到底是HiveSessionStateBuilder还是SessionStateBuilder


根据配置选择性地获取SessionStateBuilder的类名后,Spark通过反射初始化对应的BaseSEssionStateBuilder,并调用build方法来创建新的SessionState


build方法是HiveSessionStateBuilder和SessionStateBuilder公用的,具体逻辑实现在它们的父类BaseSessionStateBuilder中,差异在build方法中调用的lazy val和function,这一部分方法和成员变量的覆盖在第一章的基础类解析已经做了具体说明。


2.1.3 初始化ShareState

    在2.1.2的最后,初始化SessionState之前,首先要初始化SharedState。下列方法最主要的初始化方法是初始化externalCatalog,其他方法简单介绍。

2.1.3.1 初始化warehousePath

    读取配置信息,若有hive配置信息,则从hive配置中获取warehousePath,若没有,则在当前运行路径下自动生成一个warehousePath。

2.1.3.2 初始化CacheManager

    CacheManager可以记住LogicalPlan的cache状态,它的作用之后详细介绍。

2.1.3.3 初始化SQLListener

    用于SparkUI监控。

2.1.3.4 初始化externalCatalog

    根据配置文件创建一个新的ExternalCatalog,并验证是否有default database,若没有,则创建一个。这个方法的重点创建操作在SharedState.reflect中。




SharedState.reflect方法如下,根据配置文件的名称和实际值去初始化不同的ExternalCatalog,目前只有HiveExternalCatalog




2.1.3.5 初始化globalTempViewManager

    创建全局临时视图管理



2.1.3.6 初始化jarClassLoader

    用于加载用户定义的jar包



2.2 使用

    在2.1中,SparkSession创建完毕后,SparkSession.catalog其实和SparkSession.sessionState.catalog是同样的引用。Spark对于catalog使用的地方很多,这里无法一一枚举,很多地方也没有学习到。这里主要可以看一下catalog在Analyzer中的使用。

    Analyzer在BaseSessionSateBuilder中初始化时,会使用BaseSessionStateBuilder先初始化过的SessionCatalog作为构造参数。




在Analyzer实际的匹配过程中,部分函数使用到了catalog来进行匹配,例如,lookupTableFromCatalog等等


三、总结

    Spark SQL兼容Hive过程中,可以看出Spark SQL的整体架构中,已经预留出了不同数据源的扩展接口,不同数据源在适配过程中需要针对ExternalCatalog、BaseSessionStateBuilder、Analyzer和SparkPlanner做独立的数据源适配即可。