spark 2.1.1

一 启动命令

启动spark thrift命令

$SPARK_HOME/sbin/start-thriftserver.sh

然后会执行

org.apache.spark.deploy.SparkSubmit --class org.apache.spark.sql.hive.thriftserver.HiveThriftServer2

二 启动过程及代码分析

hive thrift代码详见:https://www.cnblogs.com/barneywill/p/10185168.html

HiveThriftServer2是spark thrift核心类,继承自Hive的HiveServer2

org.apache.spark.sql.hive.thriftserver.HiveThriftServer2 extends org.apache.hive.service.server.HiveServer2

启动过程:

HiveThriftServer2.main

SparkSQLEnv.init (sparkConf sparkSession sparkContext sqlContext)

HiveThriftServer2.init

addService(ThriftBinaryCLIService)

HiveThriftServer2.start

ThriftBinaryCLIService.run

TServer.serve

类结构:【接口或父类->子类】

TServer->TThreadPoolServer

TProcessorFactory->SQLPlainProcessorFactory

TProcessor->TSetIpAddressProcessor

ThriftCLIService->ThriftBinaryCLIService

CLIService->SparkSQLCLIService (核心子类)

服务初始化过程:

CLIService.init

SparkSQLCLIService.init

addService(SparkSQLSessionManager)

initCompositeService

SparkSQLSessionManager.init

addService(SparkSQLOperationManager)

initCompositeService

SparkSQLOperationManager.init

三 DDL执行过程

ddl执行过程需要和hive metastore交互

从执行计划开始:

spark-sql> explain create table test_table(id string);
== Physical Plan ==
ExecutedCommand
+- CreateTableCommand CatalogTable(
Table: `test_table`
Created: Wed Dec 19 18:04:15 CST 2018
Last Access: Thu Jan 01 07:59:59 CST 1970
Type: MANAGED
Schema: [StructField(id,StringType,true)]
Provider: hive
Storage(InputFormat: org.apache.hadoop.mapred.TextInputFormat, OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat)), false
Time taken: 0.28 seconds, Fetched 1 row(s)

从执行计划里可以找到具体的Command,这里是CreateTableCommand

org.apache.spark.sql.execution.command.tables

case class CreateTableCommand(table: CatalogTable, ifNotExists: Boolean) extends RunnableCommand {

  override def run(sparkSession: SparkSession): Seq[Row] = {
sparkSession.sessionState.catalog.createTable(table, ifNotExists)
Seq.empty[Row]
}
}

这里可以看到是直接将请求分发给sparkSession.sessionState.catalog

org.apache.spark.sql.internal.SessionState

  /**
* Internal catalog for managing table and database states.
*/
lazy val catalog = new SessionCatalog(
sparkSession.sharedState.externalCatalog,
sparkSession.sharedState.globalTempViewManager,
functionResourceLoader,
functionRegistry,
conf,
newHadoopConf())

取的是sparkSession.sharedState.externalCatalog

org.apache.spark.sql.internal.SharedState

  /**
* A catalog that interacts with external systems.
*/
val externalCatalog: ExternalCatalog =
SharedState.reflect[ExternalCatalog, SparkConf, Configuration](
SharedState.externalCatalogClassName(sparkContext.conf),
sparkContext.conf,
sparkContext.hadoopConfiguration)
...
private val HIVE_EXTERNAL_CATALOG_CLASS_NAME = "org.apache.spark.sql.hive.HiveExternalCatalog" private def externalCatalogClassName(conf: SparkConf): String = {
conf.get(CATALOG_IMPLEMENTATION) match {
case "hive" => HIVE_EXTERNAL_CATALOG_CLASS_NAME
case "in-memory" => classOf[InMemoryCatalog].getCanonicalName
}
}

这里可以看到是通过externalCatalogClassName反射实例化的,代码里硬编码使用的是org.apache.spark.sql.hive.HiveExternalCatalog

org.apache.spark.sql.hive.HiveExternalCatalog

  /**
* A Hive client used to interact with the metastore.
*/
val client: HiveClient = {
HiveUtils.newClientForMetadata(conf, hadoopConf)
} private def withClient[T](body: => T): T = synchronized {
try {
body
} catch {
case NonFatal(exception) if isClientException(exception) =>
val e = exception match {
// Since we are using shim, the exceptions thrown by the underlying method of
// Method.invoke() are wrapped by InvocationTargetException
case i: InvocationTargetException => i.getCause
case o => o
}
throw new AnalysisException(
e.getClass.getCanonicalName + ": " + e.getMessage, cause = Some(e))
}
} override def createDatabase(
dbDefinition: CatalogDatabase,
ignoreIfExists: Boolean): Unit = withClient {
client.createDatabase(dbDefinition, ignoreIfExists)
}

这个类里执行任何ddl方法都会执行withClient,而withClient有synchronized,执行过程是直接把请求分发给client,下面看client是什么

org.apache.spark.sql.hive.client.IsolatedClientLoader

  /** The isolated client interface to Hive. */
private[hive] def createClient(): HiveClient = {
if (!isolationOn) {
return new HiveClientImpl(version, sparkConf, hadoopConf, config, baseClassLoader, this)
}
// Pre-reflective instantiation setup.
logDebug("Initializing the logger to avoid disaster...")
val origLoader = Thread.currentThread().getContextClassLoader
Thread.currentThread.setContextClassLoader(classLoader) try {
classLoader
.loadClass(classOf[HiveClientImpl].getName)
.getConstructors.head
.newInstance(version, sparkConf, hadoopConf, config, classLoader, this)
.asInstanceOf[HiveClient]
} catch {

可见client直接用的是org.apache.spark.sql.hive.client.HiveClientImpl

org.apache.spark.sql.hive.client.HiveClientImpl

  def withHiveState[A](f: => A): A = retryLocked {
val original = Thread.currentThread().getContextClassLoader
// Set the thread local metastore client to the client associated with this HiveClientImpl.
Hive.set(client)
// The classloader in clientLoader could be changed after addJar, always use the latest
// classloader
state.getConf.setClassLoader(clientLoader.classLoader)
// setCurrentSessionState will use the classLoader associated
// with the HiveConf in `state` to override the context class loader of the current
// thread.
shim.setCurrentSessionState(state)
val ret = try f finally {
Thread.currentThread().setContextClassLoader(original)
HiveCatalogMetrics.incrementHiveClientCalls(1)
}
ret
}
private def retryLocked[A](f: => A): A = clientLoader.synchronized {
... override def createDatabase(
database: CatalogDatabase,
ignoreIfExists: Boolean): Unit = withHiveState {
client.createDatabase(
new HiveDatabase(
database.name,
database.description,
database.locationUri,
Option(database.properties).map(_.asJava).orNull),
ignoreIfExists)
}

这个类执行任何ddl方法都会执行withHiveState,withHiveState会执行retryLocked,retryLocked上有synchronized;而且这里也是直接将请求分发给client,这里的client是hive的类org.apache.hadoop.hive.ql.metadata.Hive

四 DML执行过程

dml执行过程最后会执行到spark.sql

sql执行过程:

CLIService.executeStatement (返回OperationHandle)

SessionManager.getSession

SessionManager.openSession

SparkSQLSessionManager.openSession

SparkSQLOperationManager.sessionToContexts.set (openSession时:session和sqlContext建立映射)

HiveSession.executeStatement

HiveSessionImpl.executeStatementInternal

OperationManager.newExecuteStatementOperation

SparkSQLOperationManager.newExecuteStatementOperation

SparkSQLOperationManager.sessionToContexts.get (通过session取到sqlContext)

ExecuteStatementOperation.run

SparkExecuteStatementOperation.run

SparkExecuteStatementOperation.execute

SQLContext.sql (熟悉的spark sql)

可见从SparkSQLCLIService初始化开始,逐个将各个类的实现类改为spark的子类比如:

org.apache.spark.sql.hive.thriftserver.SparkSQLSessionManager extends org.apache.hive.service.cli.session.SessionManager
org.apache.spark.sql.hive.thriftserver.server.SparkSQLOperationManager extends org.apache.hive.service.cli.operation.OperationManager
org.apache.spark.sql.hive.thriftserver.SparkExecuteStatementOperation extends org.apache.hive.service.cli.operation.ExecuteStatementOperation

从而实现底层实现的替换;

hive的HiveServer2为什么这么容易的被扩展,详见spark代码的sql/hive-thriftserver,这里应该是将hive1.2代码做了很多修改,以后升级就不那么容易了;
至于spark为什么要花这么大力气扩展HiveServer2而不是重新实现,可能是为了保持接口一致,这样有利于原来使用hive thrift的用户平滑的迁移到spark thrift,因为唯一的改动就是切换url,实际上,相同sql下的spark thrift和hive thrift表现还是有很多不同的。

【原创】大数据基础之Spark(3)Spark Thrift实现原理及代码实现的更多相关文章

  1. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  2. CentOS6安装各种大数据软件 第十章:Spark集群安装和部署

    相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...

  3. 大数据平台搭建(hadoop+spark)

    大数据平台搭建(hadoop+spark) 一.基本信息 1. 服务器基本信息 主机名 ip地址 安装服务 spark-master 172.16.200.81 jdk.hadoop.spark.sc ...

  4. 大数据系列之并行计算引擎Spark部署及应用

    相关博文: 大数据系列之并行计算引擎Spark介绍 之前介绍过关于Spark的程序运行模式有三种: 1.Local模式: 2.standalone(独立模式) 3.Yarn/mesos模式 本文将介绍 ...

  5. 大数据系列之并行计算引擎Spark介绍

    相关博文:大数据系列之并行计算引擎Spark部署及应用 Spark: Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎. Spark是UC Berkeley AMP lab ( ...

  6. 【原创】大数据基础之Zookeeper(2)源代码解析

    核心枚举 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING; } zookeeper服务器状态:刚启动LOOKING,f ...

  7. 【原创】大数据基础之Spark(5)Shuffle实现原理及代码解析

    一 简介 Shuffle,简而言之,就是对数据进行重新分区,其中会涉及大量的网络io和磁盘io,为什么需要shuffle,以词频统计reduceByKey过程为例, serverA:partition ...

  8. 【原创】大数据基础之Spark(4)RDD原理及代码解析

    一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-di ...

  9. 【原创】大数据基础之Spark(1)Spark Submit即Spark任务提交过程

    Spark2.1.1 一 Spark Submit本地解析 1.1 现象 提交命令: spark-submit --master local[10] --driver-memory 30g --cla ...

  10. 【原创】大数据基础之Hive(5)hive on spark

    hive 2.3.4 on spark 2.4.0 Hive on Spark provides Hive with the ability to utilize Apache Spark as it ...

随机推荐

  1. Day4 Numerical simulation of optical wave propagation之数字傅里叶变换

    标量衍射理论是波动光学模拟的物理基础.这一理论基础的结果是将电磁波在真空中的传播作为线性系统进行处理. 对于单色波,系统观察平面的电场矢量是源平面电场矢量和自由空间脉冲响应的卷积. 因此,线性系统理论 ...

  2. Crypto加密解密

    crypto 模块提供了加密功能,包含对 OpenSSL 的哈希.HMAC.加密.解密.签名.以及验证功能的一整套封装.我们这里讲crypto AES算法加密 一.使用步骤 1.引入Crypto 1. ...

  3. Teching Yourself Programming in Ten Years -Peter Norvig

    http://norvig.com/21-days.html 我们经常能看到“7天搞定51单片机”.“21天学会C++”这样样式的标题,编程真的很容易吗?似乎比其他事情要简单很多呀!是的,糟糕的编程确 ...

  4. mysql查看存储过程函数

    查询数据库中的存储过程和函数 select `name` from mysql.proc where db = 'xx' and `type` = 'PROCEDURE'   //存储过程       ...

  5. vue 自定义指令的使用案例

    参考资料: 1. vue 自定义指令: 2. vue 自定义指令实现 v-loading: v-loading,是 element-ui 组件库中的一个用于数据加载过程中的过渡动画指令,项目中也很少需 ...

  6. sgu438-The_Glorious_Karlutka_River

    Description SGU似乎死了... 题目搬到了Codeforces... Problem - 99999438 - Codeforces Solution 动态最大流. 考虑如果不求时间, ...

  7. 【深入Java虚拟机】之三:内存溢出

    为了更直接的了解各区域,下面我们来看几个示例. 1.Java 堆溢出 下面的程中我们限制Java 堆的大小为20MB,不可扩展(将堆的最小值-Xms 参 数与最大值-Xmx 参数设置为一样即可避免堆自 ...

  8. Spring MVC 使用介绍(十)—— 编码

    一.概述 客户端与服务器端在交互过程中,需要将字符以某种编码方式转化为字节流进行传输,因此涉及字符的编码和解码.某一方以编码方案A编码,另一方须以同样的编码方案解码,否则会出现乱码. 客户端与服务器端 ...

  9. 一分钟学会JavaMail(假)__手动滑稽

    因为公司内部办公系统(OA)需要增加一个发送邮件的功能,所以学习了这个感觉比较冷门的JavaMail   1.先上成功截图 : 2.准备事项:Java Mail虽然是官方写的,但是没有集成到jdk里面 ...

  10. 配置启动MySQL的Docker容器

    docker run -d -p : --name mysql -e MYSQL_ROOT_PASSWORD= mysql: